Fawkes API  Fawkes Development Version
socket.cpp
00001 
00002 /***************************************************************************
00003  *  socket.h - Fawkes socket base class
00004  *
00005  *  Created: Thu Nov 09 14:30:56 2006
00006  *  Copyright  2006  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <netcomm/socket/socket.h>
00025 
00026 #include <core/exceptions/system.h>
00027 #include <utils/time/time.h>
00028 
00029 #ifndef _GNU_SOURCE
00030 #define _GNU_SOURCE
00031 #endif
00032 
00033 #include <errno.h>
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <netdb.h>
00037 #include <unistd.h>
00038 #include <fcntl.h>
00039 #include <string.h>
00040 #include <stdlib.h>
00041 // include <linux/in.h>
00042 #include <netinet/in.h>
00043 #include <netinet/in_systm.h>
00044 #include <netinet/ip.h> 
00045 #include <poll.h>
00046 
00047 #include <cstdio>
00048 
00049 // Until this is integrated from linux/in.h to netinet/in.h
00050 #ifdef __linux__
00051 #  ifndef IP_MTU
00052 #    define IP_MTU 14
00053 #  endif
00054 #endif  // __linux__
00055 #ifdef __FreeBSD__
00056 #  include <net/if.h>
00057 #  include <sys/ioctl.h>
00058 #endif
00059 
00060 namespace fawkes {
00061 
00062 /** @class SocketException netcomm/socket/socket.h
00063  * Socket exception.
00064  * Thrown if an exception occurs in a socket. If the error was caused by
00065  * a system call that sets errno this is given to the exception.
00066  * @ingroup NetComm
00067  */
00068 
00069 /** Constructor.
00070  * @param msg reason that caused the exception.
00071  */
00072 SocketException::SocketException(const char *msg)
00073   : Exception("%s", msg)
00074 {
00075 }
00076 
00077 
00078 /** Constructor.
00079  * @param msg reason of the exception
00080  * @param _errno error number (errno returned by a syscall)
00081  */
00082 SocketException::SocketException(const char *msg, int _errno)
00083   : Exception(_errno, "%s", msg)
00084 {
00085 }
00086 
00087 
00088 /** @class Socket netcomm/socket/socket.h
00089  * Socket base class.
00090  * This is the base class for all sockets. You cannot use it directly
00091  * but you have to use one of the derivatives like StreamSocket or
00092  * DatagramSocket.
00093  * @ingroup NetComm
00094  * @author Tim Niemueller
00095  */
00096 
00097 /** @var Socket::sock_fd
00098  * Socket file descriptor.
00099  */
00100 /** @var Socket::timeout
00101  * Timeout in seconds for various operations. If the timeout is non-zero
00102  * the socket is initialized non-blocking and operations are aborted after
00103  * timeout seconds have passed.
00104  */
00105 /** @var Socket::client_addr
00106  * Client address, set if connected.
00107  */
00108 /** @var Socket::client_addr_len
00109  * length in bytes of client address.
00110  */
00111 
00112 
00113 /** Data can be read. */
00114 const short Socket::POLL_IN    = POLLIN;
00115 
00116 /** Writing will not block. */
00117 const short Socket::POLL_OUT   = POLLOUT;
00118 
00119 /** There is urgent data to read (e.g., out-of-band data on TCP socket;
00120  * pseudo-terminal master in packet mode has seen state  change  in slave).
00121  */
00122 const short Socket::POLL_PRI   = POLLPRI;
00123 
00124 /** Stream  socket  peer closed connection, or shut down writing half of
00125  * connection.  The _GNU_SOURCE feature test macro must be defined
00126  * in order to obtain this definition (since Linux 2.6.17).
00127  */
00128 #ifdef POLLRDHUP
00129 const short Socket::POLL_RDHUP = POLLRDHUP;
00130 #else
00131 const short Socket::POLL_RDHUP = 0;
00132 #endif
00133 
00134 /** Error condition. */
00135 const short Socket::POLL_ERR   = POLLERR;
00136 
00137 /** Hang up. */
00138 const short Socket::POLL_HUP   = POLLHUP;
00139 
00140 /** Invalid request. */
00141 const short Socket::POLL_NVAL  = POLLNVAL;
00142 
00143 
00144 /**  Constructor similar to syscall.
00145  * This creates a new socket. This is a plain pass-through constructor
00146  * to the socket() syscall. In most cases this should only be used by
00147  * a derivate.
00148  * @param domain communication domain, selects the protocol
00149  * @param type type of the sockets which specifies communication semantics
00150  * @param protocol protocol to use, most types support only one and protocol
00151  * should be 0
00152  * @param timeout See Socket::timeout.
00153  * @exception SocketException thrown if socket cannot be opened, check errno for cause
00154  */
00155 Socket::Socket(int domain, int type, int protocol, float timeout)
00156 {
00157   this->timeout = timeout;
00158   if ( (sock_fd = socket(domain, type, protocol)) == -1 ) {
00159     throw SocketException("Could not open socket", errno);
00160   }
00161 
00162   if (timeout > 0.f) {
00163     // set to non-blocking
00164     if ( fcntl(sock_fd, F_SETFL, O_NONBLOCK) == -1 ) {
00165       throw SocketException("Could not set socket to non-blocking", errno);
00166     }
00167   }
00168 
00169   client_addr = NULL;
00170   client_addr_len = 0;
00171 }
00172 
00173 
00174 /** Constructor.
00175  * Plain constructor. The socket will not be opened. This may only be called by
00176  * sub-classes and you must ensure that the socket file descriptor is initialized
00177  * properly.
00178  */
00179 Socket::Socket()
00180 {
00181   client_addr = NULL;
00182   client_addr_len = 0;
00183   timeout = 0.f;
00184   sock_fd = -1;
00185 }
00186 
00187 
00188 /** Copy constructor.
00189  * @param socket socket to copy
00190  */
00191 Socket::Socket(Socket &socket)
00192 {
00193   if ( socket.client_addr != NULL ) {
00194     client_addr = (struct ::sockaddr_in *)malloc(socket.client_addr_len);
00195     client_addr_len = socket.client_addr_len;
00196     memcpy(client_addr, socket.client_addr, client_addr_len);
00197   } else {
00198     client_addr = NULL;
00199     client_addr_len = 0;
00200   }    
00201   timeout = socket.timeout;
00202   sock_fd = socket.sock_fd;
00203 }
00204 
00205 
00206 /** Destructor. */
00207 Socket::~Socket()
00208 {
00209   close();
00210   if ( client_addr != NULL ) {
00211     free(client_addr);
00212     client_addr = NULL;
00213   }
00214 }
00215 
00216 
00217 /** Close socket. */
00218 void
00219 Socket::close()
00220 {
00221   if ( sock_fd != -1 ) {
00222     ::close(sock_fd);
00223     sock_fd = -1;
00224   }
00225 }
00226 
00227 
00228 /** Connect socket.
00229  * If called for a stream socket this will connect to the remote address. If
00230  * you call this on a datagram socket you will tune in to a specific sender and
00231  * receiver.
00232  * @param addr_port struct containing address and port to connect to
00233  * @param struct_size size of addr_port struct
00234  * @exception SocketException thrown if socket cannot connect, check errno for cause
00235  */
00236 void
00237 Socket::connect(struct sockaddr *addr_port, unsigned int struct_size)
00238 {
00239   if ( sock_fd == -1 )  throw SocketException("Trying to connect invalid socket");
00240 
00241   if (timeout == 0.f) {
00242     if ( ::connect(sock_fd, addr_port, struct_size) < 0 ) {
00243       throw SocketException("Could not connect", errno);
00244     }
00245   } else {
00246     struct timeval start, now;
00247     gettimeofday(&start, NULL);
00248     do {
00249       if ( ::connect(sock_fd, addr_port, struct_size) < 0 ) {
00250         if ( (errno != EINPROGRESS) &&
00251              (errno != EALREADY) ) {
00252           throw SocketException("Could not connect", errno);
00253         }
00254       }
00255       gettimeofday(&now, NULL);
00256     } while (time_diff_sec(now, start) < timeout);
00257   }
00258 }
00259 
00260 
00261 /** Connect socket.
00262  * If called for a stream socket this will connect to the remote address. If
00263  * you call this on a datagram socket you will tune in to a specific sender and
00264  * receiver.
00265  * @param hostname hostname or textual represenation of IP address to connect to
00266  * @param port port to connect to
00267  * @exception SocketException thrown if socket cannot connect, check errno for cause
00268  */
00269 void
00270 Socket::connect(const char *hostname, unsigned short int port)
00271 {
00272   if ( sock_fd == -1 )  throw SocketException("Trying to connect invalid socket");
00273 
00274   struct hostent* h;
00275   struct ::sockaddr_in host;
00276 
00277 
00278   h = gethostbyname(hostname);
00279   if ( ! h ) {
00280     throw SocketException("Cannot lookup hostname", h_errno);
00281   }
00282 
00283   memset(&host, 0, sizeof(host));
00284   host.sin_family = AF_INET;
00285   memcpy((char *)&host.sin_addr.s_addr, h->h_addr, h->h_length);
00286   host.sin_port = htons(port);
00287 
00288   connect((struct sockaddr *)&host, sizeof(host));
00289 }
00290 
00291 
00292 /** Bind socket.
00293  * Can only be called on stream sockets.
00294  * @param port port to bind
00295  * @exception SocketException thrown if socket cannot bind, check errno for cause
00296  */
00297 void
00298 Socket::bind(const unsigned short int port)
00299 {
00300   struct ::sockaddr_in host;
00301 
00302   host.sin_family = AF_INET;
00303   host.sin_addr.s_addr = INADDR_ANY;
00304   host.sin_port = htons(port);
00305 
00306   int reuse = 1;
00307   if ( setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
00308     throw SocketException("Could not set SO_REUSEADDR", errno);
00309   }
00310 
00311   if (::bind(sock_fd, (struct sockaddr *) &host, sizeof(host)) < 0) {
00312     throw SocketException("Could not bind to port", errno);
00313   }
00314 }
00315 
00316 
00317 /** Bind socket to a specific address.
00318  * @param port port to bind
00319  * @param hostname hostname or textual IP address of a local interface to bind to.
00320  * @exception SocketException thrown if socket cannot bind, check errno for cause
00321  */
00322 void
00323 Socket::bind(const unsigned short int port, const char *hostname)
00324 {
00325   struct hostent* h;
00326   struct ::sockaddr_in host;
00327 
00328   h = gethostbyname(hostname);
00329   if ( ! h ) {
00330     throw SocketException("Cannot lookup hostname", h_errno);
00331   }
00332 
00333   memset(&host, 0, sizeof(host));
00334   host.sin_family = AF_INET;
00335   memcpy(&host.sin_addr.s_addr, h->h_addr, h->h_length);
00336   host.sin_port = htons(port);
00337 
00338   host.sin_family = AF_INET;
00339   host.sin_addr.s_addr = INADDR_ANY;
00340   host.sin_port = htons(port);
00341 
00342   if (::bind(sock_fd, (struct sockaddr *) &host, sizeof(host)) < 0) {
00343     throw SocketException("Could not bind to port", errno);
00344   }
00345 }
00346 
00347 
00348 /** Listen on socket.
00349  * This waits for new connections on a bound socket. The backlog is the maximum
00350  * number of connections waiting for being accepted.
00351  * @param backlog maximum number of waiting connections
00352  * @exception SocketException thrown if socket cannot listen, check errno for cause
00353  * @see bind()
00354  * @see accept()
00355  */
00356 void
00357 Socket::listen(int backlog)
00358 {
00359   if ( ::listen(sock_fd, backlog) ) {
00360     throw SocketException("Cannot listen on socket", errno);
00361   }
00362 }
00363 
00364 
00365 /** Accept connection.
00366  * Accepts a connection waiting in the queue.
00367  * @return new socket used to communicate with the remote part
00368  * @exception SocketException thrown if socket cannot accept, check errno for cause
00369  */
00370 Socket *
00371 Socket::accept()
00372 {
00373   struct ::sockaddr_in  tmp_client_addr;
00374   unsigned int  tmp_client_addr_len = sizeof(struct ::sockaddr_in);
00375 
00376   int a_sock_fd = -1;
00377 
00378   a_sock_fd = ::accept(sock_fd, (sockaddr *)&tmp_client_addr, &tmp_client_addr_len);
00379   if ( a_sock_fd == -1 ) {
00380     if (errno != EWOULDBLOCK) {
00381       throw SocketException("Could not accept connection", errno);
00382     } else {
00383       return NULL;
00384     }
00385   }
00386 
00387   // Does not work, evaluated at compile time, thus need clone()
00388   //__typeof(this) s = new __typeof(*this);
00389   //s->timeout = timeout;
00390 
00391   Socket *s = clone();
00392   s->sock_fd = a_sock_fd;
00393 
00394   if ( s->client_addr != NULL ) {
00395     free(s->client_addr);
00396   }
00397   struct ::sockaddr_in  *tmp_client_addr_alloc = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
00398   memcpy(tmp_client_addr_alloc, &tmp_client_addr, sizeof(struct ::sockaddr_in));
00399   s->client_addr = tmp_client_addr_alloc;
00400   s->client_addr_len = tmp_client_addr_len;
00401 
00402   return s;
00403 }
00404 
00405 
00406 /** Check if data is available.
00407  * Use this to check if data is available on the socket for reading.
00408  * @return true, if data can be read, false otherwise
00409  */
00410 bool
00411 Socket::available()
00412 {
00413   if (sock_fd == -1) return false;
00414 
00415   fd_set rfds;
00416   struct timeval tv;
00417   int retval = 1;
00418 
00419   FD_ZERO(&rfds);
00420   FD_SET(sock_fd, &rfds);
00421   tv.tv_sec = 0;
00422   tv.tv_usec = 0;
00423 
00424   retval = select(sock_fd + 1, &rfds, NULL, NULL, &tv);
00425   if ( retval < 0 ) {
00426     perror("select() failed");
00427   }
00428 
00429   return (retval > 0);
00430 }
00431 
00432 
00433 /** Wait for some event on socket.
00434  * @param timeout timeout in miliseconds to wait. A negative value means to
00435  * wait forever until an event occurs, zero means just check, don't wait.
00436  * @param what what to wait for, a bitwise OR'ed combination of POLL_IN,
00437  * POLL_OUT and POLL_PRI.
00438  * @return Returns a flag value. Use bit-wise AND with the POLL_* constants
00439  * in this class.
00440  * @exception InterruptedException thrown, if poll is interrupted by a signal
00441  * @exception SocketException thrown for any other error the poll() syscall can cause,
00442  * see Exception::errno() for the cause of the error.
00443  * @see Socket::POLL_IN
00444  * @see Socket::POLL_OUT
00445  * @see Socket::POLL_PRI
00446  * @see Socket::POLL_RDHUP
00447  * @see Socket::POLL_ERR
00448  * @see Socket::POLL_HUP
00449  * @see Socket::POLL_NVAL
00450  */
00451 short
00452 Socket::poll(int timeout, short what)
00453 {
00454   if ( sock_fd == -1 ) {
00455     return POLL_ERR;
00456   }
00457 
00458   struct pollfd pfd;
00459   pfd.fd = sock_fd;
00460   pfd.events = what;
00461   pfd.revents = 0;
00462   if ( ::poll(&pfd, 1, timeout) == -1 ) {
00463     if ( errno == EINTR ) {
00464       throw InterruptedException();
00465     } else {
00466       throw SocketException("poll() failed", errno);
00467     }
00468   } else {
00469     return pfd.revents;
00470   }
00471 }
00472 
00473 
00474 /** Write to the socket.
00475  * Write to the socket. This method can only be used on streams.
00476  * @param buf buffer to write
00477  * @param count number of bytes to write from buf
00478  * @exception SocketException if the data could not be written or if a timeout occured.
00479  */
00480 void
00481 Socket::write(const void *buf, size_t count)
00482 {
00483   int retval = 0;
00484   unsigned int bytes_written = 0;
00485   struct timeval start, now;
00486 
00487   gettimeofday(&start, NULL);
00488 
00489   do {
00490     retval = ::write(sock_fd, (char *)buf + bytes_written, count - bytes_written);
00491     if (retval == -1) {
00492       if (errno != EAGAIN) {
00493         throw SocketException("Could not write data", errno);
00494       } else {
00495         // just to meet loop condition
00496         retval = 0;
00497       }
00498     } else {
00499       bytes_written += retval;
00500       // reset timeout
00501       gettimeofday(&start, NULL);
00502     }
00503     gettimeofday(&now, NULL);
00504     usleep(0);
00505   } while ((bytes_written < count) && (time_diff_sec(now, start) < timeout) );
00506 
00507   if ( bytes_written < count) {
00508     throw SocketException("Write timeout");
00509   }
00510 }
00511 
00512 
00513 /** Read from socket.
00514  * Read from the socket. This method can only be used on streams.
00515  * @param buf buffer to write from
00516  * @param count length of buffer, number of bytes to write to stream
00517  * @param read_all setting this to true causes a call to read() loop until exactly
00518  * count bytes have been read, if false it will return after the first successful read
00519  * with the number of bytes available then.
00520  * @return number of bytes read.
00521  * @see write
00522  * @exception SocketException thrown for any error during reading
00523  */
00524 size_t
00525 Socket::read(void *buf, size_t count, bool read_all)
00526 {
00527   int retval = 0;
00528   unsigned int bytes_read = 0;
00529 
00530   if ( timeout > 0 ) {
00531     struct timeval start, now;
00532 
00533     gettimeofday(&start, NULL);
00534 
00535     if ( read_all ) {
00536       do {
00537         retval = ::read(sock_fd, (char *)buf + bytes_read, count - bytes_read);
00538         if (retval == -1) {
00539           if (errno != EAGAIN) {
00540             throw SocketException("Could not read data", errno);
00541           } else {
00542             // just to meet loop condition
00543             retval = 0;
00544           }
00545         } else {
00546           bytes_read += retval;
00547           // reset timeout
00548           gettimeofday(&start, NULL);
00549         }
00550         gettimeofday(&now, NULL);
00551         usleep(0);
00552       } while ((bytes_read < count) && (time_diff_sec(now, start) < timeout) );
00553     } else {
00554       do {
00555         retval = ::read(sock_fd, (char *)buf, count);
00556         if ( (retval == -1) && (errno != EAGAIN) ) {
00557           throw SocketException("Could not read data", errno);
00558         } else {
00559           bytes_read = retval;
00560         }
00561         usleep(0);
00562       } while (retval < 0);
00563     }
00564   } else {
00565     if ( read_all ) {
00566       do {
00567         retval = ::read(sock_fd, (char *)buf + bytes_read, count - bytes_read);
00568         if (retval == -1) {
00569           throw SocketException("Could not read data", errno);
00570         } else if (retval == 0) {
00571           throw SocketException("Could not read any data");
00572         } else {
00573           bytes_read += retval;
00574         }
00575         usleep(0);
00576       } while (bytes_read < count);
00577     } else {
00578       do {
00579         retval = ::read(sock_fd, (char *)buf, count);
00580         if ( (retval == -1) && (errno != EAGAIN) ) {
00581           throw SocketException("Could not read data", errno);
00582         } else {
00583           bytes_read = retval;
00584         }
00585         usleep(0);
00586       } while (retval < 0);
00587     }
00588   }
00589 
00590   if ( read_all && (bytes_read < count)) {
00591     throw SocketException("Read timeout");
00592   }
00593 
00594   return bytes_read;
00595 }
00596 
00597 
00598 /** Write to the socket.
00599  * Write to the socket. This method can be used on streams or on datagram
00600  * sockets which have been tuned to a specific receiver by using connect().
00601  * For streams usage of write() is recommended as it is the more intuitive
00602  * way to deal with a stream.
00603  * @param buf buffer to write
00604  * @param buf_len length of buffer, number of bytes to write to stream
00605  * @see write
00606  */
00607 void
00608 Socket::send(void *buf, size_t buf_len)
00609 {
00610   try {
00611     write(buf,  buf_len);
00612   } catch (SocketException &e) {
00613     throw;
00614   }
00615 }
00616 
00617 
00618 /** Read from socket.
00619  * Read from the socket. This method can only be used on streams. Usage of
00620  * read() is recommended.
00621  * @param buf buffer to read data into
00622  * @param buf_len length of buffer, number of bytes to read from stream
00623  * @return number of bytes read
00624  * @exception SocketException thrown if an error occurs or the other side
00625  * has closed the connection.
00626  */
00627 size_t
00628 Socket::recv(void *buf, size_t buf_len)
00629 {
00630   ssize_t rv;
00631   if ( (rv = ::recv(sock_fd, buf, buf_len, 0)) == -1 ) {
00632     throw SocketException("recv() failed", errno);
00633   } else if ( rv == 0 ) {
00634     throw SocketException("Other side closed the connection");
00635   }
00636   return rv;
00637 }
00638 
00639 
00640 /** Send message.
00641  * @param buf buffer with data to send
00642  * @param buf_len length of buffer, all data will be send.
00643  * @param addr addr to send data to.
00644  * @param addr_len length of address
00645  */
00646 void
00647 Socket::send(void *buf, size_t buf_len,
00648              const struct sockaddr *addr, socklen_t addr_len)
00649 {
00650   int retval = 0;
00651   unsigned int bytes_written = 0;
00652   struct timeval start, now;
00653 
00654   gettimeofday(&start, NULL);
00655 
00656   do {
00657     retval = ::sendto(sock_fd, (char *)buf + bytes_written, buf_len - bytes_written, 0,
00658                       addr, addr_len);
00659     if (retval == -1) {
00660       if (errno != EAGAIN) {
00661         throw SocketException("Could not read data", errno);
00662       } else {
00663         // just to meet loop condition
00664         retval = 0;
00665       }
00666     } else {
00667       bytes_written += retval;
00668       // reset timeout
00669       gettimeofday(&start, NULL);
00670     }
00671     gettimeofday(&now, NULL);
00672     usleep(0);
00673   } while ((bytes_written < buf_len) && (time_diff_sec(now, start) < timeout) );
00674 
00675   if ( bytes_written < buf_len) {
00676     throw SocketException("Write timeout");
00677   }
00678 }
00679 
00680 
00681 /** Receive data.
00682  * This will use recvfrom() to read data from the socket and returns the
00683  * number of bytes actually read. It will not wait until the requested
00684  * number of bytes has been read. Use read() if you need this.
00685  * @param buf buffer that read data shall be stored in.
00686  * @param buf_len length of buffer and number of bytes to be read
00687  * @param addr return parameter, contains address of sender
00688  * @param addr_len initially has to contain size of address, on return
00689  * contains the actual bytes used.
00690  * @return number of bytes received
00691  */
00692 size_t
00693 Socket::recv(void *buf, size_t buf_len,
00694              struct sockaddr *addr, socklen_t *addr_len)
00695 {
00696   ssize_t rv = 0;
00697 
00698   if ( (rv = ::recvfrom(sock_fd, buf, buf_len, 0, addr, addr_len)) == -1) {
00699     throw SocketException("recvfrom() failed", errno);
00700   } else if ( rv == 0 ) {
00701     throw SocketException("Peer has closed the connection");
00702   } else {
00703     return rv;
00704   }
00705 }
00706 
00707 
00708 /** Is socket listening for connections?
00709  * @return true if socket is listening for incoming connections, false otherwise
00710  */
00711 bool
00712 Socket::listening()
00713 {
00714   if ( sock_fd == -1 ) return false;
00715 
00716   int i = 0;
00717   unsigned int len = sizeof(i);
00718   if ( getsockopt(sock_fd, SOL_SOCKET, SO_ACCEPTCONN, &i, &len) == -1 ) {
00719     throw SocketException("Socket::listening(): getsockopt failed", errno);
00720   }
00721   return ( i == 1 );
00722 }
00723 
00724 
00725 /** Maximum Transfer Unit (MTU) of socket.
00726  * Note that this can only be retrieved of connected sockets!
00727  * @return MTU in bytes
00728  */
00729 unsigned int
00730 Socket::mtu()
00731 {
00732   int m = 0;
00733 
00734   if ( sock_fd == -1 ) throw SocketException("Cannot get MTU of disconnected socket");
00735 
00736 #ifdef __linux__
00737   unsigned int len = sizeof(m);
00738   if ( getsockopt(sock_fd, IPPROTO_IP, IP_MTU, &m, &len) == -1 ) {
00739     throw SocketException("Socket::mtu(): getsockopt failed", errno);
00740   }
00741 
00742   if ( m < 0 ) {
00743     throw SocketException("MTU < 0");
00744   }
00745 #elif defined __FreeBSD__
00746   struct ifreq ifr;
00747   if (ioctl(sock_fd, SIOCGIFMTU, &ifr) != -1)
00748     m = ifr.ifr_mtu;
00749 #endif
00750 
00751   return m;
00752 }
00753 
00754 } // end namespace fawkes