exception-aware packets; other misc socket changes
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Fri, 21 May 2010 06:10:25 +0000 (00:10 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Fri, 21 May 2010 06:10:25 +0000 (00:10 -0600)
link.sh
src/Moof/Packet.cc
src/Moof/Packet.hh
src/Moof/Service.cc
src/Moof/Service.hh
src/Moof/Socket.hh

diff --git a/link.sh b/link.sh
index 7db3de022997360ecb373d5527c464825bfed4d2..d3a739c519e110d7584a382e3f42dc44549331b3 100755 (executable)
--- a/link.sh
+++ b/link.sh
@@ -6,9 +6,10 @@
 #
 # You shouldn't call this directly; instead, use the configure script's
 # --enable-link-sh option and run make normally.  This isn't enabled by
-# default because there is the potential for runtime linking problems.  If
-# you have a newer version of GCC, you should prefer the --as-needed linker
-# flag over this method, though they both should accomplish the same thing.
+# default because there is the potential for runtime linking problems on
+# some platforms.  If you have a newer version of GCC, you should prefer
+# the --as-needed linker flag over this method, though they both should
+# accomplish the same thing.
 #
 # This script was adapted from some public domain code written by Bram
 # Moolenaar for Vim.  The only input needed is the link command in the
index 842d6c1d9e9406d89dcf488b61b5df6f8b0a8cb1..bb8fcc7b88bb9a2413526c9a40ab8164b0b7e7e7 100644 (file)
@@ -100,6 +100,7 @@ Packet::Packet(size_t size) :
        mSize(size),
        mR(0),
        mW(0),
+       mOriginalW(0),
        mBoolR(0),
        mBoolW(0),
        mBoolNumR(0),
@@ -110,12 +111,14 @@ Packet::Packet(const char* data, size_t size) :
        mSize(size),
        mR(0),
        mW(size),
+       mOriginalW(size),
        mBoolR(0),
        mBoolW(0),
        mBoolNumR(0),
        mBoolNumW(0)
 {
        if (mBuffer) memcpy(mBuffer, data, size);
+       else throw std::length_error("out of memory");
 }
 
 
@@ -124,12 +127,14 @@ Packet::Packet(const Packet& copy) :
        mSize(copy.mSize),
        mR(copy.mR),
        mW(copy.mW),
+       mOriginalW(copy.mOriginalW),
        mBoolR(copy.mBoolR),
        mBoolW(copy.mBoolW),
        mBoolNumR(copy.mBoolNumR),
        mBoolNumW(copy.mBoolNumW)
 {
        if (mBuffer) memcpy(mBuffer, copy.mBuffer, mSize);
+       else throw std::length_error("out of memory");
 }
 
 Packet& Packet::operator=(const Packet& copy)
@@ -140,11 +145,13 @@ Packet& Packet::operator=(const Packet& copy)
        mSize = copy.mSize;
        mR = copy.mR;
        mW = copy.mW;
+       mOriginalW = copy.mOriginalW;
        mBoolR = copy.mBoolR;
        mBoolW = copy.mBoolW;
        mBoolNumR = copy.mBoolNumR;
        mBoolNumW = copy.mBoolNumW;
        if (mBuffer) memcpy(mBuffer, copy.mBuffer, mSize);
+       else throw std::length_error("out of memory");
        return *this;
 }
 
@@ -163,7 +170,7 @@ Packet& Packet::operator<<(bool value)
                mBoolW = mW;
 
                unsigned char byte = 0;
-               if (write(&byte, 1) == 0) return *this;
+               if (write(&byte, 1) == 0) throw std::length_error("out of memory");
        }
 
        if (value) mBuffer[mBoolW] |= (1 << bit);
@@ -196,28 +203,40 @@ Packet& Packet::operator<<(int64_t value)
 
 Packet& Packet::operator<<(uint8_t value)
 {
-       write(&value, sizeof(value));
+       if (write(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::length_error("out of memory");
+       }
        return *this;
 }
 
 Packet& Packet::operator<<(uint16_t value)
 {
        value = htons(value);
-       write(&value, sizeof(value));
+       if (write(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::length_error("out of memory");
+       }
        return *this;
 }
 
 Packet& Packet::operator<<(uint32_t value)
 {
        value = htonl(value);
-       write(&value, sizeof(value));
+       if (write(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::length_error("out of memory");
+       }
        return *this;
 }
 
 Packet& Packet::operator<<(uint64_t value)
 {
        value = htonll(value);
-       write(&value, sizeof(value));
+       if (write(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::length_error("out of memory");
+       }
        return *this;
 }
 
@@ -226,7 +245,10 @@ Packet& Packet::operator<<(float value)
        // XXX: assumes the ieee-754
        uint32_t* integer = reinterpret_cast<uint32_t*>(&value);
        *integer = htonl(*integer);
-       write(integer, sizeof(value));
+       if (write(integer, sizeof(value)) != sizeof(value))
+       {
+               throw std::length_error("out of memory");
+       }
        return *this;
 }
 
@@ -235,7 +257,10 @@ Packet& Packet::operator<<(double value)
        // XXX: assumes the ieee-754
        uint64_t* integer = reinterpret_cast<uint64_t*>(&value);
        *integer = htonll(*integer);
-       write(integer, sizeof(value));
+       if (write(integer, sizeof(value)) != sizeof(value))
+       {
+               throw std::length_error("out of memory");
+       }
        return *this;
 }
 
@@ -269,7 +294,7 @@ Packet& Packet::operator>>(bool& value)
                mBoolR = mR;
 
                unsigned char byte = 0;
-               if (read(&byte, 1) == 0) return *this;
+               if (read(&byte, 1) == 0) throw std::out_of_range("end of packet");
        }
 
        value = 1 & (mBuffer[mBoolR] >> bit);
@@ -300,27 +325,39 @@ Packet& Packet::operator>>(int64_t& value)
 
 Packet& Packet::operator>>(uint8_t& value)
 {
-       read(&value, sizeof(value));
+       if (read(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::out_of_range("end of packet");
+       }
        return *this;
 }
 
 Packet& Packet::operator>>(uint16_t& value)
 {
-       read(&value, sizeof(value));
+       if (read(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::out_of_range("end of packet");
+       }
        value = ntohs(value);
        return *this;
 }
 
 Packet& Packet::operator>>(uint32_t& value)
 {
-       read(&value, sizeof(value));
+       if (read(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::out_of_range("end of packet");
+       }
        value = ntohl(value);
        return *this;
 }
 
 Packet& Packet::operator>>(uint64_t& value)
 {
-       read(&value, sizeof(value));
+       if (read(&value, sizeof(value)) != sizeof(value))
+       {
+               throw std::out_of_range("end of packet");
+       }
        value = ntohll(value);
        return *this;
 }
@@ -329,7 +366,10 @@ Packet& Packet::operator>>(float& value)
 {
        // XXX: assumes the ieee-754
        uint32_t* integer = reinterpret_cast<uint32_t*>(&value);
-       read(integer, sizeof(value));
+       if (read(integer, sizeof(value)) != sizeof(value))
+       {
+               throw std::out_of_range("end of packet");
+       }
        *integer = htonl(*integer);
        return *this;
 }
@@ -338,7 +378,10 @@ Packet& Packet::operator>>(double& value)
 {
        // XXX: assumes the ieee-754
        uint64_t* integer = reinterpret_cast<uint64_t*>(&value);
-       read(integer, sizeof(value));
+       if (read(integer, sizeof(value)) != sizeof(value))
+       {
+               throw std::out_of_range("end of packet");
+       }
        *integer = htonll(*integer);
        return *this;
 }
@@ -363,5 +406,16 @@ void Packet::clear()
 }
 
 
+void Packet::reset()
+{
+       mR = 0;
+       mW = mOriginalW;
+       mBoolR = 0;
+       mBoolW = 0;
+       mBoolNumR = 0;
+       mBoolNumW = 0;
+}
+
+
 } // namespace Mf
 
index 1a5e42fed31bc696cae6913194f535d268e0a99a..8bcefffc95b0b86f9280b7f908e52f0b7b8448eb 100644 (file)
@@ -9,10 +9,16 @@
 *
 **************************************************************************/
 
+/**
+ * \file Packet.hh
+ * Classes for building and interpreting datagram packets.
+ */
+
 #ifndef _MOOF_PACKET_HH_
 #define _MOOF_PACKET_HH_
 
 #include <cstring>
+#include <stdexcept>
 #include <string>
 #include <vector>
 
 namespace Mf {
        
 
+/**
+ * Represents a packet of serialized variables ready for transfer over the
+ * network.  This method is most suitable for representing datagram
+ * packets, but it may also be useful for seralizing data for persistent
+ * state storage.  The semantics are similar to that of a FIFO queue or
+ * stream where packets are written and read by inserting and extracting
+ * variables to and from the packet, although the actual order of the
+ * variables in the buffer may be different.  At any time, a pointer to a
+ * buffer and the size of the buffer can be retrieved.  This class also
+ * handles endian differences by serializing variables in network byte
+ * order (big endian).
+ */
 class Packet
 {
 public:
 
+       /**
+        * Construct a packet with an initial capacity.
+        * \param capacity Initial capacity of the packet.
+        */
        Packet(size_t size = PAGE_SIZE);
-       Packet(const char* data, size_t size);
-
-       Packet(const Packet& copy);
-       Packet& operator=(const Packet& copy);
 
-       ~Packet();
+       /**
+        * Construct a packet with some bytes from a buffer.  The bytes will be
+        * copied into the packet, so you don't need to keep the original
+        * buffer.
+        * \param data The bytes.
+        * \param size The number of bytes.
+        */
+       Packet(const char* data, size_t size);
 
+       /**
+        * Insert a variable into the packet, serializing it.   This usually
+        * increases the size of the packet by the size of the data type.
+        * \param value The value to insert.
+        * \return This.
+        */
        Packet& operator<<(bool value);
        Packet& operator<<(int8_t  value);
        Packet& operator<<(int16_t value);
@@ -49,8 +80,21 @@ public:
        Packet& operator<<(float value);
        Packet& operator<<(double value);
 
+       /**
+        * Write some bytes to the packet.
+        * \param bytes The bytes.
+        * \param size The number of bytes.
+        * return The number of bytes actually written.
+        */
        size_t write(const void* bytes, size_t size);
 
+
+       /**
+        * Extract a variable from the packet.  This usually decreases the size
+        * of the packet by the size of the data type.
+        * \param value Reference to the variable to extract.
+        * \return This.
+        */
        Packet& operator>>(bool& value);
        Packet& operator>>(int8_t&  value);
        Packet& operator>>(int16_t& value);
@@ -63,23 +107,57 @@ public:
        Packet& operator>>(float& value);
        Packet& operator>>(double& value);
 
+       /**
+        * Read some bytes from the packet.
+        * \param bytes The buffer to hold the bytes read.
+        * \param size The size of the read buffer.
+        * \return The number of bytes actually read.
+        */
        size_t read(void* bytes, size_t size);
 
 
+       /**
+        * Clear the contents of the packet, setting the size of the packet to
+        * zero.
+        */
        void clear();
 
 
+       /**
+        * Reset the read/write markers to their initial positions, putting the
+        * packet in the state it was at right after construction.
+        */
+       void reset();
+
+
+       /**
+        * Get a pointer to an internal structure holding the serialized bytes
+        * of the packet.
+        * return The pointer.
+        */
        const char* bytes() const
        {
                return mBuffer + mR;
        }
 
+       /**
+        * Get the size of the buffer holding the serialized bytes of the
+        * packet.
+        * \return The number of bytes.
+        */
        size_t size() const
        {
                return mW - mR;
        }
 
 
+       // The rest of this stuff is just to implement correct copy semantics.
+
+       Packet(const Packet& copy);
+       Packet& operator=(const Packet& copy);
+       ~Packet();
+
+
 private:
 
        char*   mBuffer;
@@ -87,6 +165,7 @@ private:
 
        size_t  mR;
        size_t  mW;
+       size_t  mOriginalW;
 
        size_t  mBoolR;
        size_t  mBoolW;
@@ -99,15 +178,22 @@ inline Packet& operator<<(Packet& packet, const char* value)
 {
        uint16_t length = strlen(value);
        packet << length;
-       packet.write(value, length);
+       if (packet.write(value, length) != length)
+       {
+               throw std::length_error("out of memory");
+       }
        return packet;
 }
 
 template <class T>
 inline Packet& operator<<(Packet& packet, const std::basic_string<T>& value)
 {
-       packet << (uint16_t)value.length();
-       packet.write(value.data(), value.length() * sizeof(T));
+       packet << static_cast<uint16_t>(value.length());
+       size_t numBytes = value.length() * sizeof(T);
+       if (packet.write(value.data(), numBytes) != numBytes)
+       {
+               throw std::length_error("out of memory");
+       }
        return packet;
 }
 
@@ -118,8 +204,12 @@ inline Packet& operator>>(Packet& packet, std::basic_string<T>& value)
        packet >> length;
 
        T str[length];
-       size_t charsRead = packet.read(str, length * sizeof(T));
-       value.assign(str, charsRead);
+       size_t numBytes = length * sizeof(T);
+       if (packet.read(str, numBytes) != numBytes)
+       {
+               throw std::out_of_range("end of packet");
+       }
+       value.assign(str, length);
        return packet;
 }
 
@@ -127,7 +217,7 @@ inline Packet& operator>>(Packet& packet, std::basic_string<T>& value)
 template <class T>
 inline Packet& operator<<(Packet& packet, const std::vector<T>& value)
 {
-       packet << (uint16_t)value.size();
+       packet << static_cast<uint16_t>(value.size());
        typename std::vector<T>::const_iterator it;
        for (it = value.begin(); it != value.end(); ++it)
        {
index a5fae0f33862c05fd0d251e97593baca008ac881..400006ba2eb6ee59a4e4dad2391b90dd3a55240a 100644 (file)
 **************************************************************************/
 
 #include "Service.hh"
+#include "Socket.hh"
+
+
+#define SOLICIT  0x1234ABCD
+#define RESPONSE 0xABCD1234
 
 
 namespace Mf {
 
 
-ServiceFinder::ServiceFinder(const std::string& service, int type)
+int Service::handlePacket(SocketMultiplexer& sock,
+                                                 Packet& packet,
+                                                 const SocketAddress& address)
 {
+       uint32_t magic = 0;
+
+       try
+       {
+               packet >> magic;
+       }
+       catch (...)
+       {
+               return -1;
+       }
+
+       if (magic == SOLICIT)
+       {
+               Packet out;
+               out << RESPONSE << mAddress.service() << mText;
+               sock.socket().write(out);
+               return 0;
+       }
+       return -1;
 }
 
-void ServiceFinder::update(Scalar t, Scalar dt)
+int ServiceFinder::handlePacket(SocketMultiplexer& sock,
+                                                               Packet& packet,
+                                                               const SocketAddress& address)
+{
+       try
+       {
+               uint32_t magic;
+               packet >> magic;
+               if (magic == RESPONSE)
+               {
+                       std::string service;
+                       std::string     text;
+
+                       packet >> service >> text;
+                       if (service == mService)
+                       {
+                               mServices.push_back(Service(address, text));
+                               return 0;
+                       }
+               }
+       }
+       catch (...)
+       {
+       }
+
+       return -1;
+}
+
+ServiceFinder::ServiceFinder(const std::string& service, int type)
 {
 }
 
index 7c5e6b7b7b440ad4ba9f14fb6ec519eb230633c6..77cee183f9b3346c8563dbafff75105b00e9ee76 100644 (file)
@@ -9,6 +9,11 @@
 *
 **************************************************************************/
 
+/**
+ * \file Service.hh
+ * Classes for publishing and finding network services.
+ */
+
 #ifndef _MOOF_SERVICE_HH_
 #define _MOOF_SERVICE_HH_
 
@@ -36,29 +41,39 @@ public:
        Service(const SocketAddress& address, const std::string& text);
 
 
+       /**
+        * Publish the service on the local network.
+        */
+       void publish();
+
+       void stop();
+
+
        /**
         * Get the host address.
         * \return The address.
         */
-       const SocketAddress& address() const;
+       const SocketAddress& address() const
+       {
+               return mAddress;
+       }
 
        /**
         * Get the service information.
         * \return The service information as a string.
         */
-       const std::string& text() const;
-
-
-       /**
-        * Publish the service on the network.
-        */
-       void publish();
-
-       void update(Scalar t, Scalar dt);
+       const std::string& text() const
+       {
+               return mText;
+       }
 
 
 private:
 
+       int handlePacket(SocketMultiplexer& sock,
+                                        Packet& packet,
+                                        const SocketAddress& address);
+
        SocketAddress   mAddress;
        std::string             mText;
 };
@@ -70,8 +85,6 @@ public:
 
        ServiceFinder(const std::string& service, int type = SOCK_STREAM);
 
-       void update(Scalar t, Scalar dt);
-
 
        const std::vector<Service>& services() const
        {
@@ -81,7 +94,12 @@ public:
 
 private:
 
-       std::vector<Service> mServices;
+       int handlePacket(SocketMultiplexer& sock,
+                                        Packet& packet,
+                                        const SocketAddress& address);
+
+       std::string                             mService;
+       std::vector<Service>    mServices;
 };
 
 
index 2411cc2e90a0c4c28c16ebf5bbe103fa255cf049..da8132acf62657d9cd688d03e09dd0f165ce487d 100644 (file)
@@ -9,11 +9,17 @@
 *
 **************************************************************************/
 
+/**
+ * \file Network.hh
+ * Network-related classes, including a reinterpreted sockets API.
+ */
+
 #ifndef _MOOF_SOCKET_HH_
 #define _MOOF_SOCKET_HH_
 
 #include <algorithm>
 #include <cstring>
+#include <iostream>
 #include <sstream>
 #include <string>
 #include <vector>
@@ -70,16 +76,16 @@ public:
         * Construct an address with a specified host.  The address can be used
         * to connect to a host.
         * \param service The service name or port number.
-        * \param host The numeric IP address of the host.
+        * \param name The numeric IP address of the host.
         * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
         * \param family The family; can be AF_INET or AF_INET6.
         */
        SocketAddress(const std::string& service,
-                                 const std::string& host,
+                                 const std::string& name,
                                  int type = SOCK_STREAM,
                                  int family = AF_UNSPEC)
        {
-               init(service, host, type, family);
+               init(service, name, type, family);
        }
 
        /**
@@ -105,7 +111,7 @@ public:
                mType(addr->ai_socktype)
        {
                memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
-               getServiceAndHostName(mService, mHost);
+               getNameAndService(mService, mName);
        }
 
        /**
@@ -121,7 +127,7 @@ public:
                mType(type)
        {
                memcpy(&mAddr.sa, addr, size);
-               getServiceAndHostName(mService, mHost);
+               getNameAndService(mService, mName);
        }
 
 
@@ -149,16 +155,16 @@ public:
         * Initialize the address with a specified host.  The address can be
         * used to connect to a host.
         * \param service The service name or port number.
-        * \param host The numeric IP address of the host.
+        * \param name The numeric IP address of the host.
         * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
         * \param family The family; can be AF_INET or AF_INET6.
         */
        void init(const std::string& service,
-                         const std::string& host,
+                         const std::string& name,
                          int type = SOCK_STREAM,
                          int family = AF_UNSPEC)
        {
-               struct addrinfo* addr = resolve(service.c_str(), host.c_str(),
+               struct addrinfo* addr = resolve(service.c_str(), name.c_str(),
                                                                                type, family,
                                                                                AI_ADDRCONFIG | AI_NUMERICHOST | AI_V4MAPPED);
                if (addr)
@@ -168,7 +174,7 @@ public:
                        memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
 
                        mService = service;
-                       mHost = host;
+                       mName = name;
 
                        freeaddrinfo(addr);
                }
@@ -202,7 +208,7 @@ public:
                        memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
 
                        mService = service;
-                       getHost(mHost);
+                       getName(mName);
 
                        freeaddrinfo(addr);
                }
@@ -231,9 +237,9 @@ public:
         * the address, or a resolved numeric host if none was used.
         * \return The host.
         */
-       const std::string& host() const
+       const std::string& name() const
        {
-               return mHost;
+               return mName;
        }
 
        /**
@@ -289,19 +295,19 @@ public:
         * method may take some time to return.  Use the ResolveTask class to
         * resolve addresses asynchronously.
         * \param service The service name or port number.
-        * \param host The name of the local or remote host.
+        * \param name The name of the local or remote host.
         * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
         * \param family The family; can be AF_INET or AF_INET6.
         * \param resolved The list to be filled with addresses.
         * \return 0 on success, -1 on error.
         */
        static int resolve(const std::string& service,
-                                          const std::string& host,
+                                          const std::string& name,
                                           int type,
                                           int family,
                                           std::vector<SocketAddress>& resolved)
        {
-               struct addrinfo* list = resolve(service.c_str(), host.c_str(),
+               struct addrinfo* list = resolve(service.c_str(), name.c_str(),
                                                                                type, family,
                                                                                AI_ADDRCONFIG | AI_V4MAPPED);
                int result = collectAddresses(list, resolved);
@@ -332,6 +338,68 @@ public:
        }
 
 
+       /**
+        * Resolve the hostname of the address.  The default behavior is to
+        * avoid a reverse lookup by giving the numeric address.  You can
+        * change that behavior with the getnameinfo flags.
+        * \param name The place to store the hostname or IP address.
+        * \param flags The getnameinfo flags.
+        */
+       void getName(std::string& name, int flags = NI_NUMERICHOST)
+       {
+               char node[256] = {'\0'};
+               int result = getnameinfo(&mAddr.sa, mSize,
+                                                                node, sizeof(node),
+                                                                0, 0,
+                                                                flags);
+               if (result == 0) name.assign(node);
+       }
+
+       /**
+        * Resolve the service name of the address.
+        * \param service The place to store the service name or port number.
+        * \param flags The getnameinfo flags.
+        */
+       void getService(std::string& service, int flags)
+       {
+               flags |= mType == SOCK_DGRAM ? NI_DGRAM : 0;
+
+               char serv[64] = {'\0'};
+               int result = getnameinfo(&mAddr.sa, mSize,
+                                                                0, 0,
+                                                                serv, sizeof(serv),
+                                                                flags);
+               if (result == 0) service.assign(serv);
+       }
+
+       /**
+        * Resolve the service and hostname of the address.  The default
+        * behavior is to avoid a reverse lookup by giving the numeric address.
+        * You can change that behavior with the getnameinfo flags.
+        * \param name The place to store the hostname or IP address.
+        * \param service The place to store the service name or port number.
+        * \param flags The getnameinfo flags.
+        */
+       void getNameAndService(std::string& name,
+                                                  std::string& service,
+                                                  int flags = NI_NUMERICHOST)
+       {
+               flags |= mType == SOCK_DGRAM ? NI_DGRAM : 0;
+
+               char serv[64] = {'\0'};
+               char node[256] = {'\0'};
+               int result = getnameinfo(&mAddr.sa, mSize,
+                                                                node, sizeof(node),
+                                                                serv, sizeof(serv),
+                                                                flags);
+               if (result == 0)
+               {
+                       service.assign(serv);
+                       name.assign(node);
+               }
+       }
+
+
 private:
 
        static struct addrinfo* resolve(const char* service,
@@ -383,43 +451,6 @@ private:
        }
 
 
-       void getService(std::string& service)
-       {
-               char value[64] = {'\0'};
-               int result = getnameinfo(&mAddr.sa, mSize,
-                                                                0, 0,
-                                                                value, sizeof(value),
-                                                                (mType == SOCK_DGRAM) ? NI_DGRAM : 0);
-               if (result == 0) service.assign(value);
-       }
-
-       void getHost(std::string& host)
-       {
-               char value[256] = {'\0'};
-               int result = getnameinfo(&mAddr.sa, mSize,
-                                                                value, sizeof(value),
-                                                                0, 0,
-                                                                NI_NUMERICHOST);
-               if (result == 0) host.assign(value);
-       }
-
-       void getServiceAndHostName(std::string& service, std::string& host)
-       {
-               char serv[64] = {'\0'};
-               char node[256] = {'\0'};
-               int result = getnameinfo(&mAddr.sa, mSize,
-                                                                node, sizeof(node),
-                                                                serv, sizeof(serv),
-                                                                NI_NUMERICHOST |
-                                                                ((mType == SOCK_DGRAM) ? NI_DGRAM : 0));
-               if (result == 0)
-               {
-                       service.assign(serv);
-                       host.assign(node);
-               }
-       }
-
-
        union
        {
                sockaddr                        sa;
@@ -429,7 +460,7 @@ private:
        size_t          mSize;
        int                     mType;
 
-       std::string     mHost;
+       std::string     mName;
        std::string mService;
 };
 
@@ -476,14 +507,16 @@ public:
         * Construct a socket with a specified host.  The socket can be used to
         * connect to a host.
         * \param service The service name or port number.
-        * \param host The numeric IP address of the host.
+        * \param name The numeric IP address of the host.
         * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
         * \param family The family; can be AF_INET or AF_INET6.
         * \param flags The socket options.
         */
-       Socket(const std::string& service, const std::string& name,
-                       int type = SOCK_STREAM, int family = AF_UNSPEC,
-                       int flags = 0) :
+       Socket(const std::string& service,
+                  const std::string& name,
+                  int type = SOCK_STREAM,
+                  int family = AF_UNSPEC,
+                  int flags = 0) :
                mImpl(SocketAddress(service, name, type, family), flags) {}
 
        /**
@@ -494,8 +527,10 @@ public:
         * \param family The family; can be AF_INET or AF_INET6.
         * \param flags The socket options.
         */
-       Socket(const std::string& service, int type = SOCK_STREAM,
-                       int family = AF_UNSPEC, int flags = 0) :
+       Socket(const std::string& service,
+                  int type = SOCK_STREAM,
+                  int family = AF_UNSPEC,
+                  int flags = 0) :
                mImpl(SocketAddress(service, type, family), flags) {}
 
 
@@ -595,34 +630,25 @@ public:
         * Set an integer socket option.
         * \param option The option to set.
         * \param value The new value.
+        * \param level The layer to handle the option.
         * \return 0 on success, -1 on failure.
         */
-       int set(int option, int value = 0)
+       template <class T>
+       int set(int option, const T& value, int level = SOL_SOCKET)
        {
-               if (option == SO_NONBLOCK)
-               {
-#ifdef HAVE_FCNTL
-                       int flags = fcntl(mImpl.fd, F_GETFL);
-                       return fcntl(mImpl.fd,
-                                                F_SETFL,
-                                                flags | (value ? O_NONBLOCK : 0));
-#else
-                       return ioctl(mImpl.fd, FIONBIO, value);
-#endif
-               }
-               return setsockopt(mImpl.fd, SOL_SOCKET, option,
-                                                 &value, sizeof(value));
+               return setsockopt(mImpl.fd, level, option, &value, sizeof(value));
        }
 
        /**
         * Set a string socket option.
         * \param option The option to set.
         * \param value The new value.
+        * \param level The layer to handle the option.
         * \return 0 on success, -1 on failure.
         */
-       int set(int option, const std::string& value)
+       int set(int option, const std::string& value, int level = SOL_SOCKET)
        {
-               return setsockopt(mImpl.fd, SOL_SOCKET, option,
+               return setsockopt(mImpl.fd, level, option,
                                                  value.data(), value.length());
        }
 
@@ -630,40 +656,58 @@ public:
         * Get an integer socket option.
         * \param option The option to set.
         * \param value The new value.
+        * \param level The layer to handle the option.
         * \return 0 on success, -1 on failure.
         */
-       int get(int option, int& value)
+       template <class T>
+       int get(int option, T& value, int level = SOL_SOCKET) const
        {
-               if (option == SO_NONBLOCK)
-               {
-#ifdef HAVE_FCNTL
-                       int flags = fcntl(mImpl.fd, F_GETFL);
-                       return flags & O_NONBLOCK;
-#else
-                       return ioctl(mImpl.fd, FIONBIO, &value);
-#endif
-               }
-               socklen_t optlen = sizeof(value);
-               return getsockopt(mImpl.fd, SOL_SOCKET, option, &value, &optlen);
+               int size = sizeof(value);
+               return getsockopt(mImpl.fd, level, option, &value, &size);
        }
 
        /**
         * Get a string socket option.
         * \param option The option to set.
         * \param value The new value.
+        * \param level The layer to handle the option.
         * \return 0 on success, -1 on failure.
         */
-       int get(int option, std::string& value)
+       int get(int option, std::string& value, int level = SOL_SOCKET) const
        {
-               char str[256] = {'\0'};
-               socklen_t optlen = sizeof(str);
-               int result = getsockopt(mImpl.fd, SOL_SOCKET, option,
-                                                               &str, &optlen);
-               value = str;
+               char            str[256] = {'\0'};
+               socklen_t       size = sizeof(str);
+
+               int result = getsockopt(mImpl.fd, level, option, &str, &size);
+               value.assign(str, size);
                return result;
        }
 
 
+       void setBlocking(bool isBlocking)
+       {
+               int value = isBlocking;
+#ifdef HAVE_FCNTL
+               int flags = fcntl(mImpl.fd, F_GETFL);
+               fcntl(mImpl.fd, F_SETFL, flags | (value ? O_NONBLOCK : 0));
+#else
+               ioctl(mImpl.fd, FIONBIO, value);
+#endif
+       }
+
+       bool isBlocking() const
+       {
+#ifdef HAVE_FCNTL
+               int flags = fcntl(mImpl.fd, F_GETFL);
+               return flags & O_NONBLOCK;
+#else
+               int value;
+               ioctl(mImpl.fd, FIONBIO, &value);
+               return value;
+#endif
+       }
+
+
        /**
         * Write some bytes to the socket.  Use this for connected sockets.
         * \param bytes The bytes.
@@ -858,6 +902,68 @@ private:
 };
 
 
+class SocketMultiplexer
+{
+public:
+
+       typedef boost::function<int(SocketMultiplexer&,
+                                                               Packet&,
+                                                               const SocketAddress&)> Function;
+
+       SocketMultiplexer(Socket sock) :
+               mSocket(sock) {}
+
+
+       void setSocket(Socket sock)
+       {
+               Mutex::ScopedLock lock(mMutex);
+               mSocket = sock;
+       }
+
+       Socket& socket()
+       {
+               return mSocket;
+       }
+
+
+       std::vector<Function>& protocols()
+       {
+               return mProtocols;
+       }
+
+
+       void update(Scalar t, Scalar dt)
+       {
+               SocketAddress   address;
+               Packet                  packet;
+               ssize_t                 bytes = mSocket.read(packet, address);
+
+               if (bytes > 0)
+               {
+                       std::vector<Function>::iterator it;
+                       for (it = mProtocols.begin(); it < mProtocols.end(); ++it)
+                       {
+                               packet.reset();
+                               if ((*it)(*this, packet, address)) break;
+                       }
+               }
+       }
+
+
+       int background()
+       {
+               return 0;
+       }
+
+
+private:
+
+       Socket                                  mSocket;
+       std::vector<Function>   mProtocols;
+       Mutex                                   mMutex;
+};
+
+
 /**
  * An asynchronous task to resolve addresses.
  */
@@ -868,18 +974,18 @@ public:
        /**
         * Construct a resolver task from a service and hostname.
         * \param service Server name or port number.
-        * \param host The hostname or numeric address.
+        * \param name The hostname or numeric address.
         * \param type The type of communication.
         * \param family The requested protocol family.
         */
        ResolverTask(const std::string& service,
-                                const std::string& host,
+                                const std::string& name,
                                 int type = SOCK_STREAM,
                                 int family = AF_UNSPEC) :
                mIsDone(false)
        {
                mFunction = boost::bind(&ResolverTask::resolve,
-                                                               this, service, host, type, family);
+                                                               this, service, name, type, family);
        }
 
 
@@ -920,11 +1026,11 @@ public:
 private:
 
        int resolve(const std::string& service,
-                               const std::string& host,
+                               const std::string& name,
                                int type,
                                int family)
        {
-               int status = SocketAddress::resolve(service, host,
+               int status = SocketAddress::resolve(service, name,
                                                                                        type, family,
                                                                                        mAddressList);
                mIsDone = true;
@@ -938,6 +1044,19 @@ private:
 };
 
 
+std::ostream& operator<<(std::ostream& stream, const SocketAddress& addr)
+{
+       stream << addr.name() << ":" << addr.service();
+       return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const Socket& sock)
+{
+       stream << sock.address();
+       return stream;
+}
+
+
 } // namespace Mf
 
 #endif // _MOOF_SOCKET_HH_
This page took 0.055115 seconds and 4 git commands to generate.