Revert "Revert "socket: use getaddrinfo""
authorMike Looijmans <milo-software@users.sourceforge.net>
Fri, 22 May 2015 16:57:06 +0000 (18:57 +0200)
committerMike Looijmans <milo-software@users.sourceforge.net>
Fri, 22 May 2015 18:26:21 +0000 (20:26 +0200)
This reverts commit 28618e4d5d6b4f07565c7f10f52f6cbaa75548c7.

lib/network/serversocket.cpp
lib/network/serversocket.h
lib/network/socket.cpp
lib/network/socket.h

index 78aa3c9..14cfb2a 100644 (file)
@@ -1,4 +1,5 @@
 #include <errno.h>
+#include <string.h>
 #include <lib/network/serversocket.h>
 #include <arpa/inet.h>
 
@@ -9,82 +10,138 @@ bool eServerSocket::ok()
 
 void eServerSocket::notifier(int)
 {
-       int clientfd, clientlen;
-       struct sockaddr_in client_addr;
+       int clientfd;
+       socklen_t clientlen;
+       struct sockaddr client_addr;
+       char straddr[INET6_ADDRSTRLEN];
 
 #ifdef DEBUG_SERVERSOCKET
        eDebug("[eServerSocket] incoming connection!");
 #endif
 
-       clientlen=sizeof(client_addr);
-       clientfd=accept(getDescriptor(),
-                       (struct sockaddr *) &client_addr,
-                       (socklen_t*)&clientlen);
-       if(clientfd<0)
+       clientlen = sizeof(client_addr);
+       clientfd = accept(getDescriptor(), &client_addr, &clientlen);
+       if (clientfd < 0)
+       {
                eDebug("[eServerSocket] error on accept: %m");
+               return;
+       }
 
-       strRemoteHost = inet_ntoa(client_addr.sin_addr);
+       if (client_addr.sa_family == AF_LOCAL)
+       {
+               strRemoteHost = "(local)";
+       }
+       else
+       {
+               strRemoteHost = inet_ntop(client_addr.sa_family, client_addr.sa_data, straddr, sizeof(straddr));
+       }
        newConnection(clientfd);
 }
 
 eServerSocket::eServerSocket(int port, eMainloop *ml): eSocket(ml)
 {
-       struct sockaddr_in serv_addr;
-       strRemoteHost = "";
+       int res;
+       struct addrinfo *addr = NULL;
+       struct addrinfo hints;
+       char portnumber[16];
 
-       bzero(&serv_addr, sizeof(serv_addr));
-       serv_addr.sin_family=AF_INET;
-       serv_addr.sin_addr.s_addr=INADDR_ANY;
-       serv_addr.sin_port=htons(port);
-
-       okflag=1;
-       int val=1;
+       okflag = 0;
+       strRemoteHost = "";
 
-       setsockopt(getDescriptor(), SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_UNSPEC; /* both ipv4 and ipv6 */
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_protocol = 0; /* any */
+#ifdef AI_ADDRCONFIG
+       hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_ADDRCONFIG; /* only return ipv6 if we have an ipv6 address ourselves, and ipv4 if we have an ipv4 address ourselves */
+#else
+       hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* AI_ADDRCONFIG is not available */
+#endif
+       snprintf(portnumber, sizeof(portnumber), "%d", port);
 
-       if(bind(getDescriptor(),
-               (struct sockaddr *) &serv_addr,
-               sizeof(serv_addr))<0)
+       if ((res = getaddrinfo(NULL, portnumber, &hints, &addr)) || !addr)
        {
-               eDebug("[eServerSocket] ERROR on bind: %m");
-               okflag=0;
+               eDebug("[eServerSocket] getaddrinfo: %s", gai_strerror(res));
+               return;
        }
-       listen(getDescriptor(), 0);
 
-       rsn->setRequested(eSocketNotifier::Read);
+       if (startListening(addr) >= 0)
+       {
+               okflag = 1;
+               rsn->setRequested(eSocketNotifier::Read);
+       }
+       freeaddrinfo(addr);
 }
 
-eServerSocket::eServerSocket(std::string path, eMainloop *ml) : eSocket(ml, AF_LOCAL)
+eServerSocket::eServerSocket(std::string path, eMainloop *ml) : eSocket(ml)
 {
-       struct sockaddr_un serv_addr;
+       struct sockaddr_un serv_addr_un;
+       struct addrinfo addr;
+
+       okflag = 0;
        strRemoteHost = "";
 
-       memset(&serv_addr, 0, sizeof(serv_addr));
-       serv_addr.sun_family = AF_LOCAL;
-       strcpy(serv_addr.sun_path, path.c_str());
+       memset(&serv_addr_un, 0, sizeof(serv_addr_un));
+       serv_addr_un.sun_family = AF_LOCAL;
+       strcpy(serv_addr_un.sun_path, path.c_str());
 
-       okflag=1;
+       memset(&addr, 0, sizeof(addr));
+       addr.ai_family = AF_LOCAL;
+       addr.ai_socktype = SOCK_STREAM;
+       addr.ai_protocol = 0; /* any */
+       addr.ai_addr = (struct sockaddr *)&serv_addr_un;
+       addr.ai_addrlen = sizeof(serv_addr_un);
 
        unlink(path.c_str());
-       if(bind(getDescriptor(),
-               (struct sockaddr *) &serv_addr,
-               sizeof(serv_addr))<0)
+
+       if (startListening(&addr) >= 0)
        {
-               eDebug("[eServerSocket] ERROR on bind: %m");
-               okflag=0;
+               okflag = 1;
+               rsn->setRequested(eSocketNotifier::Read);
        }
-       listen(getDescriptor(), 0);
-
-       rsn->setRequested(eSocketNotifier::Read);
 }
 
 eServerSocket::~eServerSocket()
 {
-#if 0
+#ifdef DEBUG_SERVERSOCKET
        eDebug("[eServerSocket] destructed");
 #endif
 }
 
+int eServerSocket::startListening(struct addrinfo *addr)
+{
+       struct addrinfo *ptr = addr;
+       for (ptr = addr; ptr != NULL; ptr = ptr->ai_next)
+       {
+               if (setSocket(socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol), 1) < 0)
+               {
+                       continue;
+               }
+
+               int val = 1;
+               setsockopt(getDescriptor(), SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+
+               if (bind(getDescriptor(), ptr->ai_addr, ptr->ai_addrlen) < 0)
+               {
+                       eDebug("[eServerSocket] ERROR on bind: %m");
+                       close();
+                       continue;
+               }
+       }
+
+       if (getDescriptor() < 0)
+       {
+               return -1;
+       }
+
+       if (listen(getDescriptor(), 0) < 0)
+       {
+               close();
+               return -1;
+       }
+       return 0;
+}
+
 int eServerSocket::bind(int sockfd, struct sockaddr *addr, socklen_t addrlen)
 {
        int result;
index a4df9b5..0b290bb 100644 (file)
@@ -9,7 +9,8 @@ class eServerSocket: public eSocket
        int okflag;
        std::string strRemoteHost;
 protected:
-       virtual void newConnection(int socket)=0;
+       virtual void newConnection(int socket) = 0;
+       int startListening(struct addrinfo *addr);
        int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);
        int listen(int sockfd, int backlog);
        int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
index 847fc7b..638ec6d 100644 (file)
@@ -3,6 +3,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <time.h>
+#include <string.h>
 #include <linux/serial.h>
 #include <lib/network/socket.h>
 
@@ -10,19 +11,19 @@ void eSocket::close()
 {
        if (writebuffer.empty())
        {
-               int wasconnected=(mystate==Connection) || (mystate==Closing);
-               rsn=0;
+               int wasconnected = (mystate == Connection) || (mystate == Closing);
+               rsn = 0;
                if (socketdesc >= 0)
                {
                        ::close(socketdesc);
-                       socketdesc=-1;
+                       socketdesc = -1;
                }
-               mystate=Invalid;
+               mystate = Invalid;
                if (wasconnected)
                        connectionClosed_();
        } else
        {
-               mystate=Closing;
+               mystate = Closing;
                rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
        }
 }
@@ -83,16 +84,16 @@ int eSocket::state()
        return mystate;
 }
 
-int eSocket::setSocket(int s, int iss, eMainloop *ml)
+int eSocket::setSocket(int s, int iss)
 {
-       socketdesc=s;
+       socketdesc = s;
        if (socketdesc < 0) return -1;
-       issocket=iss;
+       issocket = iss;
        fcntl(socketdesc, F_SETFL, O_NONBLOCK);
        last_break = -1;
 
        rsn = 0;
-       rsn=eSocketNotifier::create(ml, getDescriptor(),
+       rsn = eSocketNotifier::create(mainloop, getDescriptor(),
                eSocketNotifier::Read|eSocketNotifier::Hungup);
        CONNECT(rsn->activated, eSocket::notifier);
        return 0;
@@ -231,80 +232,96 @@ int eSocket::getDescriptor()
        return socketdesc;
 }
 
-int eSocket::connectToHost(std::string hostname, int port)
+int eSocket::connect(struct addrinfo *addr)
 {
-       sockaddr_in  serv_addr;
-       struct hostent *server;
        int res;
-
-       if (mystate == Invalid)
+       struct addrinfo *ptr = addr;
+       for (ptr = addr; ptr != NULL; ptr = ptr->ai_next)
        {
-               /* the socket has been closed, create a new socket descriptor */
-               int s=socket(AF_INET, SOCK_STREAM, 0);
-               mystate=Idle;
-               setSocket(s, 1, mainloop);
-       }
+               close();
+               if (setSocket(socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol), 1) < 0)
+               {
+                       continue;
+               }
+               mystate = Idle;
 
-       if(socketdesc < 0){
-               error_(errno);
-               return(-1);
+               res = ::connect(socketdesc, ptr->ai_addr, ptr->ai_addrlen);
+               if ((res < 0) && (errno != EINPROGRESS) && (errno != EINTR))
+               {
+                       error_(errno);
+                       continue;
+               }
+               if (res < 0)    // EINPROGRESS or EINTR
+               {
+                       rsn->setRequested(rsn->getRequested() | eSocketNotifier::Write);
+                       mystate = Connecting;
+                       return 0;
+               }
+               else
+               {
+                       mystate = Connection;
+                       connected_();
+                       return 1;
+               }
        }
-       server=gethostbyname(hostname.c_str());
-       if(server==NULL)
+       return -1;
+}
+
+int eSocket::connectToHost(std::string hostname, int port)
+{
+       int res;
+       struct addrinfo *addr = NULL;
+       struct addrinfo hints;
+       char portnumber[16];
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_UNSPEC; /* both ipv4 and ipv6 */
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_protocol = 0; /* any */
+#ifdef AI_ADDRCONFIG
+       hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG; /* only return ipv6 if we have an ipv6 address ourselves, and ipv4 if we have an ipv4 address ourselves */
+#else
+       hints.ai_flags = AI_NUMERICSERV; /* AI_ADDRCONFIG is not available */
+#endif
+       snprintf(portnumber, sizeof(portnumber), "%d", port);
+
+       if ((res = getaddrinfo(hostname.c_str(), portnumber, &hints, &addr)) || !addr)
        {
-               eDebug("[eSocket] can't resolve %s", hostname.c_str());
-               error_(errno);
-               return(-2);
+               eDebug("[eSocket] can't resolve %s (getaddrinfo: %s)", hostname.c_str(), gai_strerror(res));
+               return -2;
        }
-       bzero(&serv_addr, sizeof(serv_addr));
-       serv_addr.sin_family=AF_INET;
-       bcopy(server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length);
-       serv_addr.sin_port=htons(port);
-       res=::connect(socketdesc, (const sockaddr*)&serv_addr, sizeof(serv_addr));
-       if ((res < 0) && (errno != EINPROGRESS) && (errno != EINTR))
+
+       res = connect(addr);
+       if (res < 0)
        {
                eDebug("[eSocket] can't connect to host: %s", hostname.c_str());
-               close();
-               error_(errno);
-               return(-3);
-       }
-       if (res < 0)    // EINPROGRESS or EINTR
-       {
-               rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
-               mystate=Connecting;
-       } else
-       {
-               mystate=Connection;
-               connected_();
        }
-       return(0);
+       freeaddrinfo(addr);
+       return res;
 }
 
-eSocket::eSocket(eMainloop *ml, int domain): readbuffer(32768), writebuffer(32768), mainloop(ml)
+eSocket::eSocket(eMainloop *ml): readbuffer(32768), writebuffer(32768), mainloop(ml)
 {
-       int s=socket(domain, SOCK_STREAM, 0);
-#if 0
-       eDebug("[eSocket] initalized socket %d", socketdesc);
-#endif
-       mystate=Idle;
-       setSocket(s, 1, ml);
+       socketdesc = -1;
+       mystate = Invalid;
 }
 
 eSocket::eSocket(int socket, int issocket, eMainloop *ml): readbuffer(32768), writebuffer(32768), mainloop(ml)
 {
-       setSocket(socket, issocket, ml);
-       mystate=Connection;
+       setSocket(socket, issocket);
+       mystate = Connection;
 }
 
 eSocket::~eSocket()
 {
-       if(socketdesc>=0)
+       if (socketdesc >= 0)
        {
                ::close(socketdesc);
+               socketdesc = -1;
        }
 }
 
-eUnixDomainSocket::eUnixDomainSocket(eMainloop *ml) : eSocket(ml, AF_LOCAL)
+eUnixDomainSocket::eUnixDomainSocket(eMainloop *ml) : eSocket(ml)
 {
 }
 
@@ -318,39 +335,21 @@ eUnixDomainSocket::~eUnixDomainSocket()
 
 int eUnixDomainSocket::connectToPath(std::string path)
 {
-       sockaddr_un serv_addr_un;
        int res;
+       struct sockaddr_un serv_addr_un;
+       struct addrinfo addr;
 
-       if (mystate == Invalid)
-       {
-               /* the socket has been closed, create a new socket descriptor */
-               int s=socket(AF_LOCAL, SOCK_STREAM, 0);
-               mystate=Idle;
-               setSocket(s, 1, mainloop);
-       }
-
-       if(socketdesc < 0){
-               error_(errno);
-               return(-1);
-       }
-       bzero(&serv_addr_un, sizeof(serv_addr_un));
+       memset(&serv_addr_un, 0, sizeof(serv_addr_un));
        serv_addr_un.sun_family = AF_LOCAL;
        strcpy(serv_addr_un.sun_path, path.c_str());
-       res=::connect(socketdesc, (const sockaddr*)&serv_addr_un, sizeof(serv_addr_un));
-       if ((res < 0) && (errno != EINPROGRESS) && (errno != EINTR))
-       {
-               close();
-               error_(errno);
-               return(-3);
-       }
-       if (res < 0)    // EINPROGRESS or EINTR
-       {
-               rsn->setRequested(rsn->getRequested()|eSocketNotifier::Write);
-               mystate=Connecting;
-       } else
-       {
-               mystate=Connection;
-               connected_();
-       }
-       return(0);
+
+       memset(&addr, 0, sizeof(addr));
+       addr.ai_family = AF_LOCAL;
+       addr.ai_socktype = SOCK_STREAM;
+       addr.ai_protocol = 0; /* any */
+       addr.ai_addr = (struct sockaddr *)&serv_addr_un;
+       addr.ai_addrlen = sizeof(serv_addr_un);
+
+       res = connect(&addr);
+       return res;
 }
index da4aaff..99c9bbb 100644 (file)
@@ -29,14 +29,15 @@ protected:
        ePtr<eSocketNotifier> rsn;
        eMainloop *mainloop;
        virtual void notifier(int);
+       int connect(struct addrinfo *addr);
 public:
-       eSocket(eMainloop *ml, int domain = AF_INET);
+       eSocket(eMainloop *ml);
        eSocket(int socket, int issocket, eMainloop *ml);
        virtual ~eSocket();
        int connectToHost(std::string hostname, int port);
        int getDescriptor();
        int writeBlock(const char *data, unsigned int len);
-       int setSocket(int socketfd, int issocket, eMainloop *ml);
+       int setSocket(int socketfd, int issocket);
        int bytesToWrite();
        int readBlock(char *data, unsigned int maxlen);
        int bytesAvailable();