Fawkes API Fawkes Development Version
|
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