]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Socket.hh
win32 port of new sockets, with fixes
[chaz/yoink] / src / Moof / Socket.hh
index 4b67887416429835f0ebff9b0cee6afae17faf96..f1604663b038c37ff408061ca50db4d914ccd38a 100644 (file)
 #include <string>
 #include <vector>
 
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <wspiapi.h>
+#else
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#endif
 
 #include <Moof/Log.hh>
 #include <Moof/Packet.hh>
 #include <Moof/Thread.hh>
 
 
+#ifndef SO_NONBLOCK
+#define SO_NONBLOCK 1024
+#endif
+
+
 namespace Mf {
 
 
@@ -34,47 +50,27 @@ class SocketAddress
 {
 public:
 
-       SocketAddress(int type = SOCK_STREAM)
+       SocketAddress() :
+               mSize(0),
+               mType(0)
        {
-               mType = type;
-               memset(&mAddress.in4, 0, sizeof(mAddress.in4));
-               mAddress.in4.sin_family = AF_INET;
-               mAddress.in4.sin_port = 0;
-               mAddress.in4.sin_addr.s_addr = INADDR_ANY;
-               mName = "[any]";
-               mSize = sizeof(mAddress.in4);
+               mAddress.sa.sa_family = AF_UNSPEC;
+               mAddress.v4.sin_port = 0;
        }
 
-       SocketAddress(const std::string& name, const std::string& service,
-                       int type = SOCK_STREAM, int family = AF_INET)
+       SocketAddress(const std::string& service, const std::string& name,
+                       int type = SOCK_STREAM, int family = AF_UNSPEC)
        {
-               ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
-               ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
-
-               struct addrinfo hints;
-               memset(&hints, 0, sizeof(hints));
-               hints.ai_family = family;
-               hints.ai_socktype = type;
-               hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
-
-               struct addrinfo* addr;
-               int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
-                               service.length() > 0 ? service.c_str() : 0, &hints, &addr);
-               if (status != 0)
-               {
-                       Mf::logError("uh oh, that didn't work!");
-                       return;
-               }
-
-               mType = addr->ai_socktype;
-               memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
-               mName = addr->ai_canonname;
-               mSize = addr->ai_addrlen;
+               init(service, name, type, family);
+       }
 
-               freeaddrinfo(addr);
+       SocketAddress(const std::string& service,
+                       int type = SOCK_STREAM, int family = AF_UNSPEC)
+       {
+               init(service, type, family);
        }
 
-       SocketAddress(const std::string& name, const struct addrinfo* addr)
+       SocketAddress(const struct addrinfo* addr, const std::string& name)
        {
                mType = addr->ai_socktype;
                memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
@@ -88,11 +84,56 @@ public:
                mType = type;
                memcpy(&mAddress.sa, addr, size);
                mSize = size;
+               setNameFromAddress();
+       }
 
-               char name[128] = {'\0'};
-               inet_ntop(addr->sa_family, (struct sockaddr_in*)addr,
-                               name, sizeof(name));
-               mName = name;
+
+       static SocketAddress broadcast(const std::string& service)
+       {
+               return SocketAddress(service, "255.255.255.255", SOCK_DGRAM);
+       }
+
+
+       void init(const std::string& service, const std::string& name = "",
+                       int type = SOCK_STREAM, int family = AF_UNSPEC)
+       {
+               ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
+               ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
+
+               struct addrinfo hints;
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = family;
+               hints.ai_socktype = type;
+               hints.ai_flags = AI_PASSIVE;
+
+               struct addrinfo* addr;
+               int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
+                               service.c_str(), &hints, &addr);
+               if (status == 0)
+               {
+                       mType = addr->ai_socktype;
+                       memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
+                       mSize = addr->ai_addrlen;
+
+                       if (name != "") mName = name;
+                       else            setNameFromAddress();
+
+                       freeaddrinfo(addr);
+               }
+               else
+               {
+                       Mf::logWarning(gai_strerror(status));
+                       mType = 0;
+                       mSize = 0;
+                       mAddress.sa.sa_family = AF_UNSPEC;
+                       mAddress.v4.sin_port = 0;
+               }
+       }
+
+       void init(const std::string& service,
+                       int type = SOCK_STREAM, int family = AF_UNSPEC)
+       {
+               init(service, "", type, family);
        }
 
 
@@ -101,9 +142,14 @@ public:
                return mName;
        }
 
+       void setName(const std::string& name)
+       {
+               mName = name;
+       }
+
        unsigned short port() const
        {
-               return ntohs(mAddress.in4.sin_port);
+               return ntohs(mAddress.v4.sin_port);
        }
 
        int type() const
@@ -119,7 +165,7 @@ public:
 
        const struct sockaddr* address() const
        {
-               return &mAddress.sa;
+               return mSize != 0 ? &mAddress.sa : 0;
        }
 
        size_t size() const
@@ -128,45 +174,64 @@ public:
        }
 
 
-       static int resolve(const std::string& name, const std::string& service,
+       static int resolve(const std::string& service, const std::string& name,
                        int type, int family, std::vector<SocketAddress>& resolved)
        {
                ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
                ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
 
+               resolved.clear();
+
                struct addrinfo hints;
                memset(&hints, 0, sizeof(hints));
                hints.ai_family = family;
                hints.ai_socktype = type;
-               hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
+               hints.ai_flags = AI_PASSIVE;
 
                struct addrinfo* list;
                int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
                                service.length() > 0 ? service.c_str() : 0, &hints, &list);
-               if (status != 0) return -1;
-
-               resolved.clear();
-
-               const char* canonicalName = list->ai_canonname;
-               struct addrinfo* addr = list;
-               while (addr != 0)
+               if (status == 0)
+               {
+                       struct addrinfo* addr = list;
+                       while (addr != 0)
+                       {
+                               resolved.push_back(SocketAddress(addr, name));
+                               addr = addr->ai_next;
+                       }
+
+                       freeaddrinfo(list);
+               }
+               else
                {
-                       resolved.push_back(SocketAddress(canonicalName, addr));
-                       addr = addr->ai_next;
+                       Mf::logWarning(gai_strerror(status));
                }
 
-               freeaddrinfo(list);
                return 0;
        }
 
 
 private:
 
+       void setNameFromAddress()
+       {
+#if defined(_WIN32)
+               // inet_ntop was introduced in Vista
+               mName = inet_ntoa(mAddress.v4.sin_addr);
+#else
+               char name[INET6_ADDRSTRLEN] = {'\0'};
+               inet_ntop(mAddress.sa.sa_family, &mAddress.sa, name, sizeof(name));
+               mName = name;
+#endif
+       }
+
+
        union
        {
-               sockaddr                sa;
-               sockaddr_in             in4;
-               sockaddr_in6    in6;
+               sockaddr                        sa;
+               sockaddr_in                     v4;
+               sockaddr_in6            v6;
+               sockaddr_storage        storage;
        }                       mAddress;
        size_t          mSize;
        std::string     mName;
@@ -179,6 +244,7 @@ class Socket
 public:
 
        Socket(const SocketAddress& address) :
+               mFd(-1),
                mAddress(address)
        {
                mFd = socket(address.family(), address.type(), 0);
@@ -186,13 +252,17 @@ public:
 
        ~Socket()
        {
-               close(mFd);
+#if defined(_WIN32)
+               if (mFd != -1) closesocket(mFd);
+#else
+               if (mFd != -1) close(mFd);
+#endif
        }
 
 
        bool isConnected() const
        {
-               return false;
+               return mFd != -1;
        }
 
        const SocketAddress& address() const
@@ -201,6 +271,71 @@ public:
        }
 
 
+       int connect()
+       {
+               return ::connect(mFd, mAddress.address(), mAddress.size());
+       }
+
+       int bind()
+       {
+               return ::bind(mFd, mAddress.address(), mAddress.size());
+       }
+
+       int listen(int backlog = SOMAXCONN)
+       {
+               return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN);
+       }
+
+       Socket accept()
+       {
+               return Socket(mFd);
+       }
+
+
+       int set(int option, int value = 0)
+       {
+               if (option == SO_NONBLOCK)
+               {
+#ifdef HAVE_FCNTL
+                       int flags = fcntl(mFd, F_GETFL);
+                       return fcntl(mFd, F_SETFL, (value ? O_NONBLOCK : 0) | flags);
+#else
+                       return ioctl(mFd, FIONBIO, value);
+#endif
+               }
+               return setsockopt(mFd, SOL_SOCKET, option, &value, sizeof(value));
+       }
+
+       int set(int option, const std::string& value)
+       {
+               return setsockopt(mFd, SOL_SOCKET, option,
+                               value.c_str(), value.length());
+       }
+
+       int get(int option, int& value)
+       {
+               if (option == SO_NONBLOCK)
+               {
+#ifdef HAVE_FCNTL
+                       int flags = fcntl(mFd, F_GETFL);
+                       return flags & O_NONBLOCK;
+#else
+                       return ioctl(mFd, FIONBIO, &value);
+#endif
+               }
+               socklen_t optlen = sizeof(value);
+               return getsockopt(mFd, SOL_SOCKET, option, &value, &optlen);
+       }
+
+       int get(int option, std::string& value)
+       {
+               char str[64] = {'\0'};
+               socklen_t optlen = sizeof(str);
+               int result = getsockopt(mFd, SOL_SOCKET, option, &str, &optlen);
+               value = str;
+               return result;
+       }
+
        void write(const Packet& packet)
        {
                write(mAddress, packet);
@@ -233,13 +368,28 @@ public:
                int size = recvfrom(mFd, buffer, sizeof(buffer), 0,
                                &addr.sa, &length);
 
-               address = SocketAddress(&addr.sa, length, SOCK_DGRAM);
+               address = SocketAddress(&addr.sa, length, mAddress.type());
                return Packet(buffer, size);
        }
 
 
 private:
 
+       Socket(int fd)
+       {
+               // for accepting a socket from fd
+               union
+               {
+                       sockaddr                        sa;
+                       sockaddr_storage        storage;
+               } addr;
+               socklen_t length = sizeof(addr);
+
+               mFd = ::accept(fd, &addr.sa, &length);
+               mAddress = SocketAddress(&addr.sa, length);
+       }
+
+
        int                             mFd;
        SocketAddress   mAddress;
 };
@@ -249,12 +399,12 @@ class ResolverTask : public ThreadedTask
 {
 public:
 
-       ResolverTask(const std::string& name, const std::string& service,
+       ResolverTask(const std::string& service, const std::string& name,
                        int type = SOCK_STREAM, int family = AF_UNSPEC) :
                mIsDone(false)
        {
                mFunction = boost::bind(&ResolverTask::resolve,
-                               this, name, service, type, family);
+                               this, service, name, type, family);
        }
 
 
@@ -277,10 +427,10 @@ public:
 
 private:
 
-       int resolve(const std::string& name, const std::string& service,
+       int resolve(const std::string& service, const std::string& name,
                        int type, int family)
        {
-               int status = SocketAddress::resolve(name, service,
+               int status = SocketAddress::resolve(service, name,
                                type, family, mAddressList);
                mIsDone = true;
                return status;
This page took 0.028554 seconds and 4 git commands to generate.