#include "socket.h" #include "stringf.h" #include #include #include int socket_bind(string host_port_str) { const char *cs(strrchr(host_port_str.c_str(),':')); const string node(!cs?"":host_port_str.substr(0,cs-host_port_str.c_str())); const string service(!cs?host_port_str:cs+1); struct addrinfo hints={}; // designated initializer: error: missing initializer for member ... [-Werror=missing-field-initializers] hints.ai_family=AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype=SOCK_STREAM; hints.ai_flags=AI_PASSIVE|AI_ADDRCONFIG; /* For wildcard IP address */ struct addrinfo *result; int err(getaddrinfo(node.empty()?NULL:node.c_str(),service.c_str(),&hints,&result)); if (err) fatal("<%s>:<%s>: %s",node.c_str(),service.c_str(),gai_strerror(err)); int fd=-1; struct addrinfo *rp; for (rp=result;rp;rp=rp->ai_next) { fd=socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol); if (fd==-1) continue; static const int int1(1); err=setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&int1,sizeof(int1)); assert(!err); if (bind(fd,rp->ai_addr,rp->ai_addrlen)==0) break; err=close(fd); assert(!err); } if (rp==NULL) fatal("Cannot bind(): <%s>:<%s>: %m",node.c_str(),service.c_str()); assert(fd!=-1); freeaddrinfo(result); err=listen(fd,SOMAXCONN); assert(!err); return fd; } string sockaddr_string(const struct sockaddr *sockaddrp,socklen_t socklen) { char hostname[NI_MAXHOST]; char servname[NI_MAXSERV]; const int err=getnameinfo(sockaddrp,socklen,hostname,sizeof(hostname),servname,sizeof(servname),NI_NUMERICSERV/*flags*/); assert(!err); return stringf("%s:%s",hostname,servname); } string socket_name(int socket_fd) { struct sockaddr sockaddr; socklen_t socklen(sizeof(sockaddr)); const int err(getsockname(socket_fd,&sockaddr,&socklen)); assert(!err); return sockaddr_string(&sockaddr,socklen); } static void socket_setopt(int fd) { static const int int1(1); int err; err=setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,&int1,sizeof(int1)); assert(!err); static const uint8_t tos(IPTOS_LOWDELAY); err=setsockopt(fd,IPPROTO_IP,IP_TOS,&tos,sizeof(tos)); assert(!err); err=setsockopt(fd,IPPROTO_IP,TCP_NODELAY,&int1,sizeof(int1)); assert(!err); } int socket_accept(int listen_fd,function msgfunc) { struct sockaddr sockaddr; socklen_t socklen(sizeof(sockaddr)); const int client_fd(accept(listen_fd,&sockaddr,&socklen)); assert(client_fd>=0); msgfunc(client_fd,sockaddr_string(&sockaddr,socklen)); socket_setopt(client_fd); return client_fd; } int socket_connect(const string &host_port_str,unsigned retries) { const char *cs(strrchr(host_port_str.c_str(),':')); if (!cs) fatal("Error parsing :: %s",host_port_str.c_str()); const string node(host_port_str.substr(0,cs-host_port_str.c_str())); const string service(cs+1); struct addrinfo hints={}; // designated initializer: error: missing initializer for member ... [-Werror=missing-field-initializers] hints.ai_family=AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype=SOCK_STREAM; struct addrinfo *result; int err=getaddrinfo(node.c_str(),service.c_str(),&hints,&result); if (err) fatal("Error parsing node+service: <%s>:<%s>: %s",node.c_str(),service.c_str(),gai_strerror(err)); int fd; struct addrinfo *rp; for (unsigned retryno=0;retryno<1+retries;++retryno) { if (retryno) { warning("Sleeping 1 second for connect retry #%u/%u",retryno,retries); err=sleep(1); assert(!err); } for (rp=result;rp;rp=rp->ai_next) { fd=socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol); if (fd==-1) continue; if (connect(fd,rp->ai_addr,rp->ai_addrlen)==0) break; err=close(fd); assert(!err); } if (rp==NULL) warning("Could not connect(): <%s>:<%s>: %m",node.c_str(),service.c_str()); else break; } freeaddrinfo(result); if (rp==NULL) fatal("Could not connect(), giving up"); socket_setopt(fd); return fd; }