IBR-DTNSuite  0.12
socket.cpp
Go to the documentation of this file.
1 /*
2  * socket.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrcommon/config.h"
23 #include "ibrcommon/net/socket.h"
24 #include "ibrcommon/net/vsocket.h"
25 #include "ibrcommon/Logger.h"
26 
27 #ifdef __WIN32__
28 #include <windows.h>
29 #include <ws2tcpip.h>
30 #ifndef AI_ADDRCONFIG
31 #define AI_ADDRCONFIG 0
32 #endif
33 #else
34 #include <arpa/inet.h>
35 #include <sys/select.h>
36 #include <netinet/tcp.h>
37 #include <sys/un.h>
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #endif
41 
42 #include <string.h>
43 #include <fcntl.h>
44 #include <sys/time.h>
45 #include <unistd.h>
46 
47 #include <sstream>
48 
49 #include <cassert>
50 
51 #ifndef HAVE_BZERO
52 #define bzero(s,n) (memset((s), '\0', (n)), (void) 0)
53 #endif
54 
55 #ifdef __WIN32__
56 #define EINPROGRESS WSAEINPROGRESS
57 #define ECONNRESET WSAECONNRESET
58 #define EAFNOSUPPORT WSAEAFNOSUPPORT
59 #define ENOBUFS WSAENOBUFS
60 #define EPROTONOSUPPORT WSAEPROTONOSUPPORT
61 #define ELOOP WSAELOOP
62 #endif
63 
64 namespace ibrcommon
65 {
66 #ifdef __WIN32__
67 
70  int __compat_setsockopt(int __fd, int __level, int __optname, __const void *__optval, socklen_t __optlen)
71  {
72  return ::setsockopt(__fd, __level, __optname, (char*)__optval, __optlen);
73  }
74 
75  int __init_sockets()
76  {
77  static bool initialized = false;
78  if (initialized) return 0;
79  WSADATA wsa;
80  return WSAStartup(MAKEWORD(2,2),&wsa);
81  }
82 
83 #define __close closesocket
84 #define __errno WSAGetLastError()
85 #else
86 #define __compat_setsockopt ::setsockopt
87 #define __init_sockets void
88 #define __close ::close
89 #define __errno errno
90 #endif
91 
92  int basesocket::DEFAULT_SOCKET_FAMILY = AF_INET6;
94 
97  }
98 
100  : _state(SOCKET_DOWN), _fd(-1), _family(PF_UNSPEC)
101  {
102  __init_sockets();
103  }
104 
106  : _state(SOCKET_UNMANAGED), _fd(fd), _family(PF_UNSPEC)
107  {
108  __init_sockets();
109  }
110 
112  {
113 #ifdef __DEVELOPMENT_ASSERTIONS__
114  assert((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED));
115  assert(_fd == -1);
116 #endif
117  }
118 
119  int basesocket::fd() const throw (socket_exception)
120  {
121  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED) || (_fd == -1)) throw socket_exception("fd not available");
122  return _fd;
123  }
124 
126  {
127  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED)) throw socket_exception("fd not available");
128  int fd = _fd;
129  _fd = -1;
130 
131  if (_state == SOCKET_UP)
133  else
135 
136  return fd;
137  }
138 
140  {
141  int ret = __close(this->fd());
142  if (ret == -1)
143  throw socket_exception("close error");
144 
145  _fd = -1;
146 
147  if (_state == SOCKET_UNMANAGED)
149  else
151  }
152 
154  {
155  int ret = ::shutdown(this->fd(), how);
156  if (ret == -1)
157  throw socket_exception("shutdown error");
158 
159  if (_state == SOCKET_UNMANAGED)
160  _state = SOCKET_DESTROYED;
161  else
162  _state = SOCKET_DOWN;
163  }
164 
165  bool basesocket::ready() const
166  {
167  return ((_state == SOCKET_UP) || (_state == SOCKET_UNMANAGED));
168  }
169 
170  void basesocket::set_blocking_mode(bool val, int fd) const throw (socket_exception)
171  {
172 #ifdef __WIN32__
173  // set blocking mode - the win32 way
174  unsigned long block_mode = (val) ? 1 : 0;
175  ioctlsocket((fd == -1) ? _fd : fd, FIONBIO, &block_mode);
176 #else
177  int opts;
178  opts = fcntl((fd == -1) ? _fd : fd, F_GETFL);
179  if (opts < 0) {
180  throw socket_exception("cannot set non-blocking");
181  }
182 
183  if (val)
184  opts &= ~(O_NONBLOCK);
185  else
186  opts |= O_NONBLOCK;
187 
188  if (fcntl((fd == -1) ? _fd : fd, F_SETFL, opts) < 0) {
189  throw socket_exception("cannot set non-blocking");
190  }
191 #endif
192  }
193 
194  void basesocket::set_keepalive(bool val, int fd) const throw (socket_exception)
195  {
196  /* Set the option active */
197  int optval = (val ? 1 : 0);
198  if (__compat_setsockopt((fd == -1) ? _fd : fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) {
199  throw ibrcommon::socket_exception("can not activate keepalives");
200  }
201  }
202 
203  void basesocket::set_linger(bool val, int l, int fd) const throw (socket_exception)
204  {
205  // set linger option to the socket
206  struct linger linger;
207 
208  linger.l_onoff = (val ? 1 : 0);
209  linger.l_linger = l;
210  if (__compat_setsockopt((fd == -1) ? _fd : fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) < 0) {
211  throw ibrcommon::socket_exception("can not set linger option");
212  }
213  }
214 
215  void basesocket::set_reuseaddr(bool val, int fd) const throw (socket_exception)
216  {
217  int on = (val ? 1: 0);
218  if (__compat_setsockopt((fd == -1) ? _fd : fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
219  {
220  throw socket_exception("setsockopt(SO_REUSEADDR) failed");
221  }
222  }
223 
224  void basesocket::set_nodelay(bool val, int fd) const throw (socket_exception)
225  {
226  int set = (val ? 1 : 0);
227  if (__compat_setsockopt((fd == -1) ? _fd : fd, IPPROTO_TCP, TCP_NODELAY, &set, sizeof(set)) < 0) {
228  throw socket_exception("set no delay option failed");
229  }
230  }
231 
232  sa_family_t basesocket::get_family() const throw (socket_exception)
233  {
234  return _family;
235  }
236 
237  sa_family_t basesocket::get_family(int fd) throw (socket_exception)
238  {
239  struct sockaddr_storage bound_addr;
240  socklen_t bound_len = sizeof(bound_addr);
241  ::memset(&bound_addr, 0, bound_len);
242 
243  // get the socket family
244  int ret = ::getsockname(fd, (struct sockaddr*)&bound_addr, &bound_len);
245  if (ret == -1) {
246  throw socket_exception("socket is not bound");
247  }
248 
249  return bound_addr.ss_family;
250  }
251 
252  bool basesocket::hasSupport(const sa_family_t family, const int type, const int protocol) throw ()
253  {
254  int fd = 0;
255  if ((fd = ::socket(family, type, protocol)) < 0) {
256  return false;
257  }
258  __close(fd);
259  return true;
260  }
261 
262  void basesocket::init_socket(const vaddress &addr, int type, int protocol) throw (socket_exception)
263  {
264  try {
265  _family = addr.family();
266  if ((_fd = ::socket(_family, type, protocol)) < 0) {
267  throw socket_raw_error(__errno, "cannot create socket");
268  }
269  } catch (const vaddress::address_exception&) {
270  // if no address is set use DEFAULT_SOCKET_FAMILY
271  if ((_fd = ::socket(DEFAULT_SOCKET_FAMILY, type, protocol)) > -1) {
272  _family = static_cast<sa_family_t>(DEFAULT_SOCKET_FAMILY);
273  }
274  // if that fails switch to the alternative SOCKET_FAMILY
275  else if ((_fd = ::socket(DEFAULT_SOCKET_FAMILY_ALTERNATIVE, type, protocol)) > -1) {
276  _family = static_cast<sa_family_t>(DEFAULT_SOCKET_FAMILY_ALTERNATIVE);
277 
278  // set the alternative socket family as default
279  DEFAULT_SOCKET_FAMILY = DEFAULT_SOCKET_FAMILY_ALTERNATIVE;
280  }
281  else
282  {
283  throw socket_raw_error(__errno, "cannot create socket");
284  }
285  }
286  }
287 
288  void basesocket::init_socket(int domain, int type, int protocol) throw (socket_exception)
289  {
290  _family = static_cast<sa_family_t>(domain);
291  if ((_fd = ::socket(domain, type, protocol)) < 0) {
292  throw socket_raw_error(__errno, "cannot create socket");
293  }
294  }
295 
296  void basesocket::bind(int fd, struct sockaddr *addr, socklen_t len) throw (socket_exception)
297  {
298  int ret = ::bind(fd, addr, len);
299 
300  if (ret < 0) {
301  // error
302  int bind_err = __errno;
303 
304  char addr_str[256];
305  char serv_str[256];
306  ::getnameinfo(addr, len, (char*)&addr_str, 256, (char*)&serv_str, 256, NI_NUMERICHOST | NI_NUMERICSERV);
307  std::stringstream ss;
308  vaddress vaddr(addr_str, serv_str, addr->sa_family);
309  ss << "with address " << vaddr.toString();
310 
311  check_bind_error(bind_err, ss.str());
312  }
313  }
314 
316  {
317  }
318 
320  : basesocket(fd)
321  {
322  }
323 
325  {
326  try {
327  down();
328  } catch (const socket_exception&) { }
329  }
330 
332  {
333  if (_state != SOCKET_DOWN)
334  throw socket_exception("socket is already up");
335 
336  _state = SOCKET_UP;
337  }
338 
340  {
341  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED))
342  throw socket_exception("socket is not up");
343 
344  this->close();
345  }
346 
347  ssize_t clientsocket::send(const char *data, size_t len, int flags) throw (socket_exception)
348  {
349  ssize_t ret = ::send(this->fd(), data, len, flags);
350  if (ret == -1) {
351  switch (__errno)
352  {
353  case EPIPE:
354  // connection has been reset
355  throw socket_error(ERROR_EPIPE, "connection has been reset");
356 
357  case ECONNRESET:
358  // Connection reset by peer
359  throw socket_error(ERROR_RESET, "Connection reset by peer");
360 
361  case EAGAIN:
362  // sent failed but we should retry again
363  throw socket_error(ERROR_AGAIN, "sent failed but we should retry again");
364 
365  default:
366  throw socket_error(ERROR_WRITE, "send error");
367  }
368  }
369  return ret;
370  }
371 
372  ssize_t clientsocket::recv(char *data, size_t len, int flags) throw (socket_exception)
373  {
374  ssize_t ret = ::recv(this->fd(), data, len, flags);
375  if (ret == -1) {
376  switch (__errno)
377  {
378  case EPIPE:
379  // connection has been reset
380  throw socket_error(ERROR_EPIPE, "connection has been reset");
381 
382  default:
383  throw socket_error(ERROR_READ, "read error");
384  }
385  }
386 
387  return ret;
388  }
389 
391  {
392  switch (opt) {
393  case NO_DELAY:
394  set_nodelay(val);
395  break;
396  case BLOCKING:
397  set_blocking_mode(val);
398  break;
399  default:
400  break;
401  }
402  }
403 
405  {
406  }
407 
409  : basesocket(fd)
410  {
411  }
412 
414  {
415  }
416 
417  void serversocket::listen(int connections) throw (socket_exception)
418  {
419  int ret = ::listen(_fd, connections);
420  if (ret == -1)
421  throw socket_exception("listen failed");
422  }
423 
425  {
426  struct sockaddr_storage cliaddr;
427  socklen_t len = sizeof(cliaddr);
428  ::memset(&cliaddr, 0, len);
429 
430  int new_fd = ::accept(this->fd(), (struct sockaddr *) &cliaddr, &len);
431 
432  if (new_fd <= 0) {
433  throw socket_exception("accept failed");
434  }
435 
436  // set source to addr
437  char address[256];
438  char service[256];
439  if (::getnameinfo((struct sockaddr *) &cliaddr, len, address, sizeof address, service, sizeof service, NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
440  addr = ibrcommon::vaddress(std::string(address), std::string(service), cliaddr.ss_family);
441  }
442 
443  return new_fd;
444  }
445 
446  void serversocket::set(SERVER_OPTION opt, bool val)
447  {
448  switch (opt) {
449  case BLOCKING:
450  set_blocking_mode(val);
451  break;
452  }
453  }
454 
456  {
457  }
458 
460  : basesocket(fd)
461  {
462  }
463 
465  {
466  }
467 
468  ssize_t datagramsocket::recvfrom(char *buf, size_t buflen, int flags, ibrcommon::vaddress &addr) throw (socket_exception)
469  {
470  struct sockaddr_storage clientAddress;
471  socklen_t clientAddressLength = sizeof(clientAddress);
472  ::memset(&clientAddress, 0, clientAddressLength);
473 
474  // data waiting
475  ssize_t ret = ::recvfrom(this->fd(), buf, buflen, flags, (struct sockaddr *) &clientAddress, &clientAddressLength);
476 
477  if (ret == -1) {
478  throw socket_exception("recvfrom error");
479  }
480 
481  char address[256];
482  char service[256];
483  if (::getnameinfo((struct sockaddr *) &clientAddress, clientAddressLength, address, sizeof address, service, sizeof service, NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
484  addr = ibrcommon::vaddress(std::string(address), std::string(service), clientAddress.ss_family);
485  }
486 
487  return ret;
488  }
489 
490  void datagramsocket::sendto(const char *buf, size_t buflen, int flags, const ibrcommon::vaddress &addr) throw (socket_exception)
491  {
492  int ret = 0;
493  struct addrinfo hints, *res;
494  memset(&hints, 0, sizeof hints);
495 
496  hints.ai_family = _family;
497  hints.ai_socktype = SOCK_DGRAM;
498  hints.ai_flags = AI_ADDRCONFIG;
499 
500  const char *address = NULL;
501  const char *service = NULL;
502 
503  try {
504  address = addr.address().c_str();
505  } catch (const vaddress::address_not_set&) {
506  throw socket_exception("need at least an address to send to");
507  };
508 
509  try {
510  service = addr.service().c_str();
511  } catch (const vaddress::address_not_set&) { };
512 
513  if ((ret = ::getaddrinfo(address, service, &hints, &res)) != 0)
514  {
515  throw socket_exception("getaddrinfo(): " + std::string(gai_strerror(ret)));
516  }
517 
518  ssize_t len = 0;
519  len = ::sendto(this->fd(), buf, buflen, flags, res->ai_addr, res->ai_addrlen);
520 
521  // free the addrinfo struct
522  freeaddrinfo(res);
523 
524  if (len == -1) {
525  throw socket_raw_error(__errno);
526  }
527  }
528 
530  : clientsocket(fd)
531  {
532  }
533 
535  : _filename(file)
536  {
537  }
538 
540  {
541  try {
542  down();
543  } catch (const socket_exception&) { }
544  }
545 
547  {
548  if (_state != SOCKET_DOWN)
549  throw socket_exception("socket is already up");
550 
551 #ifdef __WIN32__
552  throw socket_exception("socket type not supported");
553 #else
554  size_t len = 0;
555  struct sockaddr_un saun;
556 
557  /*
558  * Get a socket to work with. This socket will
559  * be in the UNIX domain, and will be a
560  * stream socket.
561  */
562  init_socket(AF_UNIX, SOCK_STREAM, 0);
563 
564  /*
565  * Create the address we will be connecting to.
566  */
567  saun.sun_family = AF_UNIX;
568  ::strcpy(saun.sun_path, _filename.getPath().c_str());
569 
570  /*
571  * Try to connect to the address. For this to
572  * succeed, the server must already have bound
573  * this address, and must have issued a listen()
574  * request.
575  *
576  * The third argument indicates the "length" of
577  * the structure, not just the length of the
578  * socket name.
579  */
580  len = sizeof(saun.sun_family) + strlen(saun.sun_path);
581 
582  if (::connect(_fd, (struct sockaddr *)&saun, static_cast<socklen_t>(len)) < 0) {
583  this->close();
584  throw socket_exception("Could not connect to the named socket.");
585  }
586 #endif
587 
588  _state = SOCKET_UP;
589  }
590 
592  {
593  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED))
594  throw socket_exception("socket is not up");
595 
596  this->close();
597  }
598 
600  : _filename(file), _listen(listen)
601  {
602  }
603 
605  {
606  try {
607  down();
608  } catch (const socket_exception&) { }
609  }
610 
612  {
613  if (_state != SOCKET_DOWN)
614  throw socket_exception("socket is already up");
615 
616  /*
617  * Get a socket to work with. This socket will
618  * be in the UNIX domain, and will be a
619  * stream socket.
620  */
621  init_socket(AF_UNIX, SOCK_STREAM, 0);
622 
623  try {
624  this->bind(_filename);
625  this->listen(_listen);
626  } catch (const socket_exception&) {
627  // clean-up socket
628  __close(_fd);
629  _fd = -1;
630  throw;
631  };
632 
633  _state = SOCKET_UP;
634  }
635 
637  {
638  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED))
639  throw socket_exception("socket is not up");
640 
641  this->close();
642  }
643 
645  {
646  return new filesocket(_accept_fd(addr));
647  }
648 
649  void fileserversocket::bind(const File &file) throw (socket_exception)
650  {
651 #ifndef __WIN32__
652  // remove old sockets
653  unlink(file.getPath().c_str());
654 
655  struct sockaddr_un address;
656  size_t address_length;
657 
658  address.sun_family = AF_UNIX;
659  strcpy(address.sun_path, file.getPath().c_str());
660  address_length = sizeof(address.sun_family) + strlen(address.sun_path);
661 
662  // bind to the socket
663  basesocket::bind(_fd, (struct sockaddr *) &address, static_cast<socklen_t>(address_length));
664 #endif
665  }
666 
667  tcpserversocket::tcpserversocket(const int port, int listen)
668  : _address(port), _listen(listen)
669  {
670  }
671 
673  : _address(address), _listen(listen)
674  {
675  }
676 
678  {
679  try {
680  down();
681  } catch (const socket_exception&) { }
682  }
683 
685  {
686  if (_state != SOCKET_DOWN)
687  throw socket_exception("socket is already up");
688 
689  init_socket(_address, SOCK_STREAM, 0);
690 
691  // enable reuse to avoid delay on process restart
692  this->set_reuseaddr(true);
693 
694  try {
695  // try to bind on port and/or address
696  this->bind(_address);
697  this->listen(_listen);
698  } catch (const socket_exception&) {
699  // clean-up socket
700  __close(_fd);
701  _fd = -1;
702  throw;
703  };
704 
705  _state = SOCKET_UP;
706  }
707 
709  {
710  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED))
711  throw socket_exception("socket is not up");
712 
713  this->close();
714  }
715 
717  {
718  struct addrinfo hints, *res;
719  memset(&hints, 0, sizeof hints);
720 
721  hints.ai_family = _family;
722  hints.ai_socktype = SOCK_STREAM;
723  hints.ai_flags = 0;
724 
725  const char *address = NULL;
726  const char *service = NULL;
727 
728  if (addr.isAny()) {
729  hints.ai_flags |= AI_PASSIVE;
730  address = NULL;
731  } else if (addr.isLocal()) {
732  address = NULL;
733  } else {
734  hints.ai_flags |= AI_PASSIVE;
735  try {
736  address = addr.address().c_str();
737  } catch (const vaddress::address_not_set&) { };
738  }
739 
740  try {
741  service = addr.service().c_str();
742  } catch (const vaddress::address_not_set&) { };
743 
744  if (0 != ::getaddrinfo(address, service, &hints, &res))
745  throw socket_exception("failed to getaddrinfo with address: " + addr.toString());
746 
747  try {
748  basesocket::bind(_fd, res->ai_addr, res->ai_addrlen);
749  freeaddrinfo(res);
750  } catch (const socket_exception&) {
751  freeaddrinfo(res);
752  throw;
753  }
754  }
755 
757  {
758  return new tcpsocket(_accept_fd(addr));
759  }
760 
762  {
763  return _address;
764  }
765 
767  : clientsocket(fd)
768  {
769  timerclear(&_timeout);
770  }
771 
772  tcpsocket::tcpsocket(const ibrcommon::vaddress &destination, const timeval *timeout)
773  : _address(destination)
774  {
775  if (timeout == NULL) {
776  timerclear(&_timeout);
777  } else {
778  ::memcpy(&_timeout, timeout, sizeof _timeout);
779  }
780  }
781 
783  {
784  try {
785  down();
786  } catch (const socket_exception&) { }
787  }
788 
790  {
791  if (_state != SOCKET_DOWN)
792  throw socket_exception("socket is already up");
793 
794  struct addrinfo hints;
795  struct addrinfo *walk;
796  memset(&hints, 0, sizeof(struct addrinfo));
797  hints.ai_family = PF_UNSPEC;
798  hints.ai_socktype = SOCK_STREAM;
799  hints.ai_flags = 0;
800 
801  struct addrinfo *res = NULL;
802  int ret = 0;
803 
804  const char *address = NULL;
805  const char *service = NULL;
806 
807  try {
808  address = _address.address().c_str();
809  } catch (const vaddress::address_not_set&) {
810  throw socket_exception("need at least an address to connect to");
811  };
812 
813  try {
814  service = _address.service().c_str();
815  } catch (const vaddress::service_not_set&) { };
816 
817  if ((ret = ::getaddrinfo(address, service, &hints, &res)) != 0)
818  {
819  throw socket_exception("getaddrinfo(): " + std::string(gai_strerror(ret)));
820  }
821 
822  if (res == NULL)
823  {
824  throw socket_exception("Could not connect to the server.");
825  }
826 
827  // create a vsocket for concurrent connection setup
828  ibrcommon::vsocket probesocket;
829 
830  try {
831  // walk through all the returned addresses and try to connect to all of them
832  for (walk = res; walk != NULL; walk = walk->ai_next) {
833  // mark the socket as invalid first
834  int fd = -1;
835 
836  // create a matching socket
837  fd = ::socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol);
838 
839  // if the socket is invalid we proceed with the next address
840  if (fd < 0) {
841  /* Hier kann eine Fehlermeldung hin, z.B. mit warn() */
842 
843  if ((walk->ai_next == NULL) && (probesocket.size() == 0))
844  {
845  throw socket_exception("Could not create a socket.");
846  }
847  continue;
848  }
849 
850  // set the socket to non-blocking
851  this->set_blocking_mode(false, fd);
852 
853  // connect to the current address using the created socket
854  if (::connect(fd, walk->ai_addr, walk->ai_addrlen) != 0) {
855  if (__errno != EINPROGRESS) {
856  // the connect failed, so we close the socket immediately
857  __close(fd);
858 
859  /* Hier kann eine Fehlermeldung hin, z.B. mit warn() */
860  if ((walk->ai_next == NULL) && (probesocket.size() == 0))
861  {
862  throw socket_raw_error(__errno);
863  }
864  continue;
865  }
866  }
867 
868  // add the current socket to the probe-socket for later select-call
869  probesocket.add( new tcpsocket(fd) );
870  }
871 
872  // bring probesocket into UP state
873  probesocket.up();
874 
875  // create a probe set
876  socketset probeset;
877 
878  timeval timeout_value;
879  ::memcpy(&timeout_value, &_timeout, sizeof timeout_value);
880 
881  bool fastest_found = false;
882 
883  while (!fastest_found) {
884  // clear the probe-set
885  probeset.clear();
886 
887  if (timerisset(&_timeout)) {
888  // check timeout value
889  if (!timerisset(&timeout_value)) {
890  // timeout reached abort this
891  break;
892  }
893 
894  // probe for the first open socket using a timer value
895  probesocket.select(NULL, &probeset, NULL, &timeout_value);
896  } else {
897  // probe for the first open socket without any timer
898  probesocket.select(NULL, &probeset, NULL, NULL);
899  }
900 
901  // error checking for all returned sockets
902  for (socketset::iterator iter = probeset.begin(); iter != probeset.end(); ++iter) {
903  basesocket *current = (*iter);
904  int err = 0;
905  socklen_t len = sizeof(err);
906 #ifdef __WIN32__
907  ::getsockopt(current->fd(), SOL_SOCKET, SO_ERROR, (char*)&err, &len);
908 #else
909  ::getsockopt(current->fd(), SOL_SOCKET, SO_ERROR, &err, &len);
910 #endif
911 
912  switch (err) {
913  case 0:
914  // we got a winner!
915  fastest_found = true;
916 
917  // assign the fasted fd
918  _fd = current->release();
919 
920  // switch back to standard blocking mode
921  this->set_blocking_mode(true);
922  break;
923 
924  case EINPROGRESS:
925  // wait another round
926  break;
927 
928  default:
929  // error, remove the socket out of the probeset
930  probesocket.remove(current);
931  current->close();
932  delete current;
933 
934  // if this was the last socket then abort with an exception
935  if (probesocket.size() == 0) {
936  throw socket_raw_error(err);
937  }
938  break;
939  }
940 
941  if (fastest_found) break;
942  }
943  }
944 
945  if (fastest_found == false) {
946  throw socket_exception("connection setup timed out");
947  }
948 
949  // free the address
950  freeaddrinfo(res);
951 
952  // set the current state to UP
953  _state = SOCKET_UP;
954  } catch (const std::exception&) {
955  freeaddrinfo(res);
956  probesocket.destroy();
957  throw;
958  }
959 
960  // bring all other sockets down and clean-up
961  probesocket.destroy();
962  }
963 
965  {
966  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED))
967  throw socket_exception("socket is not up");
968 
969  this->close();
970  }
971 
973  {
974  }
975 
977  : _address(address)
978  {
979  }
980 
982  {
983  try {
984  down();
985  } catch (const socket_exception&) { }
986  }
987 
989  {
990  return _address;
991  }
992 
994  {
995  if (_state != SOCKET_DOWN)
996  throw socket_exception("socket is already up");
997 
998  init_socket(_address, SOCK_DGRAM, 0);
999 
1000  try {
1001  // test if the service is defined
1002  _address.service();
1003 
1004  // service is defined, enable reuseaddr option
1005  this->set_reuseaddr(true);
1006  } catch (const vaddress::address_exception&) { }
1007 
1008  try {
1009  // try to bind on port and/or address
1010  this->bind(_address);
1011  } catch (const socket_exception&) {
1012  // clean-up socket
1013  __close(_fd);
1014  _fd = -1;
1015  throw;
1016  };
1017 
1018  _state = SOCKET_UP;
1019  }
1020 
1022  {
1023  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED))
1024  throw socket_exception("socket is not up");
1025 
1026  this->close();
1027  }
1028 
1029  void udpsocket::bind(const vaddress &addr) throw (socket_exception)
1030  {
1031  struct addrinfo hints, *res;
1032  memset(&hints, 0, sizeof hints);
1033 
1034  hints.ai_family = _family;
1035  hints.ai_socktype = SOCK_DGRAM;
1036  hints.ai_flags = 0;
1037 
1038  const char *address = NULL;
1039  const char *service = NULL;
1040 
1041  if (addr.isAny()) {
1042  hints.ai_flags |= AI_PASSIVE;
1043  address = NULL;
1044  } else if (addr.isLocal()) {
1045  address = NULL;
1046  } else {
1047  hints.ai_flags |= AI_PASSIVE;
1048  try {
1049  address = addr.address().c_str();
1050  } catch (const vaddress::address_not_set&) { };
1051  }
1052 
1053  try {
1054  service = addr.service().c_str();
1055  } catch (const vaddress::service_not_set&) { };
1056 
1057  if (0 != ::getaddrinfo(address, service, &hints, &res))
1058  throw socket_exception("failed to getaddrinfo with address: " + addr.toString());
1059 
1060  try {
1061  basesocket::bind(_fd, res->ai_addr, res->ai_addrlen);
1062  freeaddrinfo(res);
1063  } catch (const socket_exception&) {
1064  freeaddrinfo(res);
1065  throw;
1066  }
1067  }
1068 
1070  : udpsocket(address)
1071  {
1072  }
1073 
1075  {
1076  }
1077 
1079  {
1080  udpsocket::up();
1081 
1082  try {
1083  switch (get_family()) {
1084  case AF_INET: {
1085 #ifdef HAVE_FEATURES_H
1086  int val = 1;
1087  if ( __compat_setsockopt(_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const char *)&val, sizeof(val)) < 0 )
1088  {
1089  throw socket_exception("setsockopt(IP_MULTICAST_LOOP)");
1090  }
1091 
1092  unsigned char ttl = 7; // Multicast TTL
1093  if ( __compat_setsockopt(_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0 )
1094  {
1095  throw socket_exception("setsockopt(IP_MULTICAST_TTL)");
1096  }
1097 #endif
1098 // unsigned char ittl = 255; // IP TTL
1099 // if ( __compat_setsockopt(this->fd(), IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) < 0 )
1100 // {
1101 // throw socket_exception("setsockopt(IP_TTL)");
1102 // }
1103  break;
1104  }
1105 
1106  case AF_INET6: {
1107 #ifdef HAVE_FEATURES_H
1108  int val = 1;
1109  if ( __compat_setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char *)&val, sizeof(val)) < 0 )
1110  {
1111  throw socket_exception("setsockopt(IPV6_MULTICAST_LOOP)");
1112  }
1113 
1114 // unsigned char ttl = 255; // Multicast TTL
1115 // if ( __compat_setsockopt(this_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0 )
1116 // {
1117 // throw socket_exception("setsockopt(IPV6_MULTICAST_HOPS)");
1118 // }
1119 #endif
1120 
1121 // unsigned char ittl = 255; // IP TTL
1122 // if ( __compat_setsockopt(_fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &ittl, sizeof(ittl)) < 0 )
1123 // {
1124 // throw socket_exception("setsockopt(IPV6_HOPLIMIT)");
1125 // }
1126  break;
1127  }
1128  }
1129  } catch (const socket_exception&) {
1130  udpsocket::down();
1131  throw;
1132  }
1133  }
1134 
1136  {
1137  switch (get_family()) {
1138  case AF_INET: {
1139 #ifdef HAVE_FEATURES_H
1140  int val = 0;
1141  if ( __compat_setsockopt(_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const char *)&val, sizeof(val)) < 0 )
1142  {
1143  throw socket_exception("setsockopt(IP_MULTICAST_LOOP)");
1144  }
1145 #endif
1146  break;
1147  }
1148 
1149  case AF_INET6: {
1150 #ifdef HAVE_FEATURES_H
1151  int val = 0;
1152  if ( __compat_setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char *)&val, sizeof(val)) < 0 )
1153  {
1154  throw socket_exception("setsockopt(IPV6_MULTICAST_LOOP)");
1155  }
1156 #endif
1157  break;
1158  }
1159  }
1160 
1161  udpsocket::down();
1162  }
1163 
1165  {
1166 #ifndef MCAST_JOIN_GROUP
1167  if (group.family() == AF_INET6) {
1168  mcast_op(IPV6_JOIN_GROUP, group, iface);
1169  } else {
1170  mcast_op(IP_ADD_MEMBERSHIP, group, iface);
1171  }
1172 #else
1173  mcast_op(MCAST_JOIN_GROUP, group, iface);
1174 #endif
1175  }
1176 
1178  {
1179 #ifndef MCAST_LEAVE_GROUP
1180  if (group.family() == AF_INET6) {
1181  mcast_op(IPV6_LEAVE_GROUP, group, iface);
1182  } else {
1183  mcast_op(IP_DROP_MEMBERSHIP, group, iface);
1184  }
1185 #else
1186  mcast_op(MCAST_LEAVE_GROUP, group, iface);
1187 #endif
1188  }
1189 
1190 #ifndef MCAST_JOIN_GROUP
1191  void __copy_device_address(struct in_addr *inaddr, const vinterface &iface) {
1192  ssize_t ret = 0;
1193  struct addrinfo hints, *res;
1194  memset(&hints, 0, sizeof hints);
1195 
1196  hints.ai_family = AF_INET;
1197  hints.ai_socktype = SOCK_DGRAM;
1198 
1199  // determine interface address
1200  struct sockaddr_storage iface_addr;
1201  ::memset(&iface_addr, 0, sizeof(iface_addr));
1202 
1203  const std::list<vaddress> iface_addrs = iface.getAddresses();
1204  for (std::list<vaddress>::const_iterator iter = iface_addrs.begin(); iter != iface_addrs.end(); ++iter) {
1205  const vaddress &addr = (*iter);
1206 
1207  if ((ret = ::getaddrinfo(addr.address().c_str(), NULL, &hints, &res)) == 0) {
1208  // address found
1209  ::memcpy(inaddr, &((struct sockaddr_in*)res->ai_addr)->sin_addr, sizeof(struct sockaddr_in));
1210 
1211  // free the addrinfo struct
1212  freeaddrinfo(res);
1213 
1214  break;
1215  }
1216  }
1217  }
1218 #endif
1219 
1220  void multicastsocket::mcast_op(int optname, const vaddress &group, const vinterface &iface) throw (socket_exception)
1221  {
1222  struct sockaddr_storage mcast_addr;
1223  ::memset(&mcast_addr, 0, sizeof(mcast_addr));
1224 
1225  int level = 0;
1226  int ret = 0;
1227 
1228  struct addrinfo hints, *res;
1229  memset(&hints, 0, sizeof hints);
1230 
1231  hints.ai_family = PF_UNSPEC;
1232  hints.ai_socktype = SOCK_DGRAM;
1233  hints.ai_flags = 0;
1234 
1235  if ((ret = ::getaddrinfo(group.address().c_str(), NULL, &hints, &res)) != 0) {
1236  throw socket_exception("getaddrinfo(): " + std::string(gai_strerror(ret)));
1237  }
1238 
1239  switch (res->ai_family) {
1240  case AF_INET:
1241  level = IPPROTO_IP;
1242  break;
1243 
1244  case AF_INET6:
1245  level = IPPROTO_IPV6;
1246  break;
1247 
1248  default:
1249  // free the addrinfo struct
1250  freeaddrinfo(res);
1251 
1252  throw socket_exception("address family not supported");
1253  }
1254 
1255 #ifndef MCAST_JOIN_GROUP
1256  if (res->ai_family == AF_INET) {
1257  struct ip_mreq req;
1258  ::memset(&req, 0, sizeof(req));
1259 
1260  // copy the address to the group request
1261  req.imr_multiaddr = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
1262 
1263  // free the addrinfo struct
1264  freeaddrinfo(res);
1265 
1266  // set the right interface
1267  __copy_device_address(&req.imr_interface, iface);
1268 
1269  if ( __compat_setsockopt(this->fd(), level, optname, &req, sizeof(req)) == -1 )
1270  {
1271  throw socket_raw_error(__errno, "setsockopt()");
1272  }
1273  } else {
1274  struct ipv6_mreq req;
1275  ::memset(&req, 0, sizeof(req));
1276 
1277  // copy the address to the group request
1278  req.ipv6mr_multiaddr = ((struct sockaddr_in6*)res->ai_addr)->sin6_addr;
1279 
1280  // free the addrinfo struct
1281  freeaddrinfo(res);
1282 
1283  // set the right interface
1284  req.ipv6mr_interface = iface.getIndex();
1285 
1286  if ( __compat_setsockopt(this->fd(), level, optname, &req, sizeof(req)) == -1 )
1287  {
1288  throw socket_raw_error(__errno, "setsockopt()");
1289  }
1290  }
1291 #else
1292  struct group_req req;
1293  ::memset(&req, 0, sizeof(req));
1294 
1295  // copy the address to the group request
1296  ::memcpy(&req.gr_group, res->ai_addr, res->ai_addrlen);
1297 
1298  // free the addrinfo struct
1299  freeaddrinfo(res);
1300 
1301  // set the right interface here
1302  req.gr_interface = iface.getIndex();
1303 
1304  if ( __compat_setsockopt(this->fd(), level, optname, &req, sizeof(req)) == -1 )
1305  {
1306  throw socket_raw_error(__errno, "setsockopt()");
1307  }
1308 #endif
1309 
1310  // successful!
1311  IBRCOMMON_LOGGER_DEBUG_TAG("multicastsocket", 70) << "multicast operation (" << optname << ") successful with " << group.toString() << " on " << iface.toString() << IBRCOMMON_LOGGER_ENDL;
1312  }
1313 
1314  void basesocket::check_socket_error(const int err) const throw (socket_exception)
1315  {
1316  switch (err)
1317  {
1318  case EACCES:
1319  throw socket_exception("Permission to create a socket of the specified type and/or protocol is denied.");
1320 
1321  case EAFNOSUPPORT:
1322  throw socket_exception("The implementation does not support the specified address family.");
1323 
1324  case EINVAL:
1325  throw socket_exception("Unknown protocol, or protocol family not available.");
1326 
1327  case EMFILE:
1328  throw socket_exception("Process file table overflow.");
1329 
1330  case ENFILE:
1331  throw socket_exception("The system limit on the total number of open files has been reached.");
1332 
1333  case ENOBUFS:
1334  case ENOMEM:
1335  throw socket_exception("Insufficient memory is available. The socket cannot be created until sufficient resources are freed.");
1336 
1337  case EPROTONOSUPPORT:
1338  throw socket_exception("The protocol type or the specified protocol is not supported within this domain.");
1339 
1340  default:
1341  throw socket_exception("Cannot create a socket.");
1342  }
1343  }
1344 
1345  void basesocket::check_bind_error(const int err, const std::string &msg) const throw (socket_exception)
1346  {
1347  switch ( err )
1348  {
1349  case EBADF:
1350  throw socket_exception("sockfd is not a valid descriptor.");
1351 
1352  case EINVAL:
1353  throw socket_exception("The socket is already bound to an address.");
1354 
1355  case EROFS:
1356  throw socket_exception("The socket inode would reside on a read-only filesystem.");
1357 
1358  case EFAULT:
1359  throw socket_exception("Given address points outside the user's accessible address space.");
1360 
1361  case ENAMETOOLONG:
1362  throw socket_exception("Given address is too long.");
1363 
1364  case ENOENT:
1365  throw socket_exception("The file does not exist.");
1366 
1367  case ENOMEM:
1368  throw socket_exception("Insufficient kernel memory was available.");
1369 
1370  case ENOTDIR:
1371  throw socket_exception("A component of the path prefix is not a directory.");
1372 
1373  case EACCES:
1374  throw socket_exception("Search permission is denied on a component of the path prefix.");
1375 
1376  case ELOOP:
1377  throw socket_exception("Too many symbolic links were encountered in resolving the given address.");
1378 
1379  default:
1380  throw socket_exception("Cannot bind to socket " + msg);
1381  }
1382  }
1383 }