24 #include <core/exceptions/system.h>
25 #include <netcomm/socket/socket.h>
26 #include <utils/misc/string_conversions.h>
27 #include <utils/time/time.h>
33 #include <sys/socket.h>
34 #include <sys/types.h>
44 #include <arpa/inet.h>
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip.h>
60 # include <sys/ioctl.h>
158 : addr_type(addr_type),
166 socket_addr_family_ = AF_INET;
168 socket_addr_family_ = AF_INET6;
172 if (sock_type ==
TCP) {
173 socket_type_ = SOCK_STREAM;
174 }
else if (sock_type ==
UDP) {
175 socket_type_ = SOCK_DGRAM;
194 socket_addr_family_(-1),
197 if (sock_type ==
TCP) {
198 socket_type_ = SOCK_STREAM;
199 }
else if (sock_type ==
UDP) {
200 socket_type_ = SOCK_DGRAM;
216 socket_addr_family_(0),
231 client_addr = (struct ::sockaddr_storage *)malloc(
sizeof(struct ::sockaddr_storage));
240 socket_addr_family_ = socket.socket_addr_family_;
241 socket_type_ = socket.socket_type_;
242 socket_protocol_ = socket.socket_protocol_;
262 client_addr = (struct ::sockaddr_storage *)malloc(
sizeof(struct ::sockaddr_storage));
271 socket_addr_family_ = socket.socket_addr_family_;
272 socket_type_ = socket.socket_type_;
273 socket_protocol_ = socket.socket_protocol_;
283 if (socket_addr_family_ == -1) {
287 if ((
sock_fd = socket(socket_addr_family_, socket_type_, socket_protocol_)) == -1) {
288 throw SocketException(errno,
"Could not open socket");
293 if (fcntl(
sock_fd, F_SETFL, O_NONBLOCK) == -1) {
294 throw SocketException(errno,
"Could not set socket to non-blocking");
329 connect((
const struct sockaddr *)&addr_port,
sizeof(::sockaddr_storage));
345 socket_addr_family_ = addr_port->sa_family;
354 struct timeval start, now;
355 gettimeofday(&start, NULL);
358 if ((errno != EINPROGRESS) && (errno != EALREADY)) {
362 gettimeofday(&now, NULL);
381 struct addrinfo hints, *servinfo, *p;
384 std::string tried_endpoints;
388 memset(&hints, 0,
sizeof(hints));
389 hints.ai_family = AF_UNSPEC;
390 hints.ai_socktype = socket_type_;
391 if ((rv = getaddrinfo(hostname, port_s.c_str(), &hints, &servinfo)) != 0) {
398 for (p = servinfo; p != NULL; p = p->ai_next) {
402 if ((
sock_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
419 if (p->ai_family == AF_INET) {
420 char tmp[INET_ADDRSTRLEN];
422 p->ai_family, &((
struct sockaddr_in *)p->ai_addr)->sin_addr, tmp, INET_ADDRSTRLEN)
425 std::string(
" IPv4:") + tmp +
":" + port_s +
"|" + what +
"|" + strerror(lerrno);
428 std::string(
" IPv4:FAIL") + tmp +
":" + port_s +
"|" + what +
"|" + strerror(lerrno);
430 }
else if (p->ai_family == AF_INET6) {
431 char tmp[INET6_ADDRSTRLEN];
433 p->ai_family, &((
struct sockaddr_in6 *)p->ai_addr)->sin6_addr, tmp, INET6_ADDRSTRLEN)
436 std::string(
" IPv6:[") + tmp +
"]:" + port_s +
"|" + what +
"|" + strerror(lerrno);
439 std::string(
" IPv6:FAIL") + tmp +
":" + port_s +
"|" + what +
"|" + strerror(lerrno);
442 tried_endpoints += std::string(
" UNKNOWN_AF:") + port_s;
452 freeaddrinfo(servinfo);
454 if (p == NULL ||
sock_fd == -1) {
455 throw SocketException(
"Failed to connect to any endpoint (tried:%s)", tried_endpoints.c_str());
473 struct ::sockaddr_in host;
474 memset(&host, 0,
sizeof(host));
476 host.sin_family = AF_INET;
477 host.sin_addr.s_addr = INADDR_ANY;
478 host.sin_port = htons(port);
481 if (setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse)) == -1) {
485 if (::
bind(
sock_fd, (
struct sockaddr *)&host,
sizeof(host)) < 0) {
490 struct ::sockaddr_in6 host;
491 memset(&host, 0,
sizeof(host));
493 host.sin6_family = AF_INET6;
494 host.sin6_port = htons(port);
497 if (setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) == -1) {
500 if (setsockopt(
sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) == -1) {
504 if (::
bind(
sock_fd, (
struct sockaddr *)&host,
sizeof(host)) < 0) {
508 default:
throw SocketException(
"Address type not specified for socket, cannot bind");
527 struct ::sockaddr_in host;
528 memset(&host, 0,
sizeof(host));
530 host.sin_family = AF_INET;
531 host.sin_port = htons(port);
533 if (inet_pton(AF_INET, ipaddr, &host.sin_addr) <= 0) {
534 throw SocketException(
"bind(IPv4): failed to parse IP address '%s'", ipaddr);
538 if (setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse)) == -1) {
542 if (::
bind(
sock_fd, (
struct sockaddr *)&host,
sizeof(host)) < 0) {
547 struct ::sockaddr_in6 host;
548 memset(&host, 0,
sizeof(host));
550 host.sin6_family = AF_INET6;
551 host.sin6_port = htons(port);
553 if (inet_pton(AF_INET6, ipaddr, &host.sin6_addr) <= 0) {
554 throw SocketException(
"bind(IPv6): failed to parse IP address '%s'", ipaddr);
558 if (setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) == -1) {
561 if (setsockopt(
sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) == -1) {
565 if (::
bind(
sock_fd, (
struct sockaddr *)&host,
sizeof(host)) < 0) {
569 default:
throw SocketException(
"Address type not specified for socket, cannot bind");
585 throw SocketException(
"Socket not initialized, call bind() or connect()");
602 throw SocketException(
"Socket not initialized, call bind() or connect()");
605 struct ::sockaddr_in tmp_client_addr;
606 unsigned int tmp_client_addr_len =
sizeof(struct ::sockaddr_in);
610 a_sock_fd =
::accept(
sock_fd, (sockaddr *)&tmp_client_addr, &tmp_client_addr_len);
611 if (a_sock_fd == -1) {
612 if (errno != EWOULDBLOCK) {
658 retval = select(
sock_fd + 1, &rfds, NULL, NULL, &tv);
660 perror(
"select() failed");
696 if (errno == EINTR) {
716 throw SocketException(
"Socket not initialized, call bind() or connect()");
720 unsigned int bytes_written = 0;
721 struct timeval start, now;
723 gettimeofday(&start, NULL);
726 retval =
::write(
sock_fd, (
char *)buf + bytes_written, count - bytes_written);
728 if (errno != EAGAIN) {
735 bytes_written += retval;
737 gettimeofday(&start, NULL);
739 gettimeofday(&now, NULL);
743 if (bytes_written < count) {
763 throw SocketException(
"Socket not initialized, call bind() or connect()");
767 unsigned int bytes_read = 0;
770 struct timeval start, now;
772 gettimeofday(&start, NULL);
776 retval =
::read(
sock_fd, (
char *)buf + bytes_read, count - bytes_read);
778 if (errno != EAGAIN) {
785 bytes_read += retval;
787 gettimeofday(&start, NULL);
789 gettimeofday(&now, NULL);
795 if ((retval == -1) && (errno != EAGAIN)) {
801 }
while (retval < 0);
806 retval =
::read(
sock_fd, (
char *)buf + bytes_read, count - bytes_read);
809 }
else if (retval == 0) {
812 bytes_read += retval;
815 }
while (bytes_read < count);
819 if ((retval == -1) && (errno != EAGAIN)) {
825 }
while (retval < 0);
829 if (read_all && (bytes_read < count)) {
868 throw SocketException(
"Socket not initialized, call bind() or connect()");
872 if ((rv = ::
recv(
sock_fd, buf, buf_len, 0)) == -1) {
874 }
else if (rv == 0) {
887 Socket::send(
void *buf,
size_t buf_len,
const struct sockaddr *addr, socklen_t addr_len)
890 throw SocketException(
"Socket not initialized, call bind() or connect()");
894 unsigned int bytes_written = 0;
895 struct timeval start, now;
897 gettimeofday(&start, NULL);
901 ::sendto(
sock_fd, (
char *)buf + bytes_written, buf_len - bytes_written, 0, addr, addr_len);
903 if (errno != EAGAIN) {
910 bytes_written += retval;
912 gettimeofday(&start, NULL);
914 gettimeofday(&now, NULL);
918 if (bytes_written < buf_len) {
935 Socket::recv(
void *buf,
size_t buf_len,
struct sockaddr *addr, socklen_t *addr_len)
938 throw SocketException(
"Socket not initialized, call bind() or connect()");
943 if ((rv = ::recvfrom(
sock_fd, buf, buf_len, 0, addr, addr_len)) == -1) {
945 }
else if (rv == 0) {
962 unsigned int len =
sizeof(i);
963 if (getsockopt(
sock_fd, SOL_SOCKET, SO_ACCEPTCONN, &i, &len) == -1) {
964 throw SocketException(errno,
"Socket::listening(): getsockopt failed");
977 throw SocketException(
"Socket not initialized, call bind() or connect()");
983 unsigned int len =
sizeof(m);
984 if (getsockopt(
sock_fd, IPPROTO_IP, IP_MTU, &m, &len) == -1) {
991 #elif defined __FreeBSD__
993 if (ioctl(
sock_fd, SIOCGIFMTU, &ifr) != -1)
Base class for exceptions in Fawkes.
void append_va(const char *format, va_list va) noexcept
Append messages to the message list.
The current system call has been interrupted (for instance by a signal).
SocketException(int _errno, const char *msg)
Constructor.
virtual bool available()
Check if data is available.
virtual void bind(const unsigned short int port)
Bind socket.
static const short POLL_RDHUP
Stream socket peer closed connection, or shut down writing half of connection.
int sock_fd
Socket file descriptor.
static const short POLL_NVAL
Invalid request.
AddrType
Address type specification.
virtual unsigned int mtu()
Maximum Transfer Unit (MTU) of socket.
virtual void connect(const char *hostname, const unsigned short int port)
Connect socket.
virtual size_t recv(void *buf, size_t buf_len)
Read from socket.
@ UDP
UDP datagram socket.
virtual size_t read(void *buf, size_t count, bool read_all=true)
Read from socket.
static const short POLL_HUP
Hang up.
virtual bool listening()
Is socket listening for connections?
Socket & operator=(Socket &socket)
Copy constructor.
static const short POLL_IN
Data can be read.
virtual void send(void *buf, size_t buf_len)
Write to the socket.
AddrType addr_type
Address type/family of socket.
static const short POLL_OUT
Writing will not block.
virtual short poll(int timeout=-1, short what=POLL_IN|POLL_HUP|POLL_PRI|POLL_RDHUP)
Wait for some event on socket.
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 ...
virtual Socket * clone()=0
Clone socket.
virtual ~Socket()
Destructor.
float timeout
Timeout in seconds for various operations.
struct ::sockaddr_storage * client_addr
Client address, set if connected.
virtual Socket * accept()
Accept connection.
static const short POLL_ERR
Error condition.
virtual void listen(int backlog=1)
Listen on socket.
unsigned int client_addr_len
length in bytes of client address.
virtual void close()
Close socket.
virtual void write(const void *buf, size_t count)
Write to the socket.
static std::string to_string(unsigned int i)
Convert unsigned int value to a string.
Fawkes library namespace.
double time_diff_sec(const timeval &a, const timeval &b)
Calculate time difference of two time structs.