+ return setsockopt(mImpl.fd, level, option,
+ value.data(), value.length());
+ }
+
+ /**
+ * 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.
+ */
+ template <class T>
+ int get(int option, T& value, int level = SOL_SOCKET) const
+ {
+ 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 level = SOL_SOCKET) const
+ {
+ char str[256] = {'\0'};
+ socklen_t size = sizeof(str);
+
+#if defined(_WIN32)
+ int result = getsockopt(mImpl.fd,
+ level,
+ option,
+ reinterpret_cast<char*>(&str),
+ &size);
+#else
+ int result = getsockopt(mImpl.fd, level, option, &str, &size);
+#endif
+ value.assign(str, size);
+ return result;
+ }
+
+
+ /**
+ * Set the socket IO mode to either blocking or non-blocking.
+ * \param isBlocking True if the socket blocks, false otherwise.
+ */
+ void setBlocking(bool isBlocking)
+ {
+#ifdef HAVE_FCNTL
+ int flags = fcntl(mImpl.fd, F_GETFL);
+ flags = isBlocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
+ fcntl(mImpl.fd, F_SETFL, flags);
+#elif defined(_WIN32)
+ u_long value = isBlocking;
+ ioctlsocket(mImpl.fd, FIONBIO, &value);
+#endif
+ }
+
+ /**
+ * Get whether or not the socket is blocking or non-blocking. If the
+ * IO mode can't be determined, this method will assume the socket is
+ * a blocking socket.
+ * \return True if the socket blocks, false otherwise.
+ */
+ bool isBlocking() const
+ {
+#ifdef HAVE_FCNTL
+ int flags = fcntl(mImpl.fd, F_GETFL);
+ return !(flags & O_NONBLOCK);
+#endif
+ return true;
+ }
+
+
+ /**
+ * Write some bytes to the socket. Use this for connected sockets.
+ * \param bytes The bytes.
+ * \param size The number of bytes.
+ * \param flags The send options.
+ * \return The number of bytes written.
+ */
+ ssize_t write(const void* bytes, size_t size, int flags = 0)
+ {
+#if defined(_WIN32)
+ return send(mImpl.fd,
+ reinterpret_cast<const char *>(bytes), size,
+ flags);
+#else
+ return send(mImpl.fd, bytes, size, flags);
+#endif
+ }
+
+ /**
+ * Write some bytes to the socket using the given address. Use this
+ * for unconnected sockets.
+ * \param bytes The bytes.
+ * \param size The number of bytes.
+ * \param address The address to send to.
+ * \param flags The send options.
+ * \return The number of bytes written.
+ */
+ ssize_t write(const void* bytes,
+ size_t size,
+ const SocketAddress& address,
+ int flags = 0)
+ {
+#if defined(_WIN32)
+ return sendto(mImpl.fd,
+ reinterpret_cast<const char*>(bytes), size,
+ flags,
+ address.address(), address.size());
+#else
+ return sendto(mImpl.fd, bytes, size, flags,
+ address.address(), address.size());
+#endif
+ }
+
+ /**
+ * Write a packet to the socket. Use this for connected sockets.
+ * \param packet The packet.
+ * \param flags The send options.
+ * \return The number of bytes written.
+ */
+ ssize_t write(const Packet& packet, int flags = 0)
+ {
+ return write(packet.bytes(), packet.size(), flags);
+ }
+
+ /**
+ * Write a packet to the socket using the given address. Use this for
+ * unconnected sockets.
+ * \param packet The packet.
+ * \param address The address to send to.
+ * \param flags The send options.
+ * \return The number of bytes written.
+ */
+ ssize_t write(const Packet& packet,
+ const SocketAddress& address,
+ int flags = 0)
+ {
+ return write(packet.bytes(), packet.size(), address, flags);
+ }
+
+
+ /**
+ * Read some bytes from the socket. Use this for connected sockets.
+ * \param bytes The buffer to store the bytes.
+ * \param size The size of the buffer.
+ * \param flags The recv options.
+ * \return The number of bytes read.
+ */
+ ssize_t read(void* bytes, size_t size, int flags = 0)
+ {
+#if defined(_WIN32)
+ ssize_t result = recv(mImpl.fd,
+ reinterpret_cast<char*>(bytes), size,
+ flags);
+#else
+ ssize_t result = recv(mImpl.fd, bytes, size, flags);
+#endif
+ if (result == 0) mImpl.isConnected = false;
+ return result;
+ }
+
+ /**
+ * Read some bytes from the socket using the given address. Use this
+ * for unconnected sockets.
+ * \param bytes The buffer to store the bytes.
+ * \param size The size of the buffer.
+ * \param address The address to read from.
+ * \param flags The recv options.
+ * \return The number of bytes read.
+ */
+ ssize_t read(void* bytes,
+ size_t size,
+ SocketAddress& address,
+ int flags = 0)
+ {
+ union
+ {
+ sockaddr sa;
+ sockaddr_storage storage;
+ } addr;
+ socklen_t length = sizeof(addr);
+
+#if defined(_WIN32)
+ ssize_t result = recvfrom(mImpl.fd,
+ reinterpret_cast<char*>(bytes), size,
+ flags,
+ &addr.sa, &length);
+#else
+ ssize_t result = recvfrom(mImpl.fd, bytes, size, flags,
+ &addr.sa, &length);
+#endif
+ if (result != -1)
+ {
+ address = SocketAddress(&addr.sa, length, mImpl.address.type());
+ }
+ else if (result == 0)
+ {
+ mImpl.isConnected = false;
+ }
+ return result;
+ }
+
+ /**
+ * Read a packet from the socket. Use this for connected sockets.
+ * \param packet Set to the packet read on return.
+ * \param flags The recv options.
+ * \return The number of bytes read.
+ */
+ ssize_t read(Packet& packet, int flags = 0)
+ {
+ char buffer[65536];
+ ssize_t result = read(buffer, sizeof(buffer), flags);
+ if (result != -1) packet = Packet(buffer, result);
+ return result;
+ }
+
+ /**
+ * Read a packet from the socket using the given address. Use this for
+ * unconnected sockets.
+ * \param packet Set to the packet read on return.
+ * \param address The address to read from.
+ * \param flags The recv options.
+ * \return The number of bytes read.
+ */
+ ssize_t read(Packet& packet, SocketAddress& address, int flags = 0)
+ {
+ char buffer[65536];
+ ssize_t result = read(buffer, sizeof(buffer), address, flags);
+ if (result != -1) packet = Packet(buffer, result);
+ return result;
+ }
+
+
+ // The rest of this junk is used to implement the "move" semantics
+ // correctly, since it makes no sense for socket objects to be copied.
+
+ Socket(Socket& move) :
+ mImpl(move.mImpl)
+ {
+ move.mImpl.fd = -1;
+ move.mImpl.isConnected = false;
+ }
+
+ Socket(Impl move) :
+ mImpl(move) {}
+
+ Socket& operator=(Socket& move)
+ {
+ close();
+ mImpl = move.mImpl;
+ move.mImpl.fd = -1;
+ move.mImpl.isConnected = false;
+ return *this;
+ }
+
+ Socket& operator=(Impl move)
+ {
+ close();
+ mImpl = move;
+ return *this;
+ }
+
+ operator Impl()
+ {
+ Impl impl(mImpl);
+ mImpl.fd = -1;
+ mImpl.isConnected = false;
+ return impl;
+ }
+
+
+private:
+
+ Socket(int fd)
+ {
+ // for accepting a socket from fd