00001 #ifndef COMMONS_SOCKETS_H
00002 #define COMMONS_SOCKETS_H
00003
00004 #include <arpa/inet.h>
00005 #include <netdb.h>
00006 #include <netinet/in.h>
00007 #include <strings.h>
00008 #include <sys/socket.h>
00009 #include <sys/types.h>
00010 #include <fcntl.h>
00011 #include <unistd.h>
00012
00013 #include <commons/check.h>
00014 #include <commons/closing.h>
00015 #include <commons/nullptr.h>
00016
00017 namespace commons
00018 {
00019
00023 #undef __FDMASK
00024 #define __FDMASK(d) (static_cast<__fd_mask>(1) << ((d) % __NFDBITS))
00025
00029 const in_addr_t inaddr_any = in_addr_t(0);
00030
00034 int
00035 set_non_blocking(int fd)
00036 {
00037 checknnegerr(fcntl(fd, F_SETFL,
00038 O_NONBLOCK | checknnegerr(fcntl(fd, F_GETFL, 0))));
00039 return fd;
00040 }
00041
00045 int
00046 tcp_socket(bool nb)
00047 {
00048 int fd = checknnegerr(socket(PF_INET, SOCK_STREAM, 0));
00049
00050 if (nb) set_non_blocking(fd);
00051 return fd;
00052 }
00053
00057 inline uint16_t
00058 safe_htons(uint16_t x)
00059 {
00060 return (x & 0x00ff << 8) | (x & 0xff00 >> 8);
00061 }
00062
00066 void
00067 sockaddr_init(sockaddr_in &a, uint16_t port)
00068 {
00069 bzero(&a, sizeof a);
00070 a.sin_family = AF_INET;
00071 a.sin_port = safe_htons(port);
00072 }
00073
00077 void
00078 sockaddr_init(sockaddr_in &a, const char *host, uint16_t port)
00079 {
00080 sockaddr_init(a, port);
00081 if (host == nullptr) {
00082 a.sin_addr.s_addr = htonl(inaddr_any);
00083 } else {
00084
00085 if (!inet_aton(host, reinterpret_cast<in_addr*>(&a.sin_addr.s_addr))) {
00086
00087 hostent *res = checkpass(gethostbyname(host));
00088 memcpy(&a.sin_addr, res->h_addr_list[0], res->h_length);
00089 }
00090 }
00091 }
00092
00096 void
00097 sockaddr_init(sockaddr_in &a, in_addr host, uint16_t port)
00098 {
00099 sockaddr_init(a, port);
00100 a.sin_addr = host;
00101 }
00102
00106 template <typename T>
00107 sockaddr_in
00108 make_sockaddr(T host, uint16_t port)
00109 {
00110 sockaddr_in a;
00111 sockaddr_init(a, host, port);
00112 return a;
00113 }
00114
00121 int
00122 server_socket(uint16_t port, bool nb = false)
00123 {
00124
00125 closingfd c(tcp_socket(nb));
00126 int fd = c.get();
00127
00128
00129 int n = 1;
00130 check0x(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
00131 reinterpret_cast<char*>(&n), sizeof(n)));
00132
00133
00134 sockaddr_in sa = make_sockaddr(nullptr, port);
00135
00136
00137 check0x(::bind(fd, reinterpret_cast<sockaddr*>(&sa), sizeof sa));
00138
00139 return c.release();
00140 }
00141
00148 int
00149 tcp_listen(uint16_t port, bool nb = false)
00150 {
00151 int fd = server_socket(port, nb);
00152 try {
00153
00154
00155 check0x(listen(fd, SOMAXCONN));
00156 return fd;
00157 } catch (...) {
00158 close(fd);
00159 throw;
00160 }
00161 }
00162
00166 int
00167 tcp_connect(const char *host, uint16_t port)
00168 {
00169 closingfd c(tcp_socket(false));
00170 sockaddr_in a = make_sockaddr(host, port);
00171 check0x(connect(c.get(), reinterpret_cast<sockaddr*>(&a), sizeof a));
00172 return c.release();
00173 }
00174
00175 }
00176
00177 #endif