/********************************************************************
*       (c) Copyright 2003, Hogeschool voor de Kunsten Utrecht
*                       Hilversum, the Netherlands
*********************************************************************
*
* File name     : socket.cpp
* System name   : signature
* 
* Version       : $Revision: 1.3 $
*
*
* Description   : Implementation of Socket class
*
*
* Author        : Marc_G
* E-mail        : marcg@dinkum.nl
*
*
********************************************************************/

/************
   $Log: socket.cpp,v $
   Revision 1.3  2003/08/28 13:22:26  marcg
   adaptations for gcc-3

   Revision 1.2  2003/02/07 16:55:58  marcg
   added wouldblock()

   Revision 1.1.1.1  2003/01/30 21:46:09  marcg
   Imported using TkCVS

*************/

using namespace std;

#include <string>
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>

#include "socket.h"


Socket::Socket() : m_sock(-1)
{
  memset(&m_addr,0,sizeof(m_addr));
}


Socket::~Socket()
{
  if(is_valid()) ::close(m_sock);
}


int Socket::create()
{
  m_sock = socket(AF_INET,SOCK_STREAM,0);
  if(!is_valid()) return -1;

  int on=1;
  if(setsockopt(m_sock,SOL_SOCKET,SO_REUSEADDR,
                (const char*)&on,sizeof(on))== -1) return -1;
  return true;
}



int Socket::bind(const int port)
{
  if(!is_valid()) return -1;

  m_addr.sin_family = AF_INET;
  m_addr.sin_addr.s_addr = INADDR_ANY;
  m_addr.sin_port = htons(port);

  int bind_status = ::bind(m_sock,
			     (struct sockaddr *)&m_addr,
			     sizeof(m_addr));
  return bind_status ;
}


int Socket::listen() const
{
  if(!is_valid()) return -1;
  int listenstatus = ::listen(m_sock,MAXCONNECTIONS);
  return listenstatus;
}



int Socket::accept(Socket& new_socket) const
{
int addr_length = sizeof ( m_addr );

  new_socket.m_sock = ::accept(m_sock,(sockaddr *)&m_addr,
                              (socklen_t *)&addr_length);

  if(new_socket.m_sock <= 0) return -1;
  return 0;
}


int Socket::connect(const string host,const int port)
{
  if(!is_valid()) return -1;

  m_addr.sin_family = AF_INET;
  m_addr.sin_port = htons(port);

  int status=inet_pton(AF_INET,host.c_str(),&m_addr.sin_addr);

  if(errno==EAFNOSUPPORT) return -1;

  status= ::connect(m_sock,(sockaddr *)&m_addr,sizeof(m_addr));

  return status;
}


bool Socket::wouldblock(void)
{
fd_set readfds;
struct timeval timeout;
int result;

  timeout.tv_sec=0;
  timeout.tv_usec=0;
  FD_ZERO(&readfds);
  FD_SET(m_sock,&readfds);
  result = select(m_sock+1,&readfds,NULL,NULL,&timeout);
  if(result <= 0 ) return true;
  return false;
}



int Socket::read(char *buf,int size)
{
int bytes_read;

  bytes_read= ::read(m_sock,buf,size);
  //if(bytes_read<=0)close(m_sock); // not for non-blocking socket !
  return bytes_read;
}


int Socket::write(char *buf,int size)
{
 return ::write(m_sock,buf,size);
}


int Socket::write(string outputstring)
{
 return ::write(m_sock,outputstring.c_str(),outputstring.length());
}


void Socket::set_non_blocking(const bool b)
{
int opts;

  opts = fcntl(m_sock,F_GETFL);

  if(opts < 0) return;

  if(b) opts=(opts | O_NONBLOCK);
  else opts=(opts & ~O_NONBLOCK);

  fcntl(m_sock,F_SETFL,opts);
}

