rllib  1
rlsocket.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  rlsocket.cpp - description
3  -------------------
4  begin : Tue Jan 02 2001
5  copyright : (C) 2001 by R. Lehrig
6  email : lehrig@t-online.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This library is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as *
13  * published by the Free Software Foundation *
14  * *
15  ***************************************************************************/
16 #include "rldefine.h"
17 
18 #ifndef IS_OLD_MSVCPP
19 #ifndef __VMS
20 #define AF_INET6_IS_AVAILABLE
21 #endif
22 #endif
23 
24 #ifdef RLWIN32
25 //#if (_WIN32_WINNT < 0x0501)
26 //#warning mingw does not have helpers modify mingw header in ws2tcpip.h
27 #include <winsock2.h>
28 #include <ws2tcpip.h>
29 
30 #define WTREAD_GNUC5 ( __GNUC__ * 1000 ) + __GNUC_MINOR__
31 #if WTREAD_GNUC5 < 4008
32 void WSAAPI freeaddrinfo(struct addrinfo*);
33 int WSAAPI getaddrinfo(const char*,const char*,const struct addrinfo*, struct addrinfo**);
34 int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, char*,DWORD,int);
35 #endif
36 
37 //#undef AF_INET6_IS_AVAILABLE
38 //#endif
39 #include <windows.h>
40 #include <io.h>
41 #include <direct.h>
42 #define MSG_NOSIGNAL 0
43 #else
44 #include <sys/time.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <netdb.h>
49 #include "unistd.h"
50 #endif
51 
52 #ifdef __VMS
53 #define MSG_NOSIGNAL 0
54 #endif
55 
56 #ifdef PVMAC
57 #define MSG_NOSIGNAL 0
58 #endif
59 
60 #include <stdio.h>
61 #include <stdarg.h>
62 #include <string.h>
63 #include "rlsocket.h"
64 #include "rlwthread.h"
65 #include "rlcutil.h"
66 
67 /* windows stuff */
68 int rlwsa()
69 {
70 #ifdef RLWIN32
71  static int first = 1;
72  WORD wVersionRequested;
73  WSADATA wsadata;
74  int err;
75 
76  if(first == 1)
77  {
78 #ifdef IS_OLD_MSVCPP
79  wVersionRequested = MAKEWORD(1,1);
80 #else
81  wVersionRequested = MAKEWORD(2,0);
82 #endif
83  err = WSAStartup(wVersionRequested, &wsadata);
84  if(err != 0)
85  {
86  ::printf("Startup error=%d on windows\n",err);
87  exit(0);
88  }
89  first = 0;
90  }
91 #endif
92  return 0;
93 }
94 
95 int rlScoketWrite(int *socket, const void *buf, int len)
96 {
97  int ret,bytes_left,first_byte;
98  const char *cbuf;
99 
100  if(socket == NULL) return -1;
101  if(*socket == -1) return -1;
102  cbuf = (char *) buf;
103  bytes_left = len;
104  first_byte = 0;
105 
106  while(bytes_left > 0)
107  {
108  ret = send(*socket,&cbuf[first_byte],bytes_left,MSG_NOSIGNAL);
109  if(ret <= 0)
110  {
111  //disconnect();
112  if(*socket != -1)
113  {
114 #ifdef RLWIN32
115  closesocket(*socket);
116 #else
117  close(*socket);
118 #endif
119  }
120  *socket = -1;
121  return -1;
122  }
123  bytes_left -= ret;
124  first_byte += ret;
125  }
126 
127  return first_byte;
128 }
129 
130 rlSocket::rlSocket(const char *a, int p, int act)
131 {
132  rlwsa(); // init sockets on windows
133  setAdr(a);
134  port = p;
135  active = act;
136  s = -1;
137  os = -1;
138  first = 1;
139  rl_ipversion = 4;
140  memset(sockaddr,0,sizeof(sockaddr));
141 }
142 
144 {
145  adr[0] = '\0';
146  port = -1;
147  active = 0;
148  s = socket;
149  os = -1;
150  first = 0;
151  rl_ipversion = 4;
152  memset(sockaddr,0,sizeof(sockaddr));
153 }
154 
156 {
157  disconnect();
158  if(os != -1 && active == 0)
159  {
160 #ifdef RLWIN32
161  closesocket(os);
162 #else
163  close(os);
164 #endif
165  }
166 }
167 
168 void rlSocket::setAdr(const char *a)
169 {
170  adr[0] = '\0';
171  if(a == NULL) return;
172  if((strlen(a)+1) > sizeof(adr)) return;
173  strcpy(adr,a);
174 }
175 
176 void rlSocket::setPort(int p)
177 {
178  port = p;
179 }
180 
182 {
183  return port;
184 }
185 
186 void rlSocket::setActive(int act)
187 {
188  active = act;
189 }
190 
191 int rlSocket::read(void *buf, int len, int timeout)
192 {
193  int i,ret;
194  char *cbuf;
195 
196  if(s == -1) return -1;
197  if(select(timeout) == 0) return 0; // timeout
198 
199  cbuf = (char *) buf;
200  i = 0;
201  while(i < len)
202  {
203  ret = recv(s,&cbuf[i],len-i,0);
204  if(ret <= 0)
205  {
206  disconnect();
207  return -1;
208  }
209  i += ret;
210  if(i < len)
211  {
212  if(select(timeout) == 0) return 0; // timeout
213  }
214  }
215 
216  return i;
217 }
218 
219 int rlSocket::readStr(char *buf, int len, int timeout)
220 {
221  int ret,i;
222 
223  if(s == -1) return -1;
224  if(select(timeout) == 0) return 0; // timeout
225 
226  i = 0;
227  while(1)
228  {
229 #ifdef RLWIN32
230 tryagain:
231 #endif
232  ret = recv(s,&buf[i],1,0);
233  if(ret <= 0)
234  {
235 #ifdef RLWIN32
236  if(WSAEWOULDBLOCK == WSAGetLastError()) goto tryagain;
237 #endif
238  disconnect();
239  buf[i] = '\0';
240  return -1;
241  }
242  if(buf[i] == '\n')
243  {
244  buf[i+1] = '\0';
245  return i+1;
246  }
247  if(i >= len-1)
248  {
249  buf[i+1] = '\0';
250  return i+1;
251  }
252  i++;
253  }
254 }
255 
256 int rlSocket::readHttpHeader(rlString *header, int timeout)
257 {
258  char line[4096];
259  int contentLength = 0;
260 
261  *header = "";
262  while(1)
263  {
264  int ret = readStr(line, (int) sizeof(line)-1, timeout);
265  if(ret < 0)
266  {
267  printf("ERROR in rlSocket::readHttpHeader() ret=%d\n", ret);
268  return -1;
269  }
270  *header += line;
271  if(strstr(line, "Content-Length:") != NULL)
272  {
273  sscanf(line,"Content-Length: %d", &contentLength);
274  }
275  if(strlen(line) <= 2)
276  {
277  return contentLength;
278  }
279  }
280 }
281 
282 int rlSocket::write(const void *buf, int len)
283 {
284  int ret,bytes_left,first_byte;
285  const char *cbuf;
286 
287  if(s == -1) return -1;
288  cbuf = (char *) buf;
289  bytes_left = len;
290  first_byte = 0;
291 
292  while(bytes_left > 0)
293  {
294  ret = send(s,&cbuf[first_byte],bytes_left,MSG_NOSIGNAL);
295  if(ret <= 0)
296  {
297  disconnect();
298  return -1;
299  }
300  bytes_left -= ret;
301  first_byte += ret;
302  }
303 
304  return first_byte;
305 }
306 
308 {
309  int option;
310  int ret;
311 #ifdef __VMS
312  size_t socklen = sizeof(struct sockaddr);
313 #else
314  socklen_t socklen = sizeof(struct sockaddr);
315 #endif
316  struct sockaddr_in localAddr;
317  struct sockaddr_in remoteAddr;
318  struct hostent *host;
319  struct in_addr RemoteIpAddress;
320 #ifdef AF_INET6_IS_AVAILABLE
321  struct addrinfo hints0, hints1;
322  struct addrinfo *res, *ressave;
323  int n;
324  char portstr[32];
325 #endif
326 
327  if(port <= 0) return PORT_ERR;
328  if(port >= 256*256) return PORT_ERR;
329  if(active == 0)
330  { // accept calls
331  s = -1;
332  if(rl_ipversion == 4)
333  {
334  if(first == 1)
335  {
336  // create a socket
337  os = socket(AF_INET,SOCK_STREAM,0);
338  if(os == -1) return SOCKET_ERR;
339  // set socket options
340 #ifdef __VMS
341  option = 1;
342  if(setsockopt(os,SOL_SOCKET,SO_KEEPALIVE,&option,sizeof(option)) < 0)
343  {
344  return SETSOCKOPT_ERR;
345  }
346 #endif
347  option = 1;
348 #ifdef RLWIN32
349  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,(const char *) &option,sizeof(option));
350 #else
351  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
352 #endif
353  // Bind our server to the agreed upon port number.
354  memset(&localAddr,0,sizeof(localAddr));
355  localAddr.sin_port = htons((short) port);
356  localAddr.sin_family = AF_INET;
357 bind:
358  ret = bind(os, (struct sockaddr *) &localAddr, sizeof(localAddr));
359  if(ret == -1)
360  {
361  ::printf("warning: could not bind to port=%d\n", port);
362  rlwthread_sleep(1000);
363  goto bind;
364  }
365  // Prepare to accept client connections. Allow up to 5 pending
366  // connections.
367  ret = listen(os, 5);
368  if(ret == -1) return LISTEN_ERR;
369  }
370  first = 0;
371 
372  // accept connections
373  if(os < 0) return ACCEPT_ERR;
374  s = accept(os, (struct sockaddr *) &sockaddr[0], &socklen);
375  if(s == -1) return ACCEPT_ERR;
376  }
377  else if(rl_ipversion == 6)
378  {
379 #ifdef AF_INET6_IS_AVAILABLE
380  if(first == 1)
381  {
382  memset(&hints0,0,sizeof(hints0));
383  hints0.ai_flags = AI_PASSIVE;
384  //hints0.ai_family = AF_UNSPEC;
385  hints0.ai_family = AF_INET6;
386  hints0.ai_socktype = SOCK_STREAM;
387  sprintf(portstr,"%d",port);
388  //::printf("server getaddrinfo(%s,%s)\n", adr, portstr);
389  n = getaddrinfo(adr, portstr, &hints0, &res);
390  if(n != 0)
391  {
392 #ifndef RLWIN32
393  ::printf("rlSocket:tcp_listen error for %s port=%s : %s\n", adr, portstr, gai_strerror(n));
394 #endif
395  return -1;
396  }
397  //::printf("done\n");
398  ressave = res;
399 bindv6:
400  do
401  {
402  os = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
403  if(os < 0) continue; // error, try next one
404 #ifdef __VMS
405  option = 1;
406  if(setsockopt(os,SOL_SOCKET,SO_KEEPALIVE,&option,sizeof(option)) < 0)
407  {
408  return SETSOCKOPT_ERR;
409  }
410 #endif
411  option = 1;
412 #ifdef RLWIN32
413  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,(const char *) &option,sizeof(option));
414 #else
415  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
416 #endif
417  if(bind(os, res->ai_addr, res->ai_addrlen) == 0) break; // success
418  s = os;
419  disconnect(); // bind error, close and try next one
420  }
421  while((res = res->ai_next) != NULL);
422  if(res == NULL) // errno from final socket() or bind()
423  {
424  ::printf("warning: could not bind to port=%d\n", port);
425  rlwthread_sleep(1000);
426  goto bindv6;
427  }
428  // Prepare to accept client connections. Allow up to 5 pending
429  // connections
430  ret = listen(os, 5);
431  freeaddrinfo(ressave);
432  if(ret == -1) return LISTEN_ERR;
433  }
434  first = 0;
435  // accept connections
436  if(os < 0) return ACCEPT_ERR;
437  s = accept(os, (struct sockaddr *) &sockaddr[0], &socklen);
438  if(s == -1) return ACCEPT_ERR;
439 #else
440  ::printf("rlSocket:ERROR IPV6 not available on this platform\n");
441 #endif
442  }
443  else
444  {
445  ::printf("rlSocket:ERROR: rl_ipversion=%d not known\n", rl_ipversion);
446  }
447  } // end active == 0
448  else if(active == 1)
449  {
450  disconnect();
451  //::printf("debug: adr=%s port=%d\n",adr,port);
452  s = -1;
453  if(rl_ipversion == 4)
454  {
455  os = socket(AF_INET,SOCK_STREAM,0);
456  if(os == -1) return SOCKET_ERR;
457  s = os;
458 
459  //::printf("debug: gethostbyname\n");
460  // fill destblk structure
461  host = gethostbyname(adr);
462  if(host == NULL)
463  {
464  // See if the host is specified in "dot address" form
465  RemoteIpAddress.s_addr = inet_addr(adr);
466  if(RemoteIpAddress.s_addr == INADDR_NONE)
467  {
468  s = -1;
469  return INET_ADDR_ERR; // -1
470  }
471  }
472  else
473  {
474  memcpy(&RemoteIpAddress,host->h_addr,host->h_length);
475  }
476 
477  memset(&remoteAddr,0,sizeof(remoteAddr));
478  remoteAddr.sin_family = AF_INET;
479  remoteAddr.sin_port = htons((short) port);
480  remoteAddr.sin_addr = RemoteIpAddress;
481 
482  //::printf("debug: connect\n");
483  ret = ::connect(s, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr));
484  //::printf("debug: connect ret=%d\n",ret);
485  if(ret == -1)
486  {
487  disconnect(); // close s = os
488  return CONNECT_ERR;
489  }
490  }
491  else if(rl_ipversion == 6)
492  {
493 #ifdef AF_INET6_IS_AVAILABLE
494  sprintf(portstr,"%d",port);
495  memset(&hints1, 0, sizeof(hints1));
496  hints1.ai_family = AF_UNSPEC;
497  hints1.ai_socktype = SOCK_STREAM;
498  n = getaddrinfo(adr, portstr, &hints1, &res);
499  if(n != 0)
500  {
501 #ifndef RLWIN32
502  ::printf("rlSocket:tcp_connect error for %s port=%s : %s\n", adr, portstr, gai_strerror(n));
503 #endif
504  return -1;
505  }
506  ressave = res;
507  do
508  {
509  s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
510  if(s < 0) continue; // ignore this one
511  if(::connect(s, res->ai_addr, res->ai_addrlen) == 0) break; // success
512  disconnect(); // ignore this one
513  }
514  while((res = res->ai_next) != NULL);
515  if(res == NULL) ::printf("rlSocket:tcp_connect error for %s port=%s\n", adr, portstr);
516  freeaddrinfo(ressave);
517 #else
518  ::printf("rlSocket:ERROR IPV6 not available on this platform\n");
519 #endif
520  }
521  else
522  {
523  ::printf("rlSocket:ERROR: rl_ipversion=%d not known\n", rl_ipversion);
524  }
525  }
526  return s;
527 }
528 
530 {
531  if(s != -1)
532  {
533 #ifdef RLWIN32
534  closesocket(s);
535 #else
536  close(s);
537 #endif
538  }
539  s = -1;
540  return 0;
541 }
542 
544 {
545  if(s == -1) return 0;
546  return 1;
547 }
548 
549 int rlSocket::select(int timeout)
550 {
551  struct timeval timout;
552  fd_set wset,rset,eset;
553  int ret,maxfdp1;
554 
555  if(timeout == 0) return 1;
556  /* setup sockets to read */
557  maxfdp1 = s+1;
558  FD_ZERO(&rset);
559  FD_SET (s,&rset);
560  FD_ZERO(&wset);
561  FD_ZERO(&eset);
562  timout.tv_sec = timeout / 1000;
563  timout.tv_usec = (timeout % 1000) * 1000;
564 
565  ret = ::select(maxfdp1,&rset,&wset,&eset,&timout);
566  if(ret == 0) return 0; /* timeout */
567  return 1;
568 }
569 
570 int rlSocket::printf(const char *format, ...)
571 {
572  int ret;
573  char message[rl_PRINTF_LENGTH]; // should be big enough
574 
575  va_list ap;
576  va_start(ap,format);
577  ret = rlvsnprintf(message, rl_PRINTF_LENGTH - 1, format, ap);
578  va_end(ap);
579  if(ret < 0) return ret;
580  return write(message,strlen(message));
581 }
582 
584 {
585  return printf("QPushButton(%d)\n",id);
586 }
587 
588 int rlSocket::setIPVersion(int version)
589 {
590  if(version == 6) rl_ipversion = 6;
591  else rl_ipversion = 4;
592  return rl_ipversion;
593 }
594 
596 {
597  return rl_ipversion;
598 }
599 
600 int rlSocket::rlGetsockopt(int sockfd, int level, int optname, void *optval, int *optlen)
601 {
602 #ifdef RLWIN32
603  return getsockopt(sockfd, level, optname, (char *) optval, optlen);
604 #elif defined(__VMS)
605  size_t len = *optlen;
606  int ret = getsockopt(sockfd, level, optname, optval, &len);
607  *optlen = len;
608  return ret;
609 #else
610  socklen_t len = *optlen;
611  int ret = getsockopt(sockfd, level, optname, optval, &len);
612  *optlen = len;
613  return ret;
614 #endif
615 }
616 
617 int rlSocket::rlSetsockopt(int sockfd, int level, int optname, const void *optval, int optlen)
618 {
619 #ifdef RLWIN32
620  return setsockopt(sockfd, level, optname, (const char *) optval, optlen);
621 #else
622  return setsockopt(sockfd, level, optname, optval, optlen);
623 #endif
624 }
625 
626 int rlSocket::rlGetsockopt(int level, int optname)
627 {
628  int option = 1;
629  int len = sizeof(option);
630  return rlGetsockopt(s,level,optname,&option,&len);
631 }
632 
633 int rlSocket::rlSetsockopt(int level, int optname)
634 {
635  int option = 1;
636  return rlSetsockopt(s,level,optname,&option,sizeof(option));
637 }
638 
640 {
641  char line[256];
642  while(1)
643  {
644  if(readStr(line, (int)sizeof(line) - 1, timeout) < 1) return -1;
645  if(strncmp(line,"Content-Length:",15) == 0) break;
646  }
647  int len = 0;
648  sscanf(line,"Content-Length: %d", &len);
649  if(readStr(line, (int)sizeof(line) - 1, timeout) < 1) return -1; // read CR LF
650  return len;
651 }
int setIPVersion(int version)
Definition: rlsocket.cpp:588
int write(const void *buf, int len)
Definition: rlsocket.cpp:282
void setActive(int active)
Definition: rlsocket.cpp:186
int readHttpHeader(rlString *header, int timeout=0)
Definition: rlsocket.cpp:256
virtual ~rlSocket()
Definition: rlsocket.cpp:155
int port
Definition: rlsocket.h:262
int first
Definition: rlsocket.h:265
int WSAAPI getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **)
int rlScoketWrite(int *socket, const void *buf, int len)
Definition: rlsocket.cpp:95
#define rl_PRINTF_LENGTH
Definition: rldefine.h:71
void setPort(int port)
Definition: rlsocket.cpp:176
int readStr(char *buf, int len, int timeout=0)
Definition: rlsocket.cpp:219
unsigned char sockaddr[16+48]
Definition: rlsocket.h:258
#define MSG_NOSIGNAL
Definition: rlsocket.cpp:53
rlSocket(const char *adr, int port, int active)
Definition: rlsocket.cpp:130
int sendProcessViewBrowserButtonEvent(int id)
Definition: rlsocket.cpp:583
char adr[132]
Definition: rlsocket.h:261
int read(void *buf, int len, int timeout=0)
Definition: rlsocket.cpp:191
int rlvsnprintf(char *text, int len, const char *format, va_list ap)
Definition: rlcutil.cpp:197
static int rlSetsockopt(int sockfd, int level, int optname, const void *optval, int optlen)
Definition: rlsocket.cpp:617
int select(int timeout=0)
Definition: rlsocket.cpp:549
int os
Definition: rlsocket.h:264
int getPort()
Definition: rlsocket.cpp:181
void WSAAPI freeaddrinfo(struct addrinfo *)
int connect()
Definition: rlsocket.cpp:307
int s
Definition: rlsocket.h:197
int disconnect()
Definition: rlsocket.cpp:529
int isConnected()
Definition: rlsocket.cpp:543
int WSAAPI getnameinfo(const struct sockaddr *, socklen_t, char *, DWORD, char *, DWORD, int)
static int rlGetsockopt(int sockfd, int level, int optname, void *optval, int *optlen)
Definition: rlsocket.cpp:600
int active
Definition: rlsocket.h:263
int readHttpContentLength(int timeout)
Definition: rlsocket.cpp:639
void setAdr(const char *adr)
Definition: rlsocket.cpp:168
int rlwsa()
Definition: rlsocket.cpp:68
int rlwthread_sleep(long msec)
Definition: rlwthread.cpp:366
int getIPVersion()
Definition: rlsocket.cpp:595
int printf(const char *format,...)
Definition: rlsocket.cpp:570
int rl_ipversion
Definition: rlsocket.h:267