24 #include <netcomm/socket/socket.h> 26 #include <core/exceptions/system.h> 27 #include <utils/time/time.h> 28 #include <utils/misc/string_conversions.h> 35 #include <sys/types.h> 36 #include <sys/socket.h> 44 #include <netinet/in.h> 45 #include <netinet/in_systm.h> 46 #include <netinet/ip.h> 47 #include <arpa/inet.h> 60 # include <sys/ioctl.h> 141 const short Socket::POLL_RDHUP = 0;
164 : addr_type(addr_type), sock_fd(-1), timeout(timeout),
165 client_addr(NULL), client_addr_len(0), socket_protocol_(0)
167 if (addr_type ==
IPv4) {
168 socket_addr_family_ = AF_INET;
169 }
else if (addr_type ==
IPv6) {
170 socket_addr_family_ = AF_INET6;
174 if (sock_type ==
TCP) {
175 socket_type_ = SOCK_STREAM;
176 }
else if (sock_type ==
UDP) {
177 socket_type_ = SOCK_DGRAM;
193 socket_addr_family_(-1), socket_protocol_(0)
195 if (sock_type ==
TCP) {
196 socket_type_ = SOCK_STREAM;
197 }
else if (sock_type ==
UDP) {
198 socket_type_ = SOCK_DGRAM;
212 socket_addr_family_(0), socket_type_(0), socket_protocol_(0)
226 client_addr = (struct ::sockaddr_storage *)malloc(
sizeof(struct ::sockaddr_storage));
235 socket_addr_family_ = socket.socket_addr_family_;
236 socket_type_ = socket.socket_type_;
237 socket_protocol_ = socket.socket_protocol_;
244 if (socket_addr_family_ == -1) {
248 if ( (
sock_fd = socket(socket_addr_family_, socket_type_, socket_protocol_)) == -1 ) {
254 if ( fcntl(
sock_fd, F_SETFL, O_NONBLOCK) == -1 ) {
293 connect((
const struct sockaddr *)&addr_port,
sizeof(::sockaddr_storage));
308 socket_addr_family_ = addr_port->sa_family;
317 struct timeval start, now;
318 gettimeofday(&start, NULL);
321 if ( (errno != EINPROGRESS) && (errno != EALREADY) ) {
325 gettimeofday(&now, NULL);
344 struct addrinfo hints, *servinfo, *p;
347 std::string tried_endpoints;
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) {
356 hostname, port_s.c_str(), gai_strerror(rv));
359 for (p = servinfo; p != NULL; p = p->ai_next) {
363 if ((
sock_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
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);
385 tried_endpoints += std::string(
" IPv4:FAIL") + tmp +
":" + port_s +
"|" + what +
"|" + strerror(lerrno);
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);
392 tried_endpoints += std::string(
" IPv6:FAIL") + tmp +
":" + port_s +
"|" + what +
"|" + strerror(lerrno);
395 tried_endpoints += std::string(
" UNKNOWN_AF:") + port_s;
405 freeaddrinfo(servinfo);
407 if (p == NULL ||
sock_fd == -1) {
408 throw SocketException(
"Failed to connect to any endpoint (tried:%s)", tried_endpoints.c_str());
427 struct ::sockaddr_in host;
428 memset(&host, 0,
sizeof(host));
430 host.sin_family = AF_INET;
431 host.sin_addr.s_addr = INADDR_ANY;
432 host.sin_port = htons(port);
435 if ( setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse)) == -1) {
439 if (::
bind(
sock_fd, (
struct sockaddr *) &host,
sizeof(host)) < 0) {
446 struct ::sockaddr_in6 host;
447 memset(&host, 0,
sizeof(host));
449 host.sin6_family = AF_INET6;
450 host.sin6_port = htons(port);
453 if ( setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) == -1) {
456 if ( setsockopt(
sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) == -1) {
460 if (::
bind(
sock_fd, (
struct sockaddr *) &host,
sizeof(host)) < 0) {
466 throw SocketException(
"Address type not specified for socket, cannot bind");
487 struct ::sockaddr_in host;
488 memset(&host, 0,
sizeof(host));
490 host.sin_family = AF_INET;
491 host.sin_port = htons(port);
493 if (inet_pton(AF_INET, ipaddr, &host.sin_addr) <= 0) {
494 throw SocketException(
"bind(IPv4): failed to parse IP address '%s'", ipaddr);
498 if ( setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse)) == -1) {
502 if (::
bind(
sock_fd, (
struct sockaddr *) &host,
sizeof(host)) < 0) {
509 struct ::sockaddr_in6 host;
510 memset(&host, 0,
sizeof(host));
512 host.sin6_family = AF_INET6;
513 host.sin6_port = htons(port);
515 if (inet_pton(AF_INET6, ipaddr, &host.sin6_addr) <= 0) {
516 throw SocketException(
"bind(IPv6): failed to parse IP address '%s'", ipaddr);
520 if ( setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) == -1) {
523 if ( setsockopt(
sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) == -1) {
527 if (::
bind(
sock_fd, (
struct sockaddr *) &host,
sizeof(host)) < 0) {
533 throw SocketException(
"Address type not specified for socket, cannot bind");
550 throw SocketException(
"Socket not initialized, call bind() or connect()");
568 throw SocketException(
"Socket not initialized, call bind() or connect()");
571 struct ::sockaddr_in tmp_client_addr;
572 unsigned int tmp_client_addr_len =
sizeof(struct ::sockaddr_in);
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) {
613 if (
sock_fd == -1)
return false;
624 retval = select(
sock_fd + 1, &rfds, NULL, NULL, &tv);
626 perror(
"select() failed");
662 if ( ::
poll(&pfd, 1, timeout) == -1 ) {
663 if ( errno == EINTR ) {
684 throw SocketException(
"Socket not initialized, call bind() or connect()");
688 unsigned int bytes_written = 0;
689 struct timeval start, now;
691 gettimeofday(&start, NULL);
694 retval =
::write(
sock_fd, (
char *)buf + bytes_written, count - bytes_written);
696 if (errno != EAGAIN) {
703 bytes_written += retval;
705 gettimeofday(&start, NULL);
707 gettimeofday(&now, NULL);
711 if ( bytes_written < count) {
732 throw SocketException(
"Socket not initialized, call bind() or connect()");
736 unsigned int bytes_read = 0;
739 struct timeval start, now;
741 gettimeofday(&start, NULL);
745 retval =
::read(
sock_fd, (
char *)buf + bytes_read, count - bytes_read);
747 if (errno != EAGAIN) {
754 bytes_read += retval;
756 gettimeofday(&start, NULL);
758 gettimeofday(&now, NULL);
764 if ( (retval == -1) && (errno != EAGAIN) ) {
770 }
while (retval < 0);
775 retval =
::read(
sock_fd, (
char *)buf + bytes_read, count - bytes_read);
778 }
else if (retval == 0) {
781 bytes_read += retval;
784 }
while (bytes_read < count);
788 if ( (retval == -1) && (errno != EAGAIN) ) {
794 }
while (retval < 0);
798 if ( read_all && (bytes_read < count)) {
839 throw SocketException(
"Socket not initialized, call bind() or connect()");
843 if ( (rv = ::
recv(
sock_fd, buf, buf_len, 0)) == -1 ) {
845 }
else if ( rv == 0 ) {
860 const struct sockaddr *addr, socklen_t addr_len)
863 throw SocketException(
"Socket not initialized, call bind() or connect()");
867 unsigned int bytes_written = 0;
868 struct timeval start, now;
870 gettimeofday(&start, NULL);
873 retval = ::sendto(
sock_fd, (
char *)buf + bytes_written, buf_len - bytes_written, 0,
876 if (errno != EAGAIN) {
883 bytes_written += retval;
885 gettimeofday(&start, NULL);
887 gettimeofday(&now, NULL);
891 if ( bytes_written < buf_len) {
910 struct sockaddr *addr, socklen_t *addr_len)
913 throw SocketException(
"Socket not initialized, call bind() or connect()");
918 if ( (rv = ::recvfrom(
sock_fd, buf, buf_len, 0, addr, addr_len)) == -1) {
920 }
else if ( rv == 0 ) {
934 if (
sock_fd == -1 )
return false;
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");
953 throw SocketException(
"Socket not initialized, call bind() or connect()");
959 unsigned int len =
sizeof(m);
960 if ( getsockopt(
sock_fd, IPPROTO_IP, IP_MTU, &m, &len) == -1 ) {
967 #elif defined __FreeBSD__ 969 if (ioctl(
sock_fd, SIOCGIFMTU, &ifr) != -1)
virtual void connect(const char *hostname, const unsigned short int port)
Connect socket.
static const short POLL_ERR
Error condition.
virtual void close()
Close socket.
virtual void write(const void *buf, size_t count)
Write to the 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 ...
Fawkes library namespace.
virtual size_t recv(void *buf, size_t buf_len)
Read from socket.
static const short POLL_IN
Data can be read.
struct ::sockaddr_storage * client_addr
Client address, set if connected.
AddrType
Address type specification.
int _errno
Error number, should be used if the error was caused by a method that supplies errno.
unsigned int client_addr_len
length in bytes of client address.
virtual bool available()
Check if data is available.
virtual Socket * accept()
Accept connection.
virtual Socket * clone()=0
Clone socket.
Base class for exceptions in Fawkes.
double time_diff_sec(const timeval &a, const timeval &b)
Calculate time difference of two time structs.
virtual size_t read(void *buf, size_t count, bool read_all=true)
Read from socket.
void append_va(const char *format, va_list va)
Append messages to the message list.
The current system call has been interrupted (for instance by a signal).
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.
AddrType addr_type
Address type/family of socket.
virtual ~Socket()
Destructor.
virtual bool listening()
Is socket listening for connections?
virtual unsigned int mtu()
Maximum Transfer Unit (MTU) of socket.
virtual short poll(int timeout=-1, short what=POLL_IN|POLL_HUP|POLL_PRI|POLL_RDHUP)
Wait for some event on socket.
int sock_fd
Socket file descriptor.
virtual void send(void *buf, size_t buf_len)
Write to the socket.
static const short POLL_HUP
Hang up.
static const short POLL_NVAL
Invalid request.
virtual void listen(int backlog=1)
Listen on socket.
static std::string to_string(unsigned int i)
Convert unsigned int value to a string.
float timeout
Timeout in seconds for various operations.
SocketException(int _errno, const char *msg)
Constructor.
static const short POLL_OUT
Writing will not block.