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 
210  //::printf("debug: read len=%d buf=", len);
211  //for(int j=0; j<len; j++) ::printf(" %d", cbuf[j]);
212  //::printf("\n");
213 
214  i += ret;
215  if(i < len)
216  {
217  if(select(timeout) == 0) return 0; // timeout
218  }
219  }
220 
221  return i;
222 }
223 
224 int rlSocket::readStr(char *buf, int len, int timeout)
225 {
226  int ret,i;
227 
228  if(s == -1) return -1;
229  if(select(timeout) == 0) return 0; // timeout
230 
231  // ::printf("debug: readStr len=%d", len);
232 
233  i = 0;
234  while(1)
235  {
236 #ifdef RLWIN32
237 tryagain:
238 #endif
239  ret = recv(s,&buf[i],1,0);
240  if(ret <= 0)
241  {
242 #ifdef RLWIN32
243  if(WSAEWOULDBLOCK == WSAGetLastError()) goto tryagain;
244 #endif
245  disconnect();
246  buf[i] = '\0';
247  return -1;
248  }
249 
250  //::printf(" %d\n", buf[i]);
251 
252  if(buf[i] == '\n')
253  {
254  buf[i+1] = '\0';
255  return i+1;
256  }
257  if(i >= len-1)
258  {
259  buf[i+1] = '\0';
260  return i+1;
261  }
262  i++;
263  }
264 }
265 
266 int rlSocket::readHttpHeader(rlString *header, int timeout)
267 {
268  char line[4096];
269  int contentLength = 0;
270 
271  *header = "";
272  while(1)
273  {
274  int ret = readStr(line, (int) sizeof(line)-1, timeout);
275  if(ret < 0)
276  {
277  printf("ERROR in rlSocket::readHttpHeader() ret=%d\n", ret);
278  return -1;
279  }
280  *header += line;
281  if(strstr(line, "Content-Length:") != NULL)
282  {
283  sscanf(line,"Content-Length: %d", &contentLength);
284  }
285  if(strlen(line) <= 2)
286  {
287  return contentLength;
288  }
289  }
290 }
291 
292 int rlSocket::write(const void *buf, int len)
293 {
294  int ret,bytes_left,first_byte;
295  const char *cbuf;
296 
297  if(s == -1) return -1;
298  cbuf = (char *) buf;
299  bytes_left = len;
300  first_byte = 0;
301 
302  //::printf("debug: write len=%d buf=", len);
303  //for(int i=0; i<len; i++) ::printf(" %d", cbuf[i]);
304  //::printf("\n");
305 
306  while(bytes_left > 0)
307  {
308  ret = send(s,&cbuf[first_byte],bytes_left,MSG_NOSIGNAL);
309  if(ret <= 0)
310  {
311  disconnect();
312  return -1;
313  }
314  bytes_left -= ret;
315  first_byte += ret;
316  }
317 
318  return first_byte;
319 }
320 
322 {
323  int option;
324  int ret;
325 #ifdef __VMS
326  size_t socklen = sizeof(struct sockaddr);
327 #else
328  socklen_t socklen = sizeof(struct sockaddr);
329 #endif
330  struct sockaddr_in localAddr;
331  struct sockaddr_in remoteAddr;
332  struct hostent *host;
333  struct in_addr RemoteIpAddress;
334 #ifdef AF_INET6_IS_AVAILABLE
335  struct addrinfo hints0, hints1;
336  struct addrinfo *res, *ressave;
337  int n;
338  char portstr[32];
339 #endif
340 
341  if(port <= 0) return PORT_ERR;
342  if(port >= 256*256) return PORT_ERR;
343  if(active == 0)
344  { // accept calls
345  s = -1;
346  if(rl_ipversion == 4)
347  {
348  if(first == 1)
349  {
350  // create a socket
351  os = socket(AF_INET,SOCK_STREAM,0);
352  if(os == -1) return SOCKET_ERR;
353  // set socket options
354 #ifdef __VMS
355  option = 1;
356  if(setsockopt(os,SOL_SOCKET,SO_KEEPALIVE,&option,sizeof(option)) < 0)
357  {
358  return SETSOCKOPT_ERR;
359  }
360 #endif
361  option = 1;
362 #ifdef RLWIN32
363  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,(const char *) &option,sizeof(option));
364 #else
365  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
366 #endif
367  // Bind our server to the agreed upon port number.
368  memset(&localAddr,0,sizeof(localAddr));
369  localAddr.sin_port = htons((short) port);
370  localAddr.sin_family = AF_INET;
371 bind:
372  ret = bind(os, (struct sockaddr *) &localAddr, sizeof(localAddr));
373  if(ret == -1)
374  {
375  ::printf("warning: could not bind to port=%d\n", port);
376  rlwthread_sleep(1000);
377  goto bind;
378  }
379  // Prepare to accept client connections. Allow up to 5 pending
380  // connections.
381  ret = listen(os, 5);
382  if(ret == -1) return LISTEN_ERR;
383  }
384  first = 0;
385 
386  // accept connections
387  if(os < 0) return ACCEPT_ERR;
388  s = accept(os, (struct sockaddr *) &sockaddr[0], &socklen);
389  if(s == -1) return ACCEPT_ERR;
390  }
391  else if(rl_ipversion == 6)
392  {
393 #ifdef AF_INET6_IS_AVAILABLE
394  if(first == 1)
395  {
396  memset(&hints0,0,sizeof(hints0));
397  hints0.ai_flags = AI_PASSIVE;
398  //hints0.ai_family = AF_UNSPEC;
399  hints0.ai_family = AF_INET6;
400  hints0.ai_socktype = SOCK_STREAM;
401  sprintf(portstr,"%d",port);
402  //::printf("server getaddrinfo(%s,%s)\n", adr, portstr);
403  n = getaddrinfo(adr, portstr, &hints0, &res);
404  if(n != 0)
405  {
406 #ifndef RLWIN32
407  ::printf("rlSocket:tcp_listen error for %s port=%s : %s\n", adr, portstr, gai_strerror(n));
408 #endif
409  return -1;
410  }
411  //::printf("done\n");
412  ressave = res;
413 bindv6:
414  do
415  {
416  os = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
417  if(os < 0) continue; // error, try next one
418 #ifdef __VMS
419  option = 1;
420  if(setsockopt(os,SOL_SOCKET,SO_KEEPALIVE,&option,sizeof(option)) < 0)
421  {
422  return SETSOCKOPT_ERR;
423  }
424 #endif
425  option = 1;
426 #ifdef RLWIN32
427  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,(const char *) &option,sizeof(option));
428 #else
429  setsockopt(os,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
430 #endif
431  if(bind(os, res->ai_addr, res->ai_addrlen) == 0) break; // success
432  s = os;
433  disconnect(); // bind error, close and try next one
434  }
435  while((res = res->ai_next) != NULL);
436  if(res == NULL) // errno from final socket() or bind()
437  {
438  ::printf("warning: could not bind to port=%d\n", port);
439  rlwthread_sleep(1000);
440  goto bindv6;
441  }
442  // Prepare to accept client connections. Allow up to 5 pending
443  // connections
444  ret = listen(os, 5);
445  freeaddrinfo(ressave);
446  if(ret == -1) return LISTEN_ERR;
447  }
448  first = 0;
449  // accept connections
450  if(os < 0) return ACCEPT_ERR;
451  s = accept(os, (struct sockaddr *) &sockaddr[0], &socklen);
452  if(s == -1) return ACCEPT_ERR;
453 #else
454  ::printf("rlSocket:ERROR IPV6 not available on this platform\n");
455 #endif
456  }
457  else
458  {
459  ::printf("rlSocket:ERROR: rl_ipversion=%d not known\n", rl_ipversion);
460  }
461  } // end active == 0
462  else if(active == 1)
463  {
464  disconnect();
465  //::printf("debug: adr=%s port=%d\n",adr,port);
466  s = -1;
467  if(rl_ipversion == 4)
468  {
469  os = socket(AF_INET,SOCK_STREAM,0);
470  if(os == -1) return SOCKET_ERR;
471  s = os;
472 
473  //::printf("debug: gethostbyname\n");
474  // fill destblk structure
475  host = gethostbyname(adr);
476  if(host == NULL)
477  {
478  // See if the host is specified in "dot address" form
479  RemoteIpAddress.s_addr = inet_addr(adr);
480  if(RemoteIpAddress.s_addr == INADDR_NONE)
481  {
482  // mur was here: without disconnect the sockets will be created over and over
483  disconnect();
484  s = -1;
485  return INET_ADDR_ERR; // -1
486  }
487  }
488  else
489  {
490  memcpy(&RemoteIpAddress,host->h_addr,host->h_length);
491  }
492 
493  memset(&remoteAddr,0,sizeof(remoteAddr));
494  remoteAddr.sin_family = AF_INET;
495  remoteAddr.sin_port = htons((short) port);
496  remoteAddr.sin_addr = RemoteIpAddress;
497 
498  //::printf("debug: connect\n");
499  ret = ::connect(s, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr));
500  //::printf("debug: connect ret=%d\n",ret);
501  if(ret == -1)
502  {
503  disconnect(); // close s = os
504  return CONNECT_ERR;
505  }
506  }
507  else if(rl_ipversion == 6)
508  {
509 #ifdef AF_INET6_IS_AVAILABLE
510  sprintf(portstr,"%d",port);
511  memset(&hints1, 0, sizeof(hints1));
512  hints1.ai_family = AF_UNSPEC;
513  hints1.ai_socktype = SOCK_STREAM;
514  n = getaddrinfo(adr, portstr, &hints1, &res);
515  if(n != 0)
516  {
517 #ifndef RLWIN32
518  ::printf("rlSocket:tcp_connect error for %s port=%s : %s\n", adr, portstr, gai_strerror(n));
519 #endif
520  return -1;
521  }
522  ressave = res;
523  do
524  {
525  s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
526  if(s < 0) continue; // ignore this one
527  if(::connect(s, res->ai_addr, res->ai_addrlen) == 0) break; // success
528  disconnect(); // ignore this one
529  }
530  while((res = res->ai_next) != NULL);
531  if(res == NULL) ::printf("rlSocket:tcp_connect error for %s port=%s\n", adr, portstr);
532  freeaddrinfo(ressave);
533 #else
534  ::printf("rlSocket:ERROR IPV6 not available on this platform\n");
535 #endif
536  }
537  else
538  {
539  ::printf("rlSocket:ERROR: rl_ipversion=%d not known\n", rl_ipversion);
540  }
541  }
542  return s;
543 }
544 
546 {
547  if(s != -1)
548  {
549 #ifdef RLWIN32
550  closesocket(s);
551 #else
552  close(s);
553 #endif
554  }
555  s = -1;
556  return 0;
557 }
558 
560 {
561  if(s == -1) return 0;
562  return 1;
563 }
564 
565 int rlSocket::select(int timeout)
566 {
567  struct timeval timout;
568  fd_set wset,rset,eset;
569  int ret,maxfdp1;
570 
571  if(timeout == 0) return 1;
572  /* setup sockets to read */
573  maxfdp1 = s+1;
574  FD_ZERO(&rset);
575  FD_SET (s,&rset);
576  FD_ZERO(&wset);
577  FD_ZERO(&eset);
578  timout.tv_sec = timeout / 1000;
579  timout.tv_usec = (timeout % 1000) * 1000;
580 
581  ret = ::select(maxfdp1,&rset,&wset,&eset,&timout);
582  if(ret == 0) return 0; /* timeout */
583  return 1;
584 }
585 
586 int rlSocket::printf(const char *format, ...)
587 {
588  int ret;
589  char message[rl_PRINTF_LENGTH]; // should be big enough
590 
591  va_list ap;
592  va_start(ap,format);
593  ret = rlvsnprintf(message, rl_PRINTF_LENGTH - 1, format, ap);
594  va_end(ap);
595  if(ret < 0) return ret;
596  return write(message,strlen(message));
597 }
598 
600 {
601  return printf("QPushButton(%d)\n",id);
602 }
603 
604 int rlSocket::setIPVersion(int version)
605 {
606  if(version == 6) rl_ipversion = 6;
607  else rl_ipversion = 4;
608  return rl_ipversion;
609 }
610 
612 {
613  return rl_ipversion;
614 }
615 
616 int rlSocket::rlGetsockopt(int sockfd, int level, int optname, void *optval, int *optlen)
617 {
618 #ifdef RLWIN32
619  return getsockopt(sockfd, level, optname, (char *) optval, optlen);
620 #elif defined(__VMS)
621  size_t len = *optlen;
622  int ret = getsockopt(sockfd, level, optname, optval, &len);
623  *optlen = len;
624  return ret;
625 #else
626  socklen_t len = *optlen;
627  int ret = getsockopt(sockfd, level, optname, optval, &len);
628  *optlen = len;
629  return ret;
630 #endif
631 }
632 
633 int rlSocket::rlSetsockopt(int sockfd, int level, int optname, const void *optval, int optlen)
634 {
635 #ifdef RLWIN32
636  return setsockopt(sockfd, level, optname, (const char *) optval, optlen);
637 #else
638  return setsockopt(sockfd, level, optname, optval, optlen);
639 #endif
640 }
641 
642 int rlSocket::rlGetsockopt(int level, int optname)
643 {
644  int option = 1;
645  int len = sizeof(option);
646  return rlGetsockopt(s,level,optname,&option,&len);
647 }
648 
649 int rlSocket::rlSetsockopt(int level, int optname)
650 {
651  int option = 1;
652  return rlSetsockopt(s,level,optname,&option,sizeof(option));
653 }
654 
656 {
657  char line[256];
658  while(1)
659  {
660  if(readStr(line, (int)sizeof(line) - 1, timeout) < 1) return -1;
661  if(strncmp(line,"Content-Length:",15) == 0) break;
662  }
663  int len = 0;
664  sscanf(line,"Content-Length: %d", &len);
665  if(readStr(line, (int)sizeof(line) - 1, timeout) < 1) return -1; // read CR LF
666  return len;
667 }
int setIPVersion(int version)
Definition: rlsocket.cpp:604
int write(const void *buf, int len)
Definition: rlsocket.cpp:292
void setActive(int active)
Definition: rlsocket.cpp:186
int readHttpHeader(rlString *header, int timeout=0)
Definition: rlsocket.cpp:266
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:224
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:599
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:633
int select(int timeout=0)
Definition: rlsocket.cpp:565
int os
Definition: rlsocket.h:264
int getPort()
Definition: rlsocket.cpp:181
void WSAAPI freeaddrinfo(struct addrinfo *)
int connect()
Definition: rlsocket.cpp:321
int s
Definition: rlsocket.h:197
int disconnect()
Definition: rlsocket.cpp:545
int isConnected()
Definition: rlsocket.cpp:559
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:616
int active
Definition: rlsocket.h:263
int readHttpContentLength(int timeout)
Definition: rlsocket.cpp:655
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:611
int printf(const char *format,...)
Definition: rlsocket.cpp:586
int rl_ipversion
Definition: rlsocket.h:267