/***************************************************************************
* CdSocket.cpp *
* ------------------- *
* copyright : (C) 2009 by Jesus Garrido and Richard Carrillo *
* email : jgarrido@atc.ugr.es *
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "../../include/communication/CdSocket.h"
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
unsigned int CdSocket::SocketInstances = 0;
#else
// Linux socket includes
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h> // to set special server flags
#include <unistd.h> // misc symbolic constants and types
#include <netdb.h>
#include <netinet/tcp.h>
#endif
#define SERVER_PATH "server"
CdSocket::CdSocket(unsigned short status, string server_address,unsigned short tcp_port){
this->status = status;
this->serv_host_addr = server_address;
this->serv_tcp_port = tcp_port;
initializeSocket();
}
CdSocket::~CdSocket(){
#ifdef _WIN32
closesocket(socket_fd);
SocketInstances--;
if (SocketInstances==0){
WSACleanup();
}
#else
close(socket_fd);
#endif
}
void CdSocket::initializeSocket()
{
#ifdef _WIN32
if (SocketInstances==0){
WSADATA wsaData;
WORD version;
int error;
version = MAKEWORD(2,2);
error = WSAStartup(version, &wsaData);
/* check for error */
if ( error != 0 )
{
cerr << "Problem when creating the windows socket v2.2" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
/* check for correct version */
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ){
/* incorrect WinSock version */
WSACleanup();
cerr << "Invalid version of windows socket - Not v2.2 available" << endl;
exit(EXIT_FAILURE);
}
/* WinSock has been initialized */
SocketInstances ++;
}
#endif
/***************/
/*** CLIENT ***/
/***************/
if(this->status==CLIENT){
socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
#ifdef _WIN32
if(socket_fd == INVALID_SOCKET){
cerr << "Problem when creating the windows socket: creation ... closing the simulation (CD_SOCKET)" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
#else
if(socket_fd == -1){
cerr << "Problem when creating the socket: creation ... closing the simulation (CD_SOCKET)" << endl;
exit(EXIT_FAILURE);
}
#endif
struct sockaddr_in sin;
memset( &sin, 0, sizeof sin );
struct sockaddr_in serv_addr;
memset((char *)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(this->serv_host_addr.c_str());
serv_addr.sin_port = htons(this->serv_tcp_port);
int socket_connect = connect(socket_fd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(socket_connect != 0){
cerr << "Problem when connecting socket: connection ... closing the simulation ( (CD_SOCKET))" << endl;
exit(EXIT_FAILURE);
}
struct protoent *p;
int one=1;
p = getprotobyname("tcp");
setsockopt(socket_fd, p->p_proto, TCP_NODELAY, (const char*)&one, sizeof(one));
}
/***************/
/*** SERVER ***/
/***************/
if(this->status==SERVER){
int clilen, ret;
struct sockaddr_in cli_addr, serv_addr;
memset((char *)&serv_addr, 0, sizeof(serv_addr));
#ifdef _WIN32
SOCKET tmp_socket_fd = INVALID_SOCKET;
#else
int tmp_socket_fd;
#endif
tmp_socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
#ifdef _WIN32
if(tmp_socket_fd == INVALID_SOCKET){
cerr << "Problem when creating the windows socket: creation ... closing the simulation (CD_SOCKET)" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
#else
if(tmp_socket_fd == -1){
cerr << "Problem when creating the socket: creation ... closing the simulation (CD_SOCKET)" << endl;
exit(EXIT_FAILURE);
}
#endif
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(this->serv_tcp_port);
ret = bind(tmp_socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(ret!=0){
cerr << "Problem when binding socket ... closing the simulation (CD_SOCKET)" << endl;
exit(EXIT_FAILURE);
}
ret = listen(tmp_socket_fd, 1);
if(ret!=0){
cerr << "Problem when listening socket ... closing the simulation (CD_SOCKET)" << endl;
exit(EXIT_FAILURE);
}
clilen = sizeof(cli_addr);
#ifdef _WIN32
socket_fd = accept(tmp_socket_fd, (struct sockaddr *) &cli_addr, &clilen);
closesocket(tmp_socket_fd);
#else
socket_fd = accept(tmp_socket_fd, (struct sockaddr *) &cli_addr, (socklen_t *)&clilen);
close(tmp_socket_fd); // close original socket
#endif
#ifdef _WIN32
if(socket_fd == INVALID_SOCKET){
cerr << "Problem when creating the windows socket: Couldn't accept the external connection (CD_SOCKET)" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
#else
if(socket_fd == -1){
cerr << "Problem when creating the socket: creation ... closing the simulation (CD_SOCKET)" << endl;
exit(EXIT_FAILURE);
}
#endif
struct protoent *p;
int one=1;
p = getprotobyname("tcp");
setsockopt(socket_fd, p->p_proto, TCP_NODELAY, (const char*)&one, sizeof(one));
//linger ls = {1, 6000} ;
//setsockopt(socket_fd, p->p_proto, SO_LINGER, (const char *)&ls, sizeof(ls)) ;
}
}
int CdSocket::receiveBuffer(void* buffer, int buffer_size){
ret_status=0;
for(int nbytes=0;nbytes<buffer_size;){
/*** to be sure that everything is received ***/
ret_status=recv(socket_fd,((char*)buffer)+nbytes,buffer_size-nbytes,0);
if(ret_status > 0)
nbytes+=ret_status;
else
break;
}
return(ret_status);
}
int CdSocket::sendBuffer(void* buffer, int buffer_size){
return int(send(socket_fd,(char *)buffer,buffer_size,0));
}