#ifndef GENERIC_SOCKET_H #define GENERIC_SOCKET_H #include "ansi.h" /** * * @libdoc genericSocket provides some functions to open/close sockets both TCP and UDP * * @short some functions to open/close sockets both TCP and UDP * @author Anna Bergamaschi * @version 0.0 */ //version 1.0, base development, Ian 19/01/09 /* Modified by anna on 19.01.2009 */ /* canceled SetupParameters() and varaibles intialized in the constructors' headers; defined SEND_REC_MAX_SIZE (for compatibilty with mythen (and possibly other) pure C servers (i would move it to the common header file) added #ifndef C_ONLY... to cutout class definition when including in pure C servers (can be removed if SEND_REC_MAX_SIZE is moved to the common header file) defined private variables char hostname[1000] and int portno to store connection informations; defined public functions int getHostname(char *name) and int getPortNumber() to retrieve connection informations added public function int getErrorStatus() returning 1 if socketDescriptor<0 remove exits in the constructors and replace them with socketDescriptor=-1 replaced the argument of send/receive data with void (to avoid too much casting or compiler errors/warnings) added a function which really does not close the socket between send/receive (senddataonly, receivedataonly) */ #ifdef __CINT__ //class sockaddr_in; class socklen_t; class uint32_t; class uint32_t_ss; // CINT view of types: class sockaddr_in; // { // unsigned short int sa_family; // unsigned char sa_data[14]; // }; #else #include #include #include #include #include #include #endif #include /******exit */ #include #include #include #include #include #include using namespace std; #define DEFAULT_PACKET_SIZE 1286 /*#define SOCKET_BUFFER_SIZE (100*1024*1024) //100MB*/ #define SOCKET_BUFFER_SIZE (2000*1024*1024) //100MB #define DEFAULT_PORTNO 1952 #define DEFAULT_BACKLOG 5 #define DEFAULT_UDP_PORTNO 50001 #define DEFAULT_GUI_PORTNO 65000 #define DEFAULT_ZMQ_PORTNO 70001 class genericSocket{ public: /** Communication protocol */ enum communicationProtocol{ TCP, /**< TCP/IP */ UDP /**< UDP */ }; genericSocket(const char* const host_ip_or_name, unsigned short int const port_number, communicationProtocol p, int ps = DEFAULT_PACKET_SIZE) : // portno(port_number), protocol(p), is_a_server(0), socketDescriptor(-1), file_des(-1), packet_size(ps), nsending(0), nsent(0), total_sent(0),// sender (client): where to? ip header_packet_size(0) { //memset(&serverAddress, 0, sizeof(sockaddr_in)); //memset(&clientAddress, 0, sizeof(sockaddr_in)); // serverAddress = {0}; // clientAddress = {0}; // strcpy(hostname,host_ip_or_name); strcpy(lastClientIP,"none"); strcpy(thisClientIP,"none1"); strcpy(dummyClientIP,"dummy"); differentClients = 0; struct hostent *hostInfo = gethostbyname(host_ip_or_name); if (hostInfo == NULL){ cerr << "Exiting: Problem interpreting host: " << host_ip_or_name << "\n"; } else { // Set some fields in the serverAddress structure. serverAddress.sin_family = hostInfo->h_addrtype; memcpy((char *) &serverAddress.sin_addr.s_addr, hostInfo->h_addr_list[0], hostInfo->h_length); serverAddress.sin_port = htons(port_number); socketDescriptor=0; //You can use send and recv, //would it work????? } clientAddress_length=sizeof(clientAddress); } int getProtocol(communicationProtocol p) { switch (p) { case TCP: return SOCK_STREAM; break; case UDP: return SOCK_DGRAM; default: cerr << "unknow protocol " << p << endl; return -1; } } int getProtocol() {return getProtocol(protocol);}; /** The constructor for a server @short the contructor for a server \param port_number port number to listen to \param p TCP or UDP \param eth interface name or IP address to listen to (if NULL, listen to all interfaces) */ genericSocket(unsigned short int const port_number, communicationProtocol p, int ps = DEFAULT_PACKET_SIZE, const char *eth=NULL, int hsize=0): //portno(port_number), protocol(p), is_a_server(1), socketDescriptor(-1), file_des(-1), packet_size(ps), nsending(0), nsent(0), total_sent(0), header_packet_size(hsize) { /* // you can specify an IP address: */ /* // or you can let it automatically select one: */ /* myaddr.sin_addr.s_addr = INADDR_ANY; */ strcpy(lastClientIP,"none"); strcpy(thisClientIP,"none1"); strcpy(dummyClientIP,"dummy"); differentClients = 0; if(serverAddress.sin_port == htons(port_number)){ socketDescriptor = -10; return; } char ip[20]; strcpy(ip,"0.0.0.0"); clientAddress_length=sizeof(clientAddress); if (eth) { strcpy(ip,nameToIp(string(eth)).c_str()); if (string(ip)==string("0.0.0.0")) strcpy(ip,eth); } // strcpy(hostname,"localhost"); //needed?!?!?!? socketDescriptor = socket(AF_INET, getProtocol(),0); //tcp if (socketDescriptor < 0) { cerr << "Can not create socket "<= 0){ \ close(socketDescriptor); \ } \ if(is_a_server and getProtocol() == TCP){\ if(file_des>0)\ close(file_des);\ } file_des=-1; \ serverAddress.sin_port=-1; \ }; /* /\** @short if client returns hostname for connection */ /* \param name string to write the hostname to */ /* \returns 0 if client, 1 if server (in this case ignore name return value) */ /* *\/ */ /* int getHostname(char *name){ */ /* if (is_a_server==0) { */ /* strcpy(name,getHostname().c_str()); */ /* } */ /* return is_a_server; */ /* }; */ /* /\** @short if client returns hostname for connection */ /* \returns hostname */ /* *\/ */ /* string getHostname(){return string(hostname);}; */ /* /\** @short returns port number for connection */ /* \returns port number */ /* *\/ */ /* int getPortNumber(){return portno;}; */ /** @short returns communication protocol \returns TCP or UDP */ int getCommunicationProtocol(){return protocol;}; /** @short returns error status \returns 1 if error */ int getErrorStatus(){if (socketDescriptor==-10) return -10; else if (socketDescriptor<0) return 1; else return 0;}; /** @short etablishes connection; disconnect should always follow \returns 1 if error */ int Connect(){//cout<<"connect"<0) return file_des; if (protocol==UDP) return -1; if(is_a_server && protocol==TCP){ //server tcp; the server will wait for the clients connection if (socketDescriptor>0) { if ((file_des = accept(socketDescriptor,(struct sockaddr *) &clientAddress, &clientAddress_length)) < 0) { cerr << "Error: with server accept, connection refused"<=0){ close(socketDescriptor); socketDescriptor = -1; } } } /** @short free connection */ void Disconnect(){ if (protocol==UDP){ close(socketDescriptor); socketDescriptor=-1; } else{ if(file_des>=0){ //then was open if(is_a_server){ close(file_des); } else { //while(!shutdown(socketDescriptor, SHUT_RDWR)); close(socketDescriptor); socketDescriptor=-1; } file_des=-1; } } }; void ShutDownSocket(){ while(!shutdown(socketDescriptor, SHUT_RDWR)); Disconnect(); }; /** Set the socket timeout ts is in seconds */ int SetTimeOut(int ts){ if (ts<=0) return -1; //cout << "socketdescriptor "<< socketDescriptor << endl; struct timeval tout; tout.tv_sec = 0; tout.tv_usec = 0; if(::setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof(struct timeval)) <0) { cerr << "Error in setsockopt SO_RCVTIMEO "<< 0 << endl; } tout.tv_sec = ts; tout.tv_usec = 0; if(::setsockopt(socketDescriptor, SOL_SOCKET, SO_SNDTIMEO, &tout, sizeof(struct timeval)) < 0) { cerr << "Error in setsockopt SO_SNDTIMEO " << ts << endl; } return 0; }; int setPacketSize(int i=-1) { if (i>=0) packet_size=i;return packet_size;}; static string ipToName(string ip) { struct ifaddrs *addrs, *iap; struct sockaddr_in *sa; char buf[32]; strcpy(buf,"none"); getifaddrs(&addrs); for (iap = addrs; iap != NULL; iap = iap->ifa_next) { if (iap->ifa_addr && (iap->ifa_flags & IFF_UP) && iap->ifa_addr->sa_family == AF_INET) { sa = (struct sockaddr_in *)(iap->ifa_addr); inet_ntop(iap->ifa_addr->sa_family, (void *)&(sa->sin_addr), buf, sizeof(buf)); if (ip==string(buf)) { //printf("%s\n", iap->ifa_name); strcpy(buf,iap->ifa_name); break; } } } freeifaddrs(addrs); return string(buf); }; static string nameToMac(string inf) { struct ifreq ifr; int sock, j, k; char mac[32]; sock=getSock(inf,&ifr); if (-1==ioctl(sock, SIOCGIFHWADDR, &ifr)) { perror("ioctl(SIOCGIFHWADDR) "); return string("00:00:00:00:00:00"); } for (j=0, k=0; j<6; j++) { k+=snprintf(mac+k, sizeof(mac)-k-1, j ? ":%02X" : "%02X", (int)(unsigned int)(unsigned char)ifr.ifr_hwaddr.sa_data[j]); } mac[sizeof(mac)-1]='\0'; if(sock!=1){ close(sock); } return string(mac); }; static string nameToIp(string inf){ struct ifreq ifr; int sock; char *p, addr[32]; sock=getSock(inf,&ifr); if (-1==ioctl(sock, SIOCGIFADDR, &ifr)) { perror("ioctl(SIOCGIFADDR) "); return string("0.0.0.0"); } p=inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr); strncpy(addr,p,sizeof(addr)-1); addr[sizeof(addr)-1]='\0'; if(sock!=1){ close(sock); } return string(addr); }; static int getSock(string inf, struct ifreq *ifr) { int sock; sock=socket(PF_INET, SOCK_STREAM, 0); if (-1==sock) { perror("socket() "); return 1; } strncpy(ifr->ifr_name,inf.c_str(),sizeof(ifr->ifr_name)-1); ifr->ifr_name[sizeof(ifr->ifr_name)-1]='\0'; return sock; }; int ReceiveDataOnly(void* buf,int length=0){ if (buf==NULL) return -1; total_sent=0; switch(protocol) { case TCP: if (file_des<0) return -1; while(length>0){ nsending = (length>packet_size) ? packet_size:length; nsent = read(file_des,(char*)buf+total_sent,nsending); if(!nsent) break; length-=nsent; total_sent+=nsent; } if (total_sent>0) strcpy(thisClientIP,dummyClientIP); if (strcmp(lastClientIP,thisClientIP)) differentClients=1; else differentClients=0; break; case UDP: if (socketDescriptor<0) return -1; //if length given, listens to length, else listens for packetsize till length is reached if(length){ /*int k = 0;*/ while(length>0){ nsending = (length>packet_size) ? packet_size:length; nsent = recvfrom(socketDescriptor,(char*)buf+total_sent,nsending, 0, (struct sockaddr *) &clientAddress, &clientAddress_length); if(nsent != nsending){ //if((nsent != nsending)){ && (nsent < packet_size)){ if(nsent && (nsent != header_packet_size) && (nsent != -1)) cprintf(RED,"Incomplete Packet size %d\n",nsent); break; } length-=nsent; total_sent+=nsent; } } //listens to only 1 packet else{ //normal nsending=packet_size; nsent = recvfrom(socketDescriptor,(char*)buf+total_sent,nsending, 0, (struct sockaddr *) &clientAddress, &clientAddress_length); //nsent = 1040; total_sent+=nsent; } break; default: ; } #ifdef VERY_VERBOSE cout << "sent "<< total_sent << " Bytes" << endl; #endif return total_sent; } int SendDataOnly(void *buf, int length) { #ifdef VERY_VERBOSE cout << "want to send "<< length << " Bytes" << endl; #endif if (buf==NULL) return -1; total_sent=0; switch(protocol) { case TCP: if (file_des<0) return -1; while(length>0){ nsending = (length>packet_size) ? packet_size:length; nsent = write(file_des,(char*)buf+total_sent,nsending); if(!nsent) break; length-=nsent; total_sent+=nsent; } break; case UDP: if (socketDescriptor<0) return -1; while(length>0){ nsending = (length>packet_size) ? packet_size:length; nsent = sendto(socketDescriptor,(char*)buf+total_sent,nsending, 0, (struct sockaddr *) &clientAddress, clientAddress_length); if(!nsent) break; length-=nsent; total_sent+=nsent; } break; default: ; } #ifdef VERY_VERBOSE cout << "sent "<< total_sent << " Bytes" << endl; #endif return total_sent; } int getCurrentTotalReceived(){ return total_sent; } char lastClientIP[INET_ADDRSTRLEN]; char thisClientIP[INET_ADDRSTRLEN]; int differentClients; protected: communicationProtocol protocol; int is_a_server; int socketDescriptor; int file_des; int packet_size; struct sockaddr_in clientAddress, serverAddress; socklen_t clientAddress_length; char dummyClientIP[INET_ADDRSTRLEN]; private: int nsending; int nsent; int total_sent; int header_packet_size; // pthread_mutex_t mp; }; #endif