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