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