/src/libs/netcomm/socket/socket.cpp

https://gitlab.com/F34140r/rockin-refbox · C++ · 770 lines · 430 code · 112 blank · 228 comment · 126 complexity · 100b76931decc3dfd0660e610883436a MD5 · raw file

  1. /***************************************************************************
  2. * socket.h - Fawkes socket base class
  3. *
  4. * Created: Thu Nov 09 14:30:56 2006
  5. * Copyright 2006 Tim Niemueller [www.niemueller.de]
  6. *
  7. ****************************************************************************/
  8. /* This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version. A runtime exception applies to
  12. * this software (see LICENSE.GPL_WRE file mentioned below for details).
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Library General Public License for more details.
  18. *
  19. * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
  20. */
  21. #include <netcomm/socket/socket.h>
  22. #include <core/exceptions/system.h>
  23. #ifndef _GNU_SOURCE
  24. #define _GNU_SOURCE
  25. #endif
  26. #include <errno.h>
  27. #include <sys/types.h>
  28. #include <sys/socket.h>
  29. #include <sys/time.h>
  30. #include <netdb.h>
  31. #include <unistd.h>
  32. #include <fcntl.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. // include <linux/in.h>
  36. #include <netinet/in.h>
  37. #include <netinet/in_systm.h>
  38. #include <netinet/ip.h>
  39. #include <poll.h>
  40. #include <cstdio>
  41. // Until this is integrated from linux/in.h to netinet/in.h
  42. #ifdef __linux__
  43. # ifndef IP_MTU
  44. # define IP_MTU 14
  45. # endif
  46. #endif // __linux__
  47. #ifdef __FreeBSD__
  48. # include <net/if.h>
  49. # include <sys/ioctl.h>
  50. #endif
  51. namespace fawkes {
  52. /** Calculate time difference of two time structs.
  53. * The calculated time is t = a - b, where t is a represented as the number of
  54. * seconds in a single precision float.
  55. * @param a time to subtract from
  56. * @param b time to subtract
  57. * @return a - b
  58. */
  59. inline double
  60. time_diff_sec(const timeval &a, const timeval &b)
  61. {
  62. //double required if we do not want to loose the usecs
  63. double res = a.tv_sec - b.tv_sec + (a.tv_usec - b.tv_usec) / 1000000.0;
  64. return res;
  65. }
  66. /** @class SocketException netcomm/socket/socket.h
  67. * Socket exception.
  68. * Thrown if an exception occurs in a socket. If the error was caused by
  69. * a system call that sets errno this is given to the exception.
  70. * @ingroup NetComm
  71. */
  72. /** Constructor.
  73. * @param msg reason that caused the exception.
  74. */
  75. SocketException::SocketException(const char *msg)
  76. : Exception("%s", msg)
  77. {
  78. }
  79. /** Constructor.
  80. * @param msg reason of the exception
  81. * @param _errno error number (errno returned by a syscall)
  82. */
  83. SocketException::SocketException(const char *msg, int _errno)
  84. : Exception(_errno, "%s", msg)
  85. {
  86. }
  87. /** @class Socket netcomm/socket/socket.h
  88. * Socket base class.
  89. * This is the base class for all sockets. You cannot use it directly
  90. * but you have to use one of the derivatives like StreamSocket or
  91. * DatagramSocket.
  92. * @ingroup NetComm
  93. * @author Tim Niemueller
  94. */
  95. /** @var Socket::sock_fd
  96. * Socket file descriptor.
  97. */
  98. /** @var Socket::timeout
  99. * Timeout in seconds for various operations. If the timeout is non-zero
  100. * the socket is initialized non-blocking and operations are aborted after
  101. * timeout seconds have passed.
  102. */
  103. /** @var Socket::client_addr
  104. * Client address, set if connected.
  105. */
  106. /** @var Socket::client_addr_len
  107. * length in bytes of client address.
  108. */
  109. /** Data can be read. */
  110. const short Socket::POLL_IN = POLLIN;
  111. /** Writing will not block. */
  112. const short Socket::POLL_OUT = POLLOUT;
  113. /** There is urgent data to read (e.g., out-of-band data on TCP socket;
  114. * pseudo-terminal master in packet mode has seen state change in slave).
  115. */
  116. const short Socket::POLL_PRI = POLLPRI;
  117. /** Stream socket peer closed connection, or shut down writing half of
  118. * connection. The _GNU_SOURCE feature test macro must be defined
  119. * in order to obtain this definition (since Linux 2.6.17).
  120. */
  121. #ifdef POLLRDHUP
  122. const short Socket::POLL_RDHUP = POLLRDHUP;
  123. #else
  124. const short Socket::POLL_RDHUP = 0;
  125. #endif
  126. /** Error condition. */
  127. const short Socket::POLL_ERR = POLLERR;
  128. /** Hang up. */
  129. const short Socket::POLL_HUP = POLLHUP;
  130. /** Invalid request. */
  131. const short Socket::POLL_NVAL = POLLNVAL;
  132. /** Constructor similar to syscall.
  133. * This creates a new socket. This is a plain pass-through constructor
  134. * to the socket() syscall. In most cases this should only be used by
  135. * a derivate.
  136. * @param domain communication domain, selects the protocol
  137. * @param type type of the sockets which specifies communication semantics
  138. * @param protocol protocol to use, most types support only one and protocol
  139. * should be 0
  140. * @param timeout See Socket::timeout.
  141. * @exception SocketException thrown if socket cannot be opened, check errno for cause
  142. */
  143. Socket::Socket(int domain, int type, int protocol, float timeout)
  144. {
  145. this->timeout = timeout;
  146. if ( (sock_fd = socket(domain, type, protocol)) == -1 ) {
  147. throw SocketException("Could not open socket", errno);
  148. }
  149. if (timeout > 0.f) {
  150. // set to non-blocking
  151. if ( fcntl(sock_fd, F_SETFL, O_NONBLOCK) == -1 ) {
  152. throw SocketException("Could not set socket to non-blocking", errno);
  153. }
  154. }
  155. client_addr = NULL;
  156. client_addr_len = 0;
  157. }
  158. /** Constructor.
  159. * Plain constructor. The socket will not be opened. This may only be called by
  160. * sub-classes and you must ensure that the socket file descriptor is initialized
  161. * properly.
  162. */
  163. Socket::Socket()
  164. {
  165. client_addr = NULL;
  166. client_addr_len = 0;
  167. timeout = 0.f;
  168. sock_fd = -1;
  169. }
  170. /** Copy constructor.
  171. * @param socket socket to copy
  172. */
  173. Socket::Socket(Socket &socket)
  174. {
  175. if ( socket.client_addr != NULL ) {
  176. client_addr = (struct ::sockaddr_in *)malloc(socket.client_addr_len);
  177. client_addr_len = socket.client_addr_len;
  178. memcpy(client_addr, socket.client_addr, client_addr_len);
  179. } else {
  180. client_addr = NULL;
  181. client_addr_len = 0;
  182. }
  183. timeout = socket.timeout;
  184. sock_fd = socket.sock_fd;
  185. }
  186. /** Destructor. */
  187. Socket::~Socket()
  188. {
  189. close();
  190. if ( client_addr != NULL ) {
  191. free(client_addr);
  192. client_addr = NULL;
  193. }
  194. }
  195. /** Close socket. */
  196. void
  197. Socket::close()
  198. {
  199. if ( sock_fd != -1 ) {
  200. ::close(sock_fd);
  201. sock_fd = -1;
  202. }
  203. }
  204. /** Connect socket.
  205. * If called for a stream socket this will connect to the remote address. If
  206. * you call this on a datagram socket you will tune in to a specific sender and
  207. * receiver.
  208. * @param addr_port struct containing address and port to connect to
  209. * @param struct_size size of addr_port struct
  210. * @exception SocketException thrown if socket cannot connect, check errno for cause
  211. */
  212. void
  213. Socket::connect(struct sockaddr *addr_port, unsigned int struct_size)
  214. {
  215. if ( sock_fd == -1 ) throw SocketException("Trying to connect invalid socket");
  216. if (timeout == 0.f) {
  217. if ( ::connect(sock_fd, addr_port, struct_size) < 0 ) {
  218. throw SocketException("Could not connect", errno);
  219. }
  220. } else {
  221. struct timeval start, now;
  222. gettimeofday(&start, NULL);
  223. do {
  224. if ( ::connect(sock_fd, addr_port, struct_size) < 0 ) {
  225. if ( (errno != EINPROGRESS) &&
  226. (errno != EALREADY) ) {
  227. throw SocketException("Could not connect", errno);
  228. }
  229. }
  230. gettimeofday(&now, NULL);
  231. } while (time_diff_sec(now, start) < timeout);
  232. }
  233. }
  234. /** Connect socket.
  235. * If called for a stream socket this will connect to the remote address. If
  236. * you call this on a datagram socket you will tune in to a specific sender and
  237. * receiver.
  238. * @param hostname hostname or textual represenation of IP address to connect to
  239. * @param port port to connect to
  240. * @exception SocketException thrown if socket cannot connect, check errno for cause
  241. */
  242. void
  243. Socket::connect(const char *hostname, unsigned short int port)
  244. {
  245. if ( sock_fd == -1 ) throw SocketException("Trying to connect invalid socket");
  246. struct hostent* h;
  247. struct ::sockaddr_in host;
  248. h = gethostbyname(hostname);
  249. if ( ! h ) {
  250. throw SocketException("Cannot lookup hostname", h_errno);
  251. }
  252. memset(&host, 0, sizeof(host));
  253. host.sin_family = AF_INET;
  254. memcpy((char *)&host.sin_addr.s_addr, h->h_addr, h->h_length);
  255. host.sin_port = htons(port);
  256. connect((struct sockaddr *)&host, sizeof(host));
  257. }
  258. /** Bind socket.
  259. * Can only be called on stream sockets.
  260. * @param port port to bind
  261. * @exception SocketException thrown if socket cannot bind, check errno for cause
  262. */
  263. void
  264. Socket::bind(const unsigned short int port)
  265. {
  266. struct ::sockaddr_in host;
  267. host.sin_family = AF_INET;
  268. host.sin_addr.s_addr = INADDR_ANY;
  269. host.sin_port = htons(port);
  270. int reuse = 1;
  271. if ( setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
  272. throw SocketException("Could not set SO_REUSEADDR", errno);
  273. }
  274. if (::bind(sock_fd, (struct sockaddr *) &host, sizeof(host)) < 0) {
  275. throw SocketException("Could not bind to port", errno);
  276. }
  277. }
  278. /** Bind socket to a specific address.
  279. * @param port port to bind
  280. * @param hostname hostname or textual IP address of a local interface to bind to.
  281. * @exception SocketException thrown if socket cannot bind, check errno for cause
  282. */
  283. void
  284. Socket::bind(const unsigned short int port, const char *hostname)
  285. {
  286. struct hostent* h;
  287. struct ::sockaddr_in host;
  288. h = gethostbyname(hostname);
  289. if ( ! h ) {
  290. throw SocketException("Cannot lookup hostname", h_errno);
  291. }
  292. memset(&host, 0, sizeof(host));
  293. host.sin_family = AF_INET;
  294. memcpy(&host.sin_addr.s_addr, h->h_addr, h->h_length);
  295. host.sin_port = htons(port);
  296. host.sin_family = AF_INET;
  297. host.sin_addr.s_addr = INADDR_ANY;
  298. host.sin_port = htons(port);
  299. if (::bind(sock_fd, (struct sockaddr *) &host, sizeof(host)) < 0) {
  300. throw SocketException("Could not bind to port", errno);
  301. }
  302. }
  303. /** Listen on socket.
  304. * This waits for new connections on a bound socket. The backlog is the maximum
  305. * number of connections waiting for being accepted.
  306. * @param backlog maximum number of waiting connections
  307. * @exception SocketException thrown if socket cannot listen, check errno for cause
  308. * @see bind()
  309. * @see accept()
  310. */
  311. void
  312. Socket::listen(int backlog)
  313. {
  314. if ( ::listen(sock_fd, backlog) ) {
  315. throw SocketException("Cannot listen on socket", errno);
  316. }
  317. }
  318. /** Accept connection.
  319. * Accepts a connection waiting in the queue.
  320. * @return new socket used to communicate with the remote part
  321. * @exception SocketException thrown if socket cannot accept, check errno for cause
  322. */
  323. Socket *
  324. Socket::accept()
  325. {
  326. struct ::sockaddr_in tmp_client_addr;
  327. unsigned int tmp_client_addr_len = sizeof(struct ::sockaddr_in);
  328. int a_sock_fd = -1;
  329. a_sock_fd = ::accept(sock_fd, (sockaddr *)&tmp_client_addr, &tmp_client_addr_len);
  330. if ( a_sock_fd == -1 ) {
  331. if (errno != EWOULDBLOCK) {
  332. throw SocketException("Could not accept connection", errno);
  333. } else {
  334. return NULL;
  335. }
  336. }
  337. // Does not work, evaluated at compile time, thus need clone()
  338. //__typeof(this) s = new __typeof(*this);
  339. //s->timeout = timeout;
  340. Socket *s = clone();
  341. s->sock_fd = a_sock_fd;
  342. if ( s->client_addr != NULL ) {
  343. free(s->client_addr);
  344. }
  345. struct ::sockaddr_in *tmp_client_addr_alloc = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
  346. memcpy(tmp_client_addr_alloc, &tmp_client_addr, sizeof(struct ::sockaddr_in));
  347. s->client_addr = tmp_client_addr_alloc;
  348. s->client_addr_len = tmp_client_addr_len;
  349. return s;
  350. }
  351. /** Check if data is available.
  352. * Use this to check if data is available on the socket for reading.
  353. * @return true, if data can be read, false otherwise
  354. */
  355. bool
  356. Socket::available()
  357. {
  358. if (sock_fd == -1) return false;
  359. fd_set rfds;
  360. struct timeval tv;
  361. int retval = 1;
  362. FD_ZERO(&rfds);
  363. FD_SET(sock_fd, &rfds);
  364. tv.tv_sec = 0;
  365. tv.tv_usec = 0;
  366. retval = select(sock_fd + 1, &rfds, NULL, NULL, &tv);
  367. if ( retval < 0 ) {
  368. perror("select() failed");
  369. }
  370. return (retval > 0);
  371. }
  372. /** Wait for some event on socket.
  373. * @param timeout timeout in miliseconds to wait. A negative value means to
  374. * wait forever until an event occurs, zero means just check, don't wait.
  375. * @param what what to wait for, a bitwise OR'ed combination of POLL_IN,
  376. * POLL_OUT and POLL_PRI.
  377. * @return Returns a flag value. Use bit-wise AND with the POLL_* constants
  378. * in this class.
  379. * @exception InterruptedException thrown, if poll is interrupted by a signal
  380. * @exception SocketException thrown for any other error the poll() syscall can cause,
  381. * see Exception::errno() for the cause of the error.
  382. * @see Socket::POLL_IN
  383. * @see Socket::POLL_OUT
  384. * @see Socket::POLL_PRI
  385. * @see Socket::POLL_RDHUP
  386. * @see Socket::POLL_ERR
  387. * @see Socket::POLL_HUP
  388. * @see Socket::POLL_NVAL
  389. */
  390. short
  391. Socket::poll(int timeout, short what)
  392. {
  393. if ( sock_fd == -1 ) {
  394. return POLL_ERR;
  395. }
  396. struct pollfd pfd;
  397. pfd.fd = sock_fd;
  398. pfd.events = what;
  399. pfd.revents = 0;
  400. if ( ::poll(&pfd, 1, timeout) == -1 ) {
  401. if ( errno == EINTR ) {
  402. throw InterruptedException();
  403. } else {
  404. throw SocketException("poll() failed", errno);
  405. }
  406. } else {
  407. return pfd.revents;
  408. }
  409. }
  410. /** Write to the socket.
  411. * Write to the socket. This method can only be used on streams.
  412. * @param buf buffer to write
  413. * @param count number of bytes to write from buf
  414. * @exception SocketException if the data could not be written or if a timeout occured.
  415. */
  416. void
  417. Socket::write(const void *buf, size_t count)
  418. {
  419. int retval = 0;
  420. unsigned int bytes_written = 0;
  421. struct timeval start, now;
  422. gettimeofday(&start, NULL);
  423. do {
  424. retval = ::write(sock_fd, (char *)buf + bytes_written, count - bytes_written);
  425. if (retval == -1) {
  426. if (errno != EAGAIN) {
  427. throw SocketException("Could not write data", errno);
  428. } else {
  429. // just to meet loop condition
  430. retval = 0;
  431. }
  432. } else {
  433. bytes_written += retval;
  434. // reset timeout
  435. gettimeofday(&start, NULL);
  436. }
  437. gettimeofday(&now, NULL);
  438. usleep(0);
  439. } while ((bytes_written < count) && (time_diff_sec(now, start) < timeout) );
  440. if ( bytes_written < count) {
  441. throw SocketException("Write timeout");
  442. }
  443. }
  444. /** Read from socket.
  445. * Read from the socket. This method can only be used on streams.
  446. * @param buf buffer to write from
  447. * @param count length of buffer, number of bytes to write to stream
  448. * @param read_all setting this to true causes a call to read() loop until exactly
  449. * count bytes have been read, if false it will return after the first successful read
  450. * with the number of bytes available then.
  451. * @return number of bytes read.
  452. * @see write
  453. * @exception SocketException thrown for any error during reading
  454. */
  455. size_t
  456. Socket::read(void *buf, size_t count, bool read_all)
  457. {
  458. int retval = 0;
  459. unsigned int bytes_read = 0;
  460. if ( timeout > 0 ) {
  461. struct timeval start, now;
  462. gettimeofday(&start, NULL);
  463. if ( read_all ) {
  464. do {
  465. retval = ::read(sock_fd, (char *)buf + bytes_read, count - bytes_read);
  466. if (retval == -1) {
  467. if (errno != EAGAIN) {
  468. throw SocketException("Could not read data", errno);
  469. } else {
  470. // just to meet loop condition
  471. retval = 0;
  472. }
  473. } else {
  474. bytes_read += retval;
  475. // reset timeout
  476. gettimeofday(&start, NULL);
  477. }
  478. gettimeofday(&now, NULL);
  479. usleep(0);
  480. } while ((bytes_read < count) && (time_diff_sec(now, start) < timeout) );
  481. } else {
  482. do {
  483. retval = ::read(sock_fd, (char *)buf, count);
  484. if ( (retval == -1) && (errno != EAGAIN) ) {
  485. throw SocketException("Could not read data", errno);
  486. } else {
  487. bytes_read = retval;
  488. }
  489. usleep(0);
  490. } while (retval < 0);
  491. }
  492. } else {
  493. if ( read_all ) {
  494. do {
  495. retval = ::read(sock_fd, (char *)buf + bytes_read, count - bytes_read);
  496. if (retval == -1) {
  497. throw SocketException("Could not read data", errno);
  498. } else if (retval == 0) {
  499. throw SocketException("Could not read any data");
  500. } else {
  501. bytes_read += retval;
  502. }
  503. usleep(0);
  504. } while (bytes_read < count);
  505. } else {
  506. do {
  507. retval = ::read(sock_fd, (char *)buf, count);
  508. if ( (retval == -1) && (errno != EAGAIN) ) {
  509. throw SocketException("Could not read data", errno);
  510. } else {
  511. bytes_read = retval;
  512. }
  513. usleep(0);
  514. } while (retval < 0);
  515. }
  516. }
  517. if ( read_all && (bytes_read < count)) {
  518. throw SocketException("Read timeout");
  519. }
  520. return bytes_read;
  521. }
  522. /** Write to the socket.
  523. * Write to the socket. This method can be used on streams or on datagram
  524. * sockets which have been tuned to a specific receiver by using connect().
  525. * For streams usage of write() is recommended as it is the more intuitive
  526. * way to deal with a stream.
  527. * @param buf buffer to write
  528. * @param buf_len length of buffer, number of bytes to write to stream
  529. * @see write
  530. */
  531. void
  532. Socket::send(void *buf, size_t buf_len)
  533. {
  534. try {
  535. write(buf, buf_len);
  536. } catch (SocketException &e) {
  537. throw;
  538. }
  539. }
  540. /** Read from socket.
  541. * Read from the socket. This method can only be used on streams. Usage of
  542. * read() is recommended.
  543. * @param buf buffer to read data into
  544. * @param buf_len length of buffer, number of bytes to read from stream
  545. * @return number of bytes read
  546. * @exception SocketException thrown if an error occurs or the other side
  547. * has closed the connection.
  548. */
  549. size_t
  550. Socket::recv(void *buf, size_t buf_len)
  551. {
  552. ssize_t rv;
  553. if ( (rv = ::recv(sock_fd, buf, buf_len, 0)) == -1 ) {
  554. throw SocketException("recv() failed", errno);
  555. } else if ( rv == 0 ) {
  556. throw SocketException("Other side closed the connection");
  557. }
  558. return rv;
  559. }
  560. /** Send message.
  561. * @param buf buffer with data to send
  562. * @param buf_len length of buffer, all data will be send.
  563. * @param addr addr to send data to.
  564. * @param addr_len length of address
  565. */
  566. void
  567. Socket::send(void *buf, size_t buf_len,
  568. const struct sockaddr *addr, socklen_t addr_len)
  569. {
  570. int retval = 0;
  571. unsigned int bytes_written = 0;
  572. struct timeval start, now;
  573. gettimeofday(&start, NULL);
  574. do {
  575. retval = ::sendto(sock_fd, (char *)buf + bytes_written, buf_len - bytes_written, 0,
  576. addr, addr_len);
  577. if (retval == -1) {
  578. if (errno != EAGAIN) {
  579. throw SocketException("Could not read data", errno);
  580. } else {
  581. // just to meet loop condition
  582. retval = 0;
  583. }
  584. } else {
  585. bytes_written += retval;
  586. // reset timeout
  587. gettimeofday(&start, NULL);
  588. }
  589. gettimeofday(&now, NULL);
  590. usleep(0);
  591. } while ((bytes_written < buf_len) && (time_diff_sec(now, start) < timeout) );
  592. if ( bytes_written < buf_len) {
  593. throw SocketException("Write timeout");
  594. }
  595. }
  596. /** Receive data.
  597. * This will use recvfrom() to read data from the socket and returns the
  598. * number of bytes actually read. It will not wait until the requested
  599. * number of bytes has been read. Use read() if you need this.
  600. * @param buf buffer that read data shall be stored in.
  601. * @param buf_len length of buffer and number of bytes to be read
  602. * @param addr return parameter, contains address of sender
  603. * @param addr_len initially has to contain size of address, on return
  604. * contains the actual bytes used.
  605. * @return number of bytes received
  606. */
  607. size_t
  608. Socket::recv(void *buf, size_t buf_len,
  609. struct sockaddr *addr, socklen_t *addr_len)
  610. {
  611. ssize_t rv = 0;
  612. if ( (rv = ::recvfrom(sock_fd, buf, buf_len, 0, addr, addr_len)) == -1) {
  613. throw SocketException("recvfrom() failed", errno);
  614. } else if ( rv == 0 ) {
  615. throw SocketException("Peer has closed the connection");
  616. } else {
  617. return rv;
  618. }
  619. }
  620. /** Is socket listening for connections?
  621. * @return true if socket is listening for incoming connections, false otherwise
  622. */
  623. bool
  624. Socket::listening()
  625. {
  626. if ( sock_fd == -1 ) return false;
  627. int i = 0;
  628. unsigned int len = sizeof(i);
  629. if ( getsockopt(sock_fd, SOL_SOCKET, SO_ACCEPTCONN, &i, &len) == -1 ) {
  630. throw SocketException("Socket::listening(): getsockopt failed", errno);
  631. }
  632. return ( i == 1 );
  633. }
  634. /** Maximum Transfer Unit (MTU) of socket.
  635. * Note that this can only be retrieved of connected sockets!
  636. * @return MTU in bytes
  637. */
  638. unsigned int
  639. Socket::mtu()
  640. {
  641. int m = 0;
  642. if ( sock_fd == -1 ) throw SocketException("Cannot get MTU of disconnected socket");
  643. #ifdef __linux__
  644. unsigned int len = sizeof(m);
  645. if ( getsockopt(sock_fd, IPPROTO_IP, IP_MTU, &m, &len) == -1 ) {
  646. throw SocketException("Socket::mtu(): getsockopt failed", errno);
  647. }
  648. if ( m < 0 ) {
  649. throw SocketException("MTU < 0");
  650. }
  651. #elif defined __FreeBSD__
  652. struct ifreq ifr;
  653. if (ioctl(sock_fd, SIOCGIFMTU, &ifr) != -1)
  654. m = ifr.ifr_mtu;
  655. #endif
  656. return m;
  657. }
  658. } // end namespace fawkes