Fawkes API  Fawkes Development Version
socket.cpp
1 
2 /***************************************************************************
3  * socket.h - Fawkes socket base class
4  *
5  * Created: Thu Nov 09 14:30:56 2006
6  * Copyright 2006 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/exceptions/system.h>
25 #include <netcomm/socket/socket.h>
26 #include <utils/misc/string_conversions.h>
27 #include <utils/time/time.h>
28 
29 #ifndef _GNU_SOURCE
30 # define _GNU_SOURCE
31 #endif
32 
33 #include <sys/socket.h>
34 #include <sys/types.h>
35 
36 #include <cstdlib>
37 #include <cstring>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <netdb.h>
41 #include <string>
42 #include <unistd.h>
43 // include <linux/in.h>
44 #include <arpa/inet.h>
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip.h>
48 
49 #include <cstdio>
50 #include <poll.h>
51 
52 // Until this is integrated from linux/in.h to netinet/in.h
53 #ifdef __linux__
54 # ifndef IP_MTU
55 # define IP_MTU 14
56 # endif
57 #endif // __linux__
58 #ifdef __FreeBSD__
59 # include <net/if.h>
60 # include <sys/ioctl.h>
61 #endif
62 
63 namespace fawkes {
64 
65 /** @class SocketException netcomm/socket/socket.h
66  * Socket exception.
67  * Thrown if an exception occurs in a socket. If the error was caused by
68  * a system call that sets errno this is given to the exception.
69  * @ingroup NetComm
70  */
71 
72 /** Constructor.
73  * @param format format for reason that caused the exception.
74  */
75 SocketException::SocketException(const char *format, ...) : Exception()
76 {
77  va_list va;
78  va_start(va, format);
79  append_va(format, va);
80  va_end(va);
81 }
82 
83 /** Constructor.
84  * @param msg reason of the exception
85  * @param _errno error number (errno returned by a syscall)
86  */
87 SocketException::SocketException(int _errno, const char *msg) : Exception(_errno, "%s", msg)
88 {
89 }
90 
91 /** @class Socket netcomm/socket/socket.h
92  * Socket base class.
93  * This is the base class for all sockets. You cannot use it directly
94  * but you have to use one of the derivatives like StreamSocket or
95  * DatagramSocket.
96  * @ingroup NetComm
97  * @author Tim Niemueller
98  */
99 
100 /** @var Socket::addr_type
101  * Address type/family of socket.
102  */
103 /** @var Socket::sock_fd
104  * Socket file descriptor.
105  */
106 /** @var Socket::timeout
107  * Timeout in seconds for various operations. If the timeout is non-zero
108  * the socket is initialized non-blocking and operations are aborted after
109  * timeout seconds have passed.
110  */
111 /** @var Socket::client_addr
112  * Client address, set if connected.
113  */
114 /** @var Socket::client_addr_len
115  * length in bytes of client address.
116  */
117 
118 /** Data can be read. */
119 const short Socket::POLL_IN = POLLIN;
120 
121 /** Writing will not block. */
122 const short Socket::POLL_OUT = POLLOUT;
123 
124 /** There is urgent data to read (e.g., out-of-band data on TCP socket;
125  * pseudo-terminal master in packet mode has seen state change in slave).
126  */
127 const short Socket::POLL_PRI = POLLPRI;
128 
129 /** Stream socket peer closed connection, or shut down writing half of
130  * connection. The _GNU_SOURCE feature test macro must be defined
131  * in order to obtain this definition (since Linux 2.6.17).
132  */
133 #ifdef POLLRDHUP
134 const short Socket::POLL_RDHUP = POLLRDHUP;
135 #else
136 const short Socket::POLL_RDHUP = 0;
137 #endif
138 
139 /** Error condition. */
140 const short Socket::POLL_ERR = POLLERR;
141 
142 /** Hang up. */
143 const short Socket::POLL_HUP = POLLHUP;
144 
145 /** Invalid request. */
146 const short Socket::POLL_NVAL = POLLNVAL;
147 
148 /** Constructor similar to syscall.
149  * This creates a new socket. This is a plain pass-through constructor
150  * to the socket() syscall. In most cases this should only be used by
151  * a derivate.
152  * @param addr_type Specify IPv4 or IPv6
153  * @param sock_type socket type, either TCP or UDP
154  * @param timeout See Socket::timeout.
155  * @exception SocketException thrown if socket cannot be opened, check errno for cause
156  */
157 Socket::Socket(AddrType addr_type, SocketType sock_type, float timeout)
158 : addr_type(addr_type),
159  sock_fd(-1),
160  timeout(timeout),
161  client_addr(NULL),
162  client_addr_len(0),
163  socket_protocol_(0)
164 {
165  if (addr_type == IPv4) {
166  socket_addr_family_ = AF_INET;
167  } else if (addr_type == IPv6) {
168  socket_addr_family_ = AF_INET6;
169  } else {
170  throw SocketException("Unknown address type");
171  }
172  if (sock_type == TCP) {
173  socket_type_ = SOCK_STREAM;
174  } else if (sock_type == UDP) {
175  socket_type_ = SOCK_DGRAM;
176  } else {
177  throw SocketException("Unknown socket type");
178  }
179 }
180 
181 /** IPv4 Constructor.
182  * This creates a new socket. This is a plain pass-through constructor
183  * to the socket() syscall. In most cases this should only be used by
184  * a derivate.
185  * @param sock_type socket type, either TCP or UDP
186  * @param timeout See Socket::timeout.
187  * @exception SocketException thrown if socket cannot be opened, check errno for cause
188  */
189 Socket::Socket(SocketType sock_type, float timeout)
190 : sock_fd(-1),
191  timeout(timeout),
192  client_addr(NULL),
193  client_addr_len(0),
194  socket_addr_family_(-1),
195  socket_protocol_(0)
196 {
197  if (sock_type == TCP) {
198  socket_type_ = SOCK_STREAM;
199  } else if (sock_type == UDP) {
200  socket_type_ = SOCK_DGRAM;
201  } else {
202  throw SocketException("Unknown socket type");
203  }
204 }
205 
206 /** Constructor.
207  * Plain constructor. The socket will not be opened. This may only be called by
208  * sub-classes and you must ensure that the socket file descriptor is initialized
209  * properly.
210  */
212 : sock_fd(-1),
213  timeout(0.f),
214  client_addr(NULL),
215  client_addr_len(0),
216  socket_addr_family_(0),
217  socket_type_(0),
218  socket_protocol_(0)
219 {
220 }
221 
222 /** Copy constructor.
223  * @param socket socket to copy
224  */
225 Socket::Socket(Socket &socket)
226 {
227  if (socket.client_addr != NULL) {
228  if (socket.client_addr_len > sizeof(struct ::sockaddr_storage)) {
229  throw SocketException("Invalid client socket address length");
230  }
231  client_addr = (struct ::sockaddr_storage *)malloc(sizeof(struct ::sockaddr_storage));
232  client_addr_len = sizeof(struct ::sockaddr_storage);
233  memcpy(client_addr, socket.client_addr, client_addr_len);
234  } else {
235  client_addr = NULL;
236  client_addr_len = 0;
237  }
238  timeout = socket.timeout;
239  sock_fd = dup(socket.sock_fd);
240  socket_addr_family_ = socket.socket_addr_family_;
241  socket_type_ = socket.socket_type_;
242  socket_protocol_ = socket.socket_protocol_;
243 }
244 
245 /** Copy constructor.
246  * @param socket socket to copy
247  * @return reference to this instance
248  */
250 Socket::operator=(Socket &socket)
251 {
252  close();
253  if (client_addr != NULL) {
254  free(client_addr);
255  client_addr = NULL;
256  }
257 
258  if (socket.client_addr != NULL) {
259  if (socket.client_addr_len > sizeof(struct ::sockaddr_storage)) {
260  throw SocketException("Invalid client socket address length");
261  }
262  client_addr = (struct ::sockaddr_storage *)malloc(sizeof(struct ::sockaddr_storage));
263  client_addr_len = sizeof(struct ::sockaddr_storage);
264  memcpy(client_addr, socket.client_addr, client_addr_len);
265  } else {
266  client_addr = NULL;
267  client_addr_len = 0;
268  }
269  timeout = socket.timeout;
270  sock_fd = dup(socket.sock_fd);
271  socket_addr_family_ = socket.socket_addr_family_;
272  socket_type_ = socket.socket_type_;
273  socket_protocol_ = socket.socket_protocol_;
274 
275  return *this;
276 }
277 
278 void
279 Socket::create()
280 {
281  if (sock_fd != -1)
282  return;
283  if (socket_addr_family_ == -1) {
284  throw UnknownTypeException("Invalid socket address family, wrong constructor called?");
285  }
286 
287  if ((sock_fd = socket(socket_addr_family_, socket_type_, socket_protocol_)) == -1) {
288  throw SocketException(errno, "Could not open socket");
289  }
290 
291  if (timeout > 0.f) {
292  // set to non-blocking
293  if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) == -1) {
294  throw SocketException(errno, "Could not set socket to non-blocking");
295  }
296  }
297 }
298 
299 /** Destructor. */
301 {
302  close();
303  if (client_addr != NULL) {
304  free(client_addr);
305  client_addr = NULL;
306  }
307 }
308 
309 /** Close socket. */
310 void
312 {
313  if (sock_fd != -1) {
314  ::close(sock_fd);
315  sock_fd = -1;
316  }
317 }
318 
319 /** Connect socket.
320  * If called for a stream socket this will connect to the remote address. If
321  * you call this on a datagram socket you will tune in to a specific sender and
322  * receiver.
323  * @param addr_port struct containing address and port to connect to
324  * @exception SocketException thrown if socket cannot connect, check errno for cause
325  */
326 void
327 Socket::connect(const struct ::sockaddr_storage &addr_port)
328 {
329  connect((const struct sockaddr *)&addr_port, sizeof(::sockaddr_storage));
330 }
331 
332 /** Connect socket.
333  * If called for a stream socket this will connect to the remote address. If
334  * you call this on a datagram socket you will tune in to a specific sender and
335  * receiver.
336  * @param addr_port struct containing address and port to connect to
337  * @param struct_size size of addr_port struct
338  * @exception SocketException thrown if socket cannot connect, check errno for cause
339  */
340 void
341 Socket::connect(const struct sockaddr *addr_port, socklen_t struct_size)
342 {
343  if (sock_fd != -1)
344  throw SocketException("Socket already initialized and connected");
345  socket_addr_family_ = addr_port->sa_family;
346 
347  create();
348 
349  if (timeout == 0.f) {
350  if (::connect(sock_fd, addr_port, struct_size) < 0) {
351  throw SocketException(errno, "Could not connect");
352  }
353  } else {
354  struct timeval start, now;
355  gettimeofday(&start, NULL);
356  do {
357  if (::connect(sock_fd, addr_port, struct_size) < 0) {
358  if ((errno != EINPROGRESS) && (errno != EALREADY)) {
359  throw SocketException(errno, "Could not connect");
360  }
361  }
362  gettimeofday(&now, NULL);
363  } while (time_diff_sec(now, start) < timeout);
364  }
365 }
366 
367 /** Connect socket.
368  * If called for a stream socket this will connect to the remote address. If
369  * you call this on a datagram socket you will tune in to a specific sender and
370  * receiver.
371  * @param hostname hostname or textual represenation of IP address to connect to
372  * @param port port to connect to
373  * @exception SocketException thrown if socket cannot connect, check errno for cause
374  */
375 void
376 Socket::connect(const char *hostname, unsigned short int port)
377 {
378  if (sock_fd != -1)
379  throw SocketException("Socket already initialized and connected");
380 
381  struct addrinfo hints, *servinfo, *p;
382  int rv;
383 
384  std::string tried_endpoints;
385 
386  std::string port_s = StringConversions::to_string((unsigned int)port);
387 
388  memset(&hints, 0, sizeof(hints));
389  hints.ai_family = AF_UNSPEC;
390  hints.ai_socktype = socket_type_;
391  if ((rv = getaddrinfo(hostname, port_s.c_str(), &hints, &servinfo)) != 0) {
392  throw SocketException("getaddrinfo for %s:%s failed: %s",
393  hostname,
394  port_s.c_str(),
395  gai_strerror(rv));
396  }
397 
398  for (p = servinfo; p != NULL; p = p->ai_next) {
399  bool failed = false;
400  std::string what;
401  int lerrno = 0;
402  if ((sock_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
403  what = "socket";
404  lerrno = errno;
405  failed = true;
406  }
407 
408  if (!failed) {
409  if (::connect(sock_fd, p->ai_addr, p->ai_addrlen) == -1) {
410  what = "connect";
411  lerrno = errno;
412  ::close(sock_fd);
413  sock_fd = -1;
414  failed = true;
415  }
416  }
417 
418  if (failed) {
419  if (p->ai_family == AF_INET) {
420  char tmp[INET_ADDRSTRLEN];
421  if (inet_ntop(
422  p->ai_family, &((struct sockaddr_in *)p->ai_addr)->sin_addr, tmp, INET_ADDRSTRLEN)
423  != NULL) {
424  tried_endpoints +=
425  std::string(" IPv4:") + tmp + ":" + port_s + "|" + what + "|" + strerror(lerrno);
426  } else {
427  tried_endpoints +=
428  std::string(" IPv4:FAIL") + tmp + ":" + port_s + "|" + what + "|" + strerror(lerrno);
429  }
430  } else if (p->ai_family == AF_INET6) {
431  char tmp[INET6_ADDRSTRLEN];
432  if (inet_ntop(
433  p->ai_family, &((struct sockaddr_in6 *)p->ai_addr)->sin6_addr, tmp, INET6_ADDRSTRLEN)
434  != NULL) {
435  tried_endpoints +=
436  std::string(" IPv6:[") + tmp + "]:" + port_s + "|" + what + "|" + strerror(lerrno);
437  } else {
438  tried_endpoints +=
439  std::string(" IPv6:FAIL") + tmp + ":" + port_s + "|" + what + "|" + strerror(lerrno);
440  }
441  } else {
442  tried_endpoints += std::string(" UNKNOWN_AF:") + port_s;
443  }
444 
445  continue;
446  } else {
447  // Connected succesfully!
448  break;
449  }
450  }
451 
452  freeaddrinfo(servinfo);
453 
454  if (p == NULL || sock_fd == -1) {
455  throw SocketException("Failed to connect to any endpoint (tried:%s)", tried_endpoints.c_str());
456  }
457 }
458 
459 /** Bind socket.
460  * Can only be called on stream sockets.
461  * @param port port to bind
462  * @exception SocketException thrown if socket cannot bind, check errno for cause
463  */
464 void
465 Socket::bind(const unsigned short int port)
466 {
467  if (sock_fd != -1)
468  throw SocketException("Socket already initialized and connected");
469  create();
470 
471  switch (addr_type) {
472  case IPv4: {
473  struct ::sockaddr_in host;
474  memset(&host, 0, sizeof(host));
475 
476  host.sin_family = AF_INET;
477  host.sin_addr.s_addr = INADDR_ANY;
478  host.sin_port = htons(port);
479 
480  int reuse = 1;
481  if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
482  throw SocketException(errno, "Could not set SO_REUSEADDR");
483  }
484 
485  if (::bind(sock_fd, (struct sockaddr *)&host, sizeof(host)) < 0) {
486  throw SocketException(errno, "Could not bind to port");
487  }
488  } break;
489  case IPv6: {
490  struct ::sockaddr_in6 host;
491  memset(&host, 0, sizeof(host));
492 
493  host.sin6_family = AF_INET6;
494  host.sin6_port = htons(port);
495 
496  int on = 1;
497  if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
498  throw SocketException(errno, "Could not set SO_REUSEADDR");
499  }
500  if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) {
501  throw SocketException(errno, "Could not set IPV6_V6ONLY");
502  }
503 
504  if (::bind(sock_fd, (struct sockaddr *)&host, sizeof(host)) < 0) {
505  throw SocketException(errno, "Could not bind to port");
506  }
507  } break;
508  default: throw SocketException("Address type not specified for socket, cannot bind");
509  }
510 }
511 
512 /** Bind socket to a specific address.
513  * @param port port to bind
514  * @param ipaddr textual IP address of a local interface to bind to, must match the address
515  * type passed to the constructor.
516  * @exception SocketException thrown if socket cannot bind, check errno for cause
517  */
518 void
519 Socket::bind(const unsigned short int port, const char *ipaddr)
520 {
521  if (sock_fd != -1)
522  throw SocketException("Socket already initialized and connected");
523  create();
524 
525  switch (addr_type) {
526  case IPv4: {
527  struct ::sockaddr_in host;
528  memset(&host, 0, sizeof(host));
529 
530  host.sin_family = AF_INET;
531  host.sin_port = htons(port);
532 
533  if (inet_pton(AF_INET, ipaddr, &host.sin_addr) <= 0) {
534  throw SocketException("bind(IPv4): failed to parse IP address '%s'", ipaddr);
535  }
536 
537  int reuse = 1;
538  if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
539  throw SocketException(errno, "Could not set SO_REUSEADDR");
540  }
541 
542  if (::bind(sock_fd, (struct sockaddr *)&host, sizeof(host)) < 0) {
543  throw SocketException(errno, "Could not bind to port");
544  }
545  } break;
546  case IPv6: {
547  struct ::sockaddr_in6 host;
548  memset(&host, 0, sizeof(host));
549 
550  host.sin6_family = AF_INET6;
551  host.sin6_port = htons(port);
552 
553  if (inet_pton(AF_INET6, ipaddr, &host.sin6_addr) <= 0) {
554  throw SocketException("bind(IPv6): failed to parse IP address '%s'", ipaddr);
555  }
556 
557  int on = 1;
558  if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
559  throw SocketException(errno, "Could not set SO_REUSEADDR");
560  }
561  if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) {
562  throw SocketException(errno, "Could not set IPV6_V6ONLY");
563  }
564 
565  if (::bind(sock_fd, (struct sockaddr *)&host, sizeof(host)) < 0) {
566  throw SocketException(errno, "Could not bind to port");
567  }
568  } break;
569  default: throw SocketException("Address type not specified for socket, cannot bind");
570  }
571 }
572 
573 /** Listen on socket.
574  * This waits for new connections on a bound socket. The backlog is the maximum
575  * number of connections waiting for being accepted.
576  * @param backlog maximum number of waiting connections
577  * @exception SocketException thrown if socket cannot listen, check errno for cause
578  * @see bind()
579  * @see accept()
580  */
581 void
582 Socket::listen(int backlog)
583 {
584  if (sock_fd == -1) {
585  throw SocketException("Socket not initialized, call bind() or connect()");
586  }
587 
588  if (::listen(sock_fd, backlog)) {
589  throw SocketException(errno, "Cannot listen on socket");
590  }
591 }
592 
593 /** Accept connection.
594  * Accepts a connection waiting in the queue.
595  * @return new socket used to communicate with the remote part
596  * @exception SocketException thrown if socket cannot accept, check errno for cause
597  */
600 {
601  if (sock_fd == -1) {
602  throw SocketException("Socket not initialized, call bind() or connect()");
603  }
604 
605  struct ::sockaddr_in tmp_client_addr;
606  unsigned int tmp_client_addr_len = sizeof(struct ::sockaddr_in);
607 
608  int a_sock_fd = -1;
609 
610  a_sock_fd = ::accept(sock_fd, (sockaddr *)&tmp_client_addr, &tmp_client_addr_len);
611  if (a_sock_fd == -1) {
612  if (errno != EWOULDBLOCK) {
613  throw SocketException(errno, "Could not accept connection");
614  } else {
615  return NULL;
616  }
617  }
618 
619  // Does not work, evaluated at compile time, thus need clone()
620  //typeof_(this) s = new typeof_(*this);
621  //s->timeout = timeout;
622 
623  Socket *s = clone();
624  s->sock_fd = a_sock_fd;
625 
626  if (s->client_addr != NULL) {
627  free(s->client_addr);
628  }
629  /*
630  struct ::sockaddr_in *tmp_client_addr_alloc = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
631  memcpy(tmp_client_addr_alloc, &tmp_client_addr, sizeof(struct ::sockaddr_in));
632  s->client_addr = tmp_client_addr_alloc;
633  s->client_addr_len = tmp_client_addr_len;
634  */
635 
636  return s;
637 }
638 
639 /** Check if data is available.
640  * Use this to check if data is available on the socket for reading.
641  * @return true, if data can be read, false otherwise
642  */
643 bool
645 {
646  if (sock_fd == -1)
647  return false;
648 
649  fd_set rfds;
650  struct timeval tv;
651  int retval = 1;
652 
653  FD_ZERO(&rfds);
654  FD_SET(sock_fd, &rfds);
655  tv.tv_sec = 0;
656  tv.tv_usec = 0;
657 
658  retval = select(sock_fd + 1, &rfds, NULL, NULL, &tv);
659  if (retval < 0) {
660  perror("select() failed");
661  }
662 
663  return (retval > 0);
664 }
665 
666 /** Wait for some event on socket.
667  * @param timeout timeout in miliseconds to wait. A negative value means to
668  * wait forever until an event occurs, zero means just check, don't wait.
669  * @param what what to wait for, a bitwise OR'ed combination of POLL_IN,
670  * POLL_OUT and POLL_PRI.
671  * @return Returns a flag value. Use bit-wise AND with the POLL_* constants
672  * in this class.
673  * @exception InterruptedException thrown, if poll is interrupted by a signal
674  * @exception SocketException thrown for any other error the poll() syscall can cause,
675  * see Exception::errno() for the cause of the error.
676  * @see Socket::POLL_IN
677  * @see Socket::POLL_OUT
678  * @see Socket::POLL_PRI
679  * @see Socket::POLL_RDHUP
680  * @see Socket::POLL_ERR
681  * @see Socket::POLL_HUP
682  * @see Socket::POLL_NVAL
683  */
684 short
685 Socket::poll(int timeout, short what)
686 {
687  if (sock_fd == -1) {
688  return POLL_ERR;
689  }
690 
691  struct pollfd pfd;
692  pfd.fd = sock_fd;
693  pfd.events = what;
694  pfd.revents = 0;
695  if (::poll(&pfd, 1, timeout) == -1) {
696  if (errno == EINTR) {
697  throw InterruptedException();
698  } else {
699  throw SocketException(errno, "poll() failed");
700  }
701  } else {
702  return pfd.revents;
703  }
704 }
705 
706 /** Write to the socket.
707  * Write to the socket. This method can only be used on streams.
708  * @param buf buffer to write
709  * @param count number of bytes to write from buf
710  * @exception SocketException if the data could not be written or if a timeout occured.
711  */
712 void
713 Socket::write(const void *buf, size_t count)
714 {
715  if (sock_fd == -1) {
716  throw SocketException("Socket not initialized, call bind() or connect()");
717  }
718 
719  int retval = 0;
720  unsigned int bytes_written = 0;
721  struct timeval start, now;
722 
723  gettimeofday(&start, NULL);
724 
725  do {
726  retval = ::write(sock_fd, (char *)buf + bytes_written, count - bytes_written);
727  if (retval == -1) {
728  if (errno != EAGAIN) {
729  throw SocketException(errno, "Could not write data");
730  } else {
731  // just to meet loop condition
732  retval = 0;
733  }
734  } else {
735  bytes_written += retval;
736  // reset timeout
737  gettimeofday(&start, NULL);
738  }
739  gettimeofday(&now, NULL);
740  usleep(0);
741  } while ((bytes_written < count) && (time_diff_sec(now, start) < timeout));
742 
743  if (bytes_written < count) {
744  throw SocketException("Write timeout");
745  }
746 }
747 
748 /** Read from socket.
749  * Read from the socket. This method can only be used on streams.
750  * @param buf buffer to write from
751  * @param count length of buffer, number of bytes to write to stream
752  * @param read_all setting this to true causes a call to read() loop until exactly
753  * count bytes have been read, if false it will return after the first successful read
754  * with the number of bytes available then.
755  * @return number of bytes read.
756  * @see write
757  * @exception SocketException thrown for any error during reading
758  */
759 size_t
760 Socket::read(void *buf, size_t count, bool read_all)
761 {
762  if (sock_fd == -1) {
763  throw SocketException("Socket not initialized, call bind() or connect()");
764  }
765 
766  int retval = 0;
767  unsigned int bytes_read = 0;
768 
769  if (timeout > 0) {
770  struct timeval start, now;
771 
772  gettimeofday(&start, NULL);
773 
774  if (read_all) {
775  do {
776  retval = ::read(sock_fd, (char *)buf + bytes_read, count - bytes_read);
777  if (retval == -1) {
778  if (errno != EAGAIN) {
779  throw SocketException(errno, "Could not read data");
780  } else {
781  // just to meet loop condition
782  retval = 0;
783  }
784  } else {
785  bytes_read += retval;
786  // reset timeout
787  gettimeofday(&start, NULL);
788  }
789  gettimeofday(&now, NULL);
790  usleep(0);
791  } while ((bytes_read < count) && (time_diff_sec(now, start) < timeout));
792  } else {
793  do {
794  retval = ::read(sock_fd, (char *)buf, count);
795  if ((retval == -1) && (errno != EAGAIN)) {
796  throw SocketException(errno, "Could not read data");
797  } else {
798  bytes_read = retval;
799  }
800  usleep(0);
801  } while (retval < 0);
802  }
803  } else {
804  if (read_all) {
805  do {
806  retval = ::read(sock_fd, (char *)buf + bytes_read, count - bytes_read);
807  if (retval == -1) {
808  throw SocketException(errno, "Could not read data");
809  } else if (retval == 0) {
810  throw SocketException("Could not read any data");
811  } else {
812  bytes_read += retval;
813  }
814  usleep(0);
815  } while (bytes_read < count);
816  } else {
817  do {
818  retval = ::read(sock_fd, (char *)buf, count);
819  if ((retval == -1) && (errno != EAGAIN)) {
820  throw SocketException(errno, "Could not read data");
821  } else {
822  bytes_read = retval;
823  }
824  usleep(0);
825  } while (retval < 0);
826  }
827  }
828 
829  if (read_all && (bytes_read < count)) {
830  throw SocketException("Read timeout");
831  }
832 
833  return bytes_read;
834 }
835 
836 /** Write to the socket.
837  * Write to the socket. This method can be used on streams or on datagram
838  * sockets which have been tuned to a specific receiver by using connect().
839  * For streams usage of write() is recommended as it is the more intuitive
840  * way to deal with a stream.
841  * @param buf buffer to write
842  * @param buf_len length of buffer, number of bytes to write to stream
843  * @see write
844  */
845 void
846 Socket::send(void *buf, size_t buf_len)
847 {
848  try {
849  write(buf, buf_len);
850  } catch (SocketException &e) {
851  throw;
852  }
853 }
854 
855 /** Read from socket.
856  * Read from the socket. This method can only be used on streams. Usage of
857  * read() is recommended.
858  * @param buf buffer to read data into
859  * @param buf_len length of buffer, number of bytes to read from stream
860  * @return number of bytes read
861  * @exception SocketException thrown if an error occurs or the other side
862  * has closed the connection.
863  */
864 size_t
865 Socket::recv(void *buf, size_t buf_len)
866 {
867  if (sock_fd == -1) {
868  throw SocketException("Socket not initialized, call bind() or connect()");
869  }
870 
871  ssize_t rv;
872  if ((rv = ::recv(sock_fd, buf, buf_len, 0)) == -1) {
873  throw SocketException(errno, "recv() failed");
874  } else if (rv == 0) {
875  throw SocketException("Other side closed the connection");
876  }
877  return rv;
878 }
879 
880 /** Send message.
881  * @param buf buffer with data to send
882  * @param buf_len length of buffer, all data will be send.
883  * @param addr addr to send data to.
884  * @param addr_len length of address
885  */
886 void
887 Socket::send(void *buf, size_t buf_len, const struct sockaddr *addr, socklen_t addr_len)
888 {
889  if (sock_fd == -1) {
890  throw SocketException("Socket not initialized, call bind() or connect()");
891  }
892 
893  int retval = 0;
894  unsigned int bytes_written = 0;
895  struct timeval start, now;
896 
897  gettimeofday(&start, NULL);
898 
899  do {
900  retval =
901  ::sendto(sock_fd, (char *)buf + bytes_written, buf_len - bytes_written, 0, addr, addr_len);
902  if (retval == -1) {
903  if (errno != EAGAIN) {
904  throw SocketException(errno, "Could not read data");
905  } else {
906  // just to meet loop condition
907  retval = 0;
908  }
909  } else {
910  bytes_written += retval;
911  // reset timeout
912  gettimeofday(&start, NULL);
913  }
914  gettimeofday(&now, NULL);
915  usleep(0);
916  } while ((bytes_written < buf_len) && (time_diff_sec(now, start) < timeout));
917 
918  if (bytes_written < buf_len) {
919  throw SocketException("Write timeout");
920  }
921 }
922 
923 /** Receive data.
924  * This will use recvfrom() to read data from the socket and returns the
925  * number of bytes actually read. It will not wait until the requested
926  * number of bytes has been read. Use read() if you need this.
927  * @param buf buffer that read data shall be stored in.
928  * @param buf_len length of buffer and number of bytes to be read
929  * @param addr return parameter, contains address of sender
930  * @param addr_len initially has to contain size of address, on return
931  * contains the actual bytes used.
932  * @return number of bytes received
933  */
934 size_t
935 Socket::recv(void *buf, size_t buf_len, struct sockaddr *addr, socklen_t *addr_len)
936 {
937  if (sock_fd == -1) {
938  throw SocketException("Socket not initialized, call bind() or connect()");
939  }
940 
941  ssize_t rv = 0;
942 
943  if ((rv = ::recvfrom(sock_fd, buf, buf_len, 0, addr, addr_len)) == -1) {
944  throw SocketException(errno, "recvfrom() failed");
945  } else if (rv == 0) {
946  throw SocketException("Peer has closed the connection");
947  } else {
948  return rv;
949  }
950 }
951 
952 /** Is socket listening for connections?
953  * @return true if socket is listening for incoming connections, false otherwise
954  */
955 bool
957 {
958  if (sock_fd == -1)
959  return false;
960 
961  int i = 0;
962  unsigned int len = sizeof(i);
963  if (getsockopt(sock_fd, SOL_SOCKET, SO_ACCEPTCONN, &i, &len) == -1) {
964  throw SocketException(errno, "Socket::listening(): getsockopt failed");
965  }
966  return (i == 1);
967 }
968 
969 /** Maximum Transfer Unit (MTU) of socket.
970  * Note that this can only be retrieved of connected sockets!
971  * @return MTU in bytes
972  */
973 unsigned int
974 Socket::mtu()
975 {
976  if (sock_fd == -1) {
977  throw SocketException("Socket not initialized, call bind() or connect()");
978  }
979 
980  int m = 0;
981 
982 #ifdef __linux__
983  unsigned int len = sizeof(m);
984  if (getsockopt(sock_fd, IPPROTO_IP, IP_MTU, &m, &len) == -1) {
985  throw SocketException(errno, "Socket::mtu(): getsockopt failed");
986  }
987 
988  if (m < 0) {
989  throw SocketException("MTU < 0");
990  }
991 #elif defined __FreeBSD__
992  struct ifreq ifr;
993  if (ioctl(sock_fd, SIOCGIFMTU, &ifr) != -1)
994  m = ifr.ifr_mtu;
995 #endif
996 
997  return m;
998 }
999 
1000 } // end namespace fawkes
fawkes::Socket::IPv6
IPv6.
Definition: socket.h:82
fawkes::Socket::bind
virtual void bind(const unsigned short int port)
Bind socket.
Definition: socket.cpp:464
fawkes::SocketException
Definition: socket.h:60
fawkes::Socket::sock_fd
int sock_fd
Definition: socket.h:141
fawkes::Exception::append_va
void append_va(const char *format, va_list va)
Append messages to the message list.
Definition: exception.cpp:352
fawkes::Socket::POLL_HUP
static const short POLL_HUP
Hang up.
Definition: socket.h:75
fawkes::Socket::~Socket
virtual ~Socket()
Destructor.
Definition: socket.cpp:299
fawkes::Socket::client_addr_len
unsigned int client_addr_len
Definition: socket.h:144
fawkes::Socket::UDP
UDP datagram socket.
Definition: socket.h:88
fawkes::Socket::IPv4
IPv4.
Definition: socket.h:81
fawkes::InterruptedException
Definition: system.h:42
fawkes::Socket::POLL_RDHUP
static const short POLL_RDHUP
Stream socket peer closed connection, or shut down writing half of connection.
Definition: socket.h:73
fawkes::Socket::connect
virtual void connect(const char *hostname, const unsigned short int port)
Connect socket.
Definition: socket.cpp:375
fawkes::Socket::TCP
TCP stream socket.
Definition: socket.h:87
fawkes::Socket::POLL_ERR
static const short POLL_ERR
Error condition.
Definition: socket.h:74
fawkes::Socket::close
virtual void close()
Close socket.
Definition: socket.cpp:310
fawkes::Socket::write
virtual void write(const void *buf, size_t count)
Write to the socket.
Definition: socket.cpp:712
fawkes::time_diff_sec
double time_diff_sec(const timeval &a, const timeval &b)
Calculate time difference of two time structs.
Definition: time.h:45
fawkes::StringConversions::to_string
static std::string to_string(unsigned int i)
Convert unsigned int value to a string.
Definition: string_conversions.cpp:72
fawkes::SocketException::SocketException
SocketException(int _errno, const char *msg)
Constructor.
Definition: socket.cpp:86
fawkes::Socket::poll
virtual short poll(int timeout=-1, short what=POLL_IN|POLL_HUP|POLL_PRI|POLL_RDHUP)
Wait for some event on socket.
Definition: socket.cpp:684
fawkes::Socket::SocketType
SocketType
Socket type.
Definition: socket.h:86
fawkes::Socket::recv
virtual size_t recv(void *buf, size_t buf_len)
Read from socket.
Definition: socket.cpp:864
fawkes::Socket::operator=
Socket & operator=(Socket &socket)
Copy constructor.
Definition: socket.cpp:249
fawkes::Socket::listening
virtual bool listening()
Is socket listening for connections?
Definition: socket.cpp:955
fawkes::Socket::POLL_NVAL
static const short POLL_NVAL
Invalid request.
Definition: socket.h:76
fawkes::Socket::mtu
virtual unsigned int mtu()
Maximum Transfer Unit (MTU) of socket.
Definition: socket.cpp:973
fawkes::UnknownTypeException
Definition: software.h:53
fawkes::Socket::POLL_PRI
static const short POLL_PRI
There is urgent data to read (e.g., out-of-band data on TCP socket; pseudo-terminal master in packet ...
Definition: socket.h:72
fawkes
fawkes::Socket::send
virtual void send(void *buf, size_t buf_len)
Write to the socket.
Definition: socket.cpp:845
fawkes::Socket::Socket
Socket()
Constructor.
Definition: socket.cpp:210
fawkes::Socket::listen
virtual void listen(int backlog=1)
Listen on socket.
Definition: socket.cpp:581
fawkes::Socket::POLL_IN
static const short POLL_IN
Data can be read.
Definition: socket.h:70
fawkes::Socket::available
virtual bool available()
Check if data is available.
Definition: socket.cpp:643
fawkes::Socket::timeout
float timeout
Definition: socket.h:142
fawkes::Socket::POLL_OUT
static const short POLL_OUT
Writing will not block.
Definition: socket.h:71
fawkes::Socket::clone
virtual Socket * clone()=0
Clone socket.
fawkes::Socket::accept
virtual Socket * accept()
Accept connection.
Definition: socket.cpp:598
fawkes::Socket::read
virtual size_t read(void *buf, size_t count, bool read_all=true)
Read from socket.
Definition: socket.cpp:759
fawkes::Socket::client_addr
struct ::sockaddr_storage * client_addr
Definition: socket.h:143
fawkes::Socket::AddrType
AddrType
Address type specification.
Definition: socket.h:79
fawkes::Socket
Definition: socket.h:67
fawkes::Socket::addr_type
AddrType addr_type
Definition: socket.h:140
fawkes::Exception
Definition: exception.h:39