rllib  1
rlsocket.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           rlsocket.cpp  -  description
00003                              -------------------
00004     begin                : Tue Jan 02 2001
00005     copyright            : (C) 2001 by Rainer Lehrig
00006     email                : lehrig@t-online.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as        *
00013  *   published by the Free Software Foundation                             *
00014  *                                                                         *
00015  ***************************************************************************/
00016 #include "rldefine.h"
00017 
00018 #ifndef IS_OLD_MSVCPP
00019 #ifndef __VMS
00020 #define AF_INET6_IS_AVAILABLE
00021 #endif
00022 #endif
00023 
00024 #ifdef RLWIN32
00025 #include <windows.h>
00026 #ifdef IS_OLD_MSVCPP
00027 #include <winsock.h>
00028 #else
00029 //#if (_WIN32_WINNT < 0x0501)
00030 //#warning mingw does not have helpers modify mingw header in ws2tcpip.h
00031 #include <winsock2.h>
00032 #include <ws2tcpip.h>
00033 void WSAAPI freeaddrinfo(struct addrinfo*);
00034 int  WSAAPI getaddrinfo(const char*,const char*,const struct addrinfo*, struct addrinfo**);
00035 int  WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, char*,DWORD,int);
00036 //#undef AF_INET6_IS_AVAILABLE
00037 //#endif
00038 #endif
00039 #include <io.h>
00040 #include <direct.h>
00041 #define  MSG_NOSIGNAL 0
00042 #else
00043 #include <sys/time.h>
00044 #include <sys/socket.h>
00045 #include <netinet/in.h>
00046 #include <arpa/inet.h>
00047 #include <netdb.h>
00048 #include "unistd.h"
00049 #endif
00050 
00051 #ifdef __VMS
00052 #define  MSG_NOSIGNAL 0
00053 #endif
00054 
00055 #ifdef PVMAC
00056 #define MSG_NOSIGNAL 0
00057 #endif
00058 
00059 #include <stdio.h>
00060 #include <stdarg.h>
00061 #include <string.h>
00062 #include "rlsocket.h"
00063 #include "rlwthread.h"
00064 #include "rlcutil.h"
00065 
00066 /* windows stuff */
00067 int rlwsa()
00068 {
00069 #ifdef RLWIN32
00070   static int first = 1;
00071   WORD    wVersionRequested;
00072   WSADATA wsadata;
00073   int     err;
00074 
00075   if(first == 1)
00076   {
00077 #ifdef IS_OLD_MSVCPP
00078     wVersionRequested = MAKEWORD(1,1);
00079 #else
00080     wVersionRequested = MAKEWORD(2,0);
00081 #endif
00082     err = WSAStartup(wVersionRequested, &wsadata);
00083     if(err != 0)
00084     {
00085       ::printf("Startup error=%d on windows\n",err);
00086       exit(0);
00087     }
00088     first = 0;
00089   }
00090 #endif
00091   return 0;
00092 }
00093 
00094 rlSocket::rlSocket(const char *a, int p, int act)
00095 {
00096   rlwsa(); // init sockets on windows
00097   setAdr(a);
00098   port = p;
00099   active = act;
00100   s = -1;
00101   os = -1;
00102   first = 1;
00103   rl_ipversion = 4;
00104   memset(sockaddr,0,sizeof(sockaddr));
00105 }
00106 
00107 rlSocket::rlSocket(int socket)
00108 {
00109   adr[0] = '\0';
00110   port   = -1;
00111   active = 0;
00112   s      = socket;
00113   os     = -1;
00114   first  = 0;
00115   rl_ipversion = 4;
00116   memset(sockaddr,0,sizeof(sockaddr));
00117 }
00118 
00119 rlSocket::~rlSocket()
00120 {
00121   disconnect();
00122   if(os != -1 && active == 0)
00123   {
00124 #ifdef RLWIN32
00125     closesocket(os);
00126 #else
00127     close(os);
00128 #endif
00129   }
00130 }
00131 
00132 void rlSocket::setAdr(const char *a)
00133 {
00134   adr[0] = '\0';
00135   if(a == NULL) return;
00136   if((strlen(a)+1) > sizeof(adr)) return;
00137   strcpy(adr,a);
00138 }
00139 
00140 void rlSocket::setPort(int p)
00141 {
00142   port = p;
00143 }
00144 
00145 int rlSocket::getPort()
00146 {
00147   return port;
00148 }
00149 
00150 void rlSocket::setActive(int act)
00151 {
00152   active = act;
00153 }
00154 
00155 int rlSocket::read(void *buf, int len, int timeout)
00156 {
00157   int  i,ret;
00158   char *cbuf;
00159 
00160   if(s == -1) return -1;
00161   if(select(timeout) == 0) return 0; // timeout
00162 
00163   cbuf = (char *) buf;
00164   i = 0;
00165   while(i < len)
00166   {
00167     ret = recv(s,&cbuf[i],len-i,0);
00168     if(ret <= 0)
00169     {
00170       disconnect();
00171       return -1;
00172     }
00173     i += ret;
00174     if(i < len)
00175     {
00176       if(select(timeout) == 0) return 0; // timeout
00177     }
00178   }
00179 
00180   return i;
00181 }
00182 
00183 int rlSocket::readStr(char *buf, int len, int timeout)
00184 {
00185   int ret,i;
00186 
00187   if(s == -1) return -1;
00188   if(select(timeout) == 0) return 0; // timeout
00189 
00190   i = 0;
00191   while(1)
00192   {
00193 #ifdef RLWIN32
00194 tryagain:
00195 #endif
00196     ret = recv(s,&buf[i],1,0);
00197     if(ret <= 0)
00198     {
00199 #ifdef RLWIN32
00200       if(WSAEWOULDBLOCK == WSAGetLastError()) goto tryagain;
00201 #endif
00202       disconnect();
00203       buf[i] = '\0';
00204       return -1;
00205     }
00206     if(buf[i] == '\n')
00207     {
00208       buf[i+1] = '\0';
00209       return i+1;
00210     }
00211     if(i >= len-1)
00212     {
00213       buf[i+1] = '\0';
00214       return i+1;
00215     }
00216     i++;
00217   }
00218 }
00219 
00220 int rlSocket::write(const void *buf, int len)
00221 {
00222   int ret,bytes_left,first_byte;
00223   const char *cbuf;
00224 
00225   if(s == -1) return -1;
00226   cbuf = (char *) buf;
00227   bytes_left = len;
00228   first_byte = 0;
00229 
00230   while(bytes_left > 0)
00231   {
00232     ret = send(s,&cbuf[first_byte],bytes_left,MSG_NOSIGNAL);
00233     if(ret <= 0)
00234     {
00235       disconnect();
00236       return -1;
00237     }
00238     bytes_left -= ret;
00239     first_byte += ret;
00240   }
00241 
00242   return first_byte;
00243 }
00244 
00245 int rlSocket::connect()
00246 {
00247   int option;
00248   int ret;
00249 #ifdef __VMS
00250   size_t    socklen = sizeof(struct sockaddr);
00251 #else
00252   socklen_t socklen = sizeof(struct sockaddr);
00253 #endif
00254   struct sockaddr_in     localAddr;
00255   struct sockaddr_in     remoteAddr;
00256   struct hostent        *host;
00257   struct in_addr         RemoteIpAddress;
00258 #ifdef AF_INET6_IS_AVAILABLE
00259   struct addrinfo        hints0, hints1;
00260   struct addrinfo       *res, *ressave;
00261   int n;
00262   char portstr[32];
00263 #endif
00264 
00265   if(port <= 0)       return PORT_ERR;
00266   if(port >= 256*256) return PORT_ERR;
00267   if(active == 0)
00268   { // accept calls
00269     s = -1;
00270     if(rl_ipversion == 4)
00271     {
00272       if(first == 1)
00273       {
00274         // create a socket
00275         os = socket(AF_INET,SOCK_STREAM,0);
00276         if(os == -1) return SOCKET_ERR;
00277         // set socket options 
00278 #ifdef __VMS
00279         option = 1;
00280         if(setsockopt(os,SOL_SOCKET,SO_KEEPALIVE,&option,sizeof(option)) < 0)
00281         {
00282           return SETSOCKOPT_ERR;
00283         }
00284 #endif
00285         option = 1;
00286 #ifdef RLWIN32
00287         setsockopt(os,SOL_SOCKET,SO_REUSEADDR,(const char *) &option,sizeof(option));
00288 #else
00289         setsockopt(os,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
00290 #endif
00291         // Bind our server to the agreed upon port number.
00292         memset(&localAddr,0,sizeof(localAddr));
00293         localAddr.sin_port = htons((short) port);
00294         localAddr.sin_family = AF_INET;
00295 bind:
00296         ret = bind(os, (struct sockaddr *) &localAddr, sizeof(localAddr));
00297         if(ret == -1)
00298         {
00299           rlwthread_sleep(1000);
00300           goto bind;
00301         }
00302         // Prepare to accept client connections.  Allow up to 5 pending 
00303         // connections.                                            
00304         ret = listen(os, 5);
00305         if(ret == -1) return LISTEN_ERR;
00306       }
00307       first = 0;
00308 
00309       // accept connections
00310       s = accept(os, (struct sockaddr *) &sockaddr[0], &socklen);
00311       if(s == -1) return ACCEPT_ERR;
00312     }
00313     else if(rl_ipversion == 6)
00314     {
00315 #ifdef AF_INET6_IS_AVAILABLE
00316       if(first == 1)
00317       {
00318         memset(&hints0,0,sizeof(hints0));
00319         hints0.ai_flags = AI_PASSIVE;
00320         //hints0.ai_family = AF_UNSPEC;
00321         hints0.ai_family = AF_INET6;
00322         hints0.ai_socktype = SOCK_STREAM;
00323         sprintf(portstr,"%d",port);
00324         //::printf("server getaddrinfo(%s,%s)\n", adr, portstr);
00325         n = getaddrinfo(adr, portstr, &hints0, &res);
00326         if(n != 0)
00327         {
00328 #ifndef RLWIN32
00329           ::printf("rlSocket:tcp_listen error for %s port=%s : %s\n", adr, portstr, gai_strerror(n));
00330 #endif
00331           return -1;
00332         }
00333         //::printf("done\n");
00334         ressave = res;
00335 bindv6:
00336         do
00337         {
00338           os = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00339           if(os < 0)                                            continue; // error, try next one
00340 #ifdef __VMS
00341           option = 1;
00342           if(setsockopt(os,SOL_SOCKET,SO_KEEPALIVE,&option,sizeof(option)) < 0)
00343           {
00344             return SETSOCKOPT_ERR;
00345           }
00346 #endif
00347           option = 1;
00348 #ifdef RLWIN32
00349           setsockopt(os,SOL_SOCKET,SO_REUSEADDR,(const char *) &option,sizeof(option));
00350 #else
00351           setsockopt(os,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
00352 #endif
00353           if(bind(os, res->ai_addr, res->ai_addrlen) == 0)      break;    // success
00354           s = os;
00355           disconnect();                                                   // bind error, close and try next one
00356         }
00357         while((res = res->ai_next) != NULL);
00358         if(res == NULL)                                                   // errno from final socket() or bind()
00359         {
00360           ::printf("warning: could not bind to port=%d\n", port);
00361           rlwthread_sleep(1000);
00362           goto bindv6;
00363         }
00364         // Prepare to accept client connections.  Allow up to 5 pending 
00365         // connections
00366         ret = listen(os, 5);
00367         freeaddrinfo(ressave);
00368         if(ret == -1) return LISTEN_ERR;
00369       }
00370       first = 0;
00371       // accept connections
00372       s = accept(os, (struct sockaddr *) &sockaddr[0], &socklen);
00373       if(s == -1) return ACCEPT_ERR;
00374 #else
00375       ::printf("rlSocket:ERROR IPV6 not available on this platform\n");
00376 #endif
00377     }
00378     else
00379     {
00380       ::printf("rlSocket:ERROR: rl_ipversion=%d not known\n", rl_ipversion);
00381     }
00382   } // end active == 0 
00383   else if(active == 1)
00384   {
00385     disconnect();
00386     //::printf("debug: adr=%s port=%d\n",adr,port);
00387     s = -1;
00388     if(rl_ipversion == 4)
00389     {
00390       os = socket(AF_INET,SOCK_STREAM,0);
00391       if(os == -1) return SOCKET_ERR;
00392       s = os;
00393 
00394       //::printf("debug: gethostbyname\n");
00395       // fill destblk structure 
00396       host = gethostbyname(adr);
00397       if(host == NULL)
00398       {
00399         // See if the host is specified in "dot address" form
00400         RemoteIpAddress.s_addr = inet_addr(adr);
00401         if(RemoteIpAddress.s_addr == INADDR_NONE)
00402         {
00403           s = -1;
00404           return INET_ADDR_ERR; // -1
00405         }
00406       }
00407       else
00408       {
00409         memcpy(&RemoteIpAddress,host->h_addr,host->h_length);
00410       }
00411 
00412       memset(&remoteAddr,0,sizeof(remoteAddr));
00413       remoteAddr.sin_family = AF_INET;
00414       remoteAddr.sin_port = htons((short) port);
00415       remoteAddr.sin_addr = RemoteIpAddress;
00416 
00417       //::printf("debug: connect\n");
00418       ret = ::connect(s, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr));
00419       //::printf("debug: connect ret=%d\n",ret);
00420       if(ret == -1) 
00421       {
00422         s = -1;
00423         return CONNECT_ERR;
00424       }
00425     }
00426     else if(rl_ipversion == 6)
00427     {
00428 #ifdef AF_INET6_IS_AVAILABLE
00429       sprintf(portstr,"%d",port);
00430       memset(&hints1, 0, sizeof(hints1));
00431       hints1.ai_family = AF_UNSPEC;
00432       hints1.ai_socktype = SOCK_STREAM;
00433       n = getaddrinfo(adr, portstr, &hints1, &res);
00434       if(n != 0)
00435       {
00436 #ifndef RLWIN32
00437         ::printf("rlSocket:tcp_connect error for %s port=%s : %s\n", adr, portstr, gai_strerror(n));
00438 #endif
00439         return -1;
00440       }
00441       ressave = res;
00442       do
00443       {
00444         s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00445         if(s < 0)                                            continue; // ignore this one
00446         if(::connect(s, res->ai_addr, res->ai_addrlen) == 0) break;    // success
00447         disconnect();                                                  // ignore this one
00448       }
00449       while((res = res->ai_next) != NULL);
00450       if(res == NULL) ::printf("rlSocket:tcp_connect error for %s port=%s\n", adr, portstr);
00451       freeaddrinfo(ressave);
00452 #else
00453       ::printf("rlSocket:ERROR IPV6 not available on this platform\n");
00454 #endif
00455     }
00456     else
00457     {
00458       ::printf("rlSocket:ERROR: rl_ipversion=%d not known\n", rl_ipversion);
00459     }
00460   }
00461   return s;
00462 }
00463 
00464 int rlSocket::disconnect()
00465 {
00466   if(s != -1)
00467   {
00468 #ifdef RLWIN32
00469     closesocket(s);
00470 #else
00471     close(s);
00472 #endif
00473   }
00474   s = -1;
00475   return 0;
00476 }
00477 
00478 int rlSocket::isConnected()
00479 {
00480   if(s == -1) return 0;
00481   return 1;
00482 }
00483 
00484 int rlSocket::select(int timeout)
00485 {
00486   struct timeval timout;
00487   fd_set wset,rset,eset;
00488   int    ret,maxfdp1;
00489 
00490   if(timeout == 0) return 1;
00491   /* setup sockets to read */
00492   maxfdp1 = s+1;
00493   FD_ZERO(&rset);
00494   FD_SET (s,&rset);
00495   FD_ZERO(&wset);
00496   FD_ZERO(&eset);
00497   timout.tv_sec  =  timeout / 1000;
00498   timout.tv_usec = (timeout % 1000) * 1000;
00499 
00500   ret = ::select(maxfdp1,&rset,&wset,&eset,&timout);
00501   if(ret == 0) return 0; /* timeout */
00502   return 1;
00503 }
00504 
00505 int rlSocket::printf(const char *format, ...)
00506 {
00507   int ret;
00508   char message[rl_PRINTF_LENGTH]; // should be big enough
00509 
00510   va_list ap;
00511   va_start(ap,format);
00512   ret = rlvsnprintf(message, rl_PRINTF_LENGTH - 1, format, ap);
00513   va_end(ap);
00514   if(ret < 0) return ret;
00515   return write(message,strlen(message));
00516 }
00517 
00518 int rlSocket::sendProcessViewBrowserButtonEvent(int id)
00519 {
00520   return printf("QPushButton(%d)\n",id);
00521 }
00522 
00523 int rlSocket::setIPVersion(int version)
00524 {
00525   if(version == 6) rl_ipversion = 6;
00526   else             rl_ipversion = 4;
00527   return rl_ipversion;
00528 }
00529 
00530 int rlSocket::getIPVersion()
00531 {
00532   return rl_ipversion;
00533 }
00534 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines