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