-
-/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
-**] All rights reserved.
-*
-* vi:ts=4 sw=4 tw=75
-*
-* Distributable under the terms and conditions of the 2-clause BSD license;
-* see the file COPYING for a complete text of the license.
-*
-**************************************************************************/
-
-/**
- * \file Socket.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>
-
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#else
-#error No alternative to fcntl implemented yet.
-#endif
-
-#if defined(_WIN32)
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <wspiapi.h>
-#define SHUT_RD SD_RECEIVE
-#define SHUT_WR SD_SEND
-#define SHUT_RDWR SD_BOTH
-#else
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#endif
-
-#include <Moof/Log.hh>
-#include <Moof/Packet.hh>
-#include <Moof/Thread.hh>
-
-
-#ifndef AI_ADDRCONFIG
-#define AI_ADDRCONFIG 0
-#endif
-
-#ifndef AI_V4MAPPED
-#define AI_V4MAPPED 0
-#endif
-
-
-namespace Mf {
-
-
-/**
- * A class to represent the address of a remote host, including the type of
- * service and socket communication.
- */
-class SocketAddress
-{
-public:
-
- /**
- * Construct an unspecified address.
- */
- SocketAddress() :
- mSize(0),
- mType(0)
- {
- mAddr.sa.sa_family = AF_UNSPEC;
- mAddr.in.sin_port = 0;
- }
-
- /**
- * 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 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& name,
- int type = SOCK_STREAM,
- int family = AF_UNSPEC)
- {
- init(service, name, type, family);
- }
-
- /**
- * Construct an address without a specified host. The address can be
- * used to accept on a local port.
- * \param service The service name or port number.
- * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
- * \param family The family; can be AF_INET or AF_INET6.
- */
- explicit SocketAddress(const std::string& service,
- int type = SOCK_STREAM,
- int family = AF_UNSPEC)
- {
- init(service, type, family);
- }
-
- /**
- * Construct an address from the information in an addrinfo structure.
- * \param addr The addrinfo structure.
- */
- SocketAddress(const struct addrinfo* addr) :
- mSize(addr->ai_addrlen),
- mType(addr->ai_socktype)
- {
- memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
- getNameAndService(mName, mService);
- }
-
- /**
- * Construct an address from a sockaddr structure.
- * \param addr The sockaddr structure.
- * \param size The size of the sockaddr structure.
- * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
- */
- SocketAddress(const struct sockaddr* addr,
- size_t size,
- int type = SOCK_STREAM) :
- mSize(size),
- mType(type)
- {
- memcpy(&mAddr.sa, addr, size);
- getNameAndService(mName, mService);
- }
-
-
- /**
- * Get an IPv4 broadcast address.
- * \param service The service name or port number.
- * \return The socket address.
- */
- static SocketAddress broadcast(const std::string& service)
- {
- std::istringstream stream(service);
- unsigned short port;
- stream >> port;
-
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = INADDR_BROADCAST;
- memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
- return SocketAddress((sockaddr*)&addr, sizeof(addr), SOCK_DGRAM);
- }
-
-
- /**
- * 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 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& name,
- int type = SOCK_STREAM,
- int family = AF_UNSPEC)
- {
- struct addrinfo* addr = resolve(service.c_str(), name.c_str(),
- type, family,
- AI_ADDRCONFIG | AI_NUMERICHOST | AI_V4MAPPED);
- if (addr)
- {
- mSize = addr->ai_addrlen;
- mType = addr->ai_socktype;
- memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
-
- mService = service;
- mName = name;
-
- freeaddrinfo(addr);
- }
- else
- {
- mType = 0;
- mSize = 0;
- mAddr.sa.sa_family = AF_UNSPEC;
- mAddr.in.sin_port = 0;
- }
- }
-
- /**
- * Initialize the address without a specified host. The address can be
- * used to accept on a local port.
- * \param service The service name or port number.
- * \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,
- int type = SOCK_STREAM,
- int family = AF_UNSPEC)
- {
- struct addrinfo* addr = resolve(service.c_str(), 0,
- type, family,
- AI_PASSIVE);
- if (addr)
- {
- mSize = addr->ai_addrlen;
- mType = addr->ai_socktype;
- memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
-
- mService = service;
- getName(mName);
-
- freeaddrinfo(addr);
- }
- else
- {
- mType = 0;
- mSize = 0;
- mAddr.sa.sa_family = AF_UNSPEC;
- mAddr.in.sin_port = 0;
- }
- }
-
-
- /**
- * Get the name of the service. This could also be a port number if
- * there is no service name associated with the number.
- * \return The service.
- */
- const std::string& service() const
- {
- return mService;
- }
-
- /**
- * Get the name of the host. This may be the host used to construct
- * the address, or a resolved numeric host if none was used.
- * \return The host.
- */
- const std::string& name() const
- {
- return mName;
- }
-
- /**
- * Get the port number of the address service.
- * \return Port number.
- */
- unsigned short port() const
- {
- return ntohs(mAddr.in.sin_port);
- }
-
- /**
- * Get the type of socket associated with the service of this address.
- * \return Socket type; either SOCK_STREAM or SOCK_DGRAM.
- */
- int type() const
- {
- return mType;
- }
-
- /**
- * Get the family of the protocol associated with the address.
- * \return Protocol family; either AF_INET, AF_INET6, or AF_UNSPEC.
- */
- int family() const
- {
- return mAddr.sa.sa_family;
- }
-
-
- /**
- * Get the sockaddr structure of the address.
- * \return The sockaddr structure.
- */
- const struct sockaddr* address() const
- {
- return mSize != 0 ? &mAddr.sa : 0;
- }
-
- /**
- * Get the size of the sockaddr structure of the address.
- * \return The size of the sockaddr structure.
- */
- size_t size() const
- {
- return mSize;
- }
-
-
- /**
- * Get a list of addresses resolved to by the given search criteria.
- * This can be used to perform lookups for name resolution, so this
- * method may take some time to return. Use the ResolveTask class to
- * resolve addresses asynchronously.
- * \param service The service name or port number.
- * \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& name,
- int type,
- int family,
- std::vector<SocketAddress>& resolved)
- {
- struct addrinfo* list = resolve(service.c_str(), name.c_str(),
- type, family,
- AI_ADDRCONFIG | AI_V4MAPPED);
- int result = collectAddresses(list, resolved);
- freeaddrinfo(list);
- return result;
- }
-
- /**
- * Get a list of addresses resolved to by the given search criteria.
- * The addresses will be suitable for accepting on a local port.
- * \param service The service name or port number.
- * \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,
- int type,
- int family,
- std::vector<SocketAddress>& resolved)
- {
- struct addrinfo* list = resolve(service.c_str(), 0,
- type, family,
- AI_PASSIVE);
- int result = collectAddresses(list, resolved);
- freeaddrinfo(list);
- return result;
- }
-
-
- /**
- * 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,
- const char* node,
- int type,
- int family,
- int flags)
- {
- 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 = flags;
-
- struct addrinfo* addr;
- int status = getaddrinfo(node, service, &hints, &addr);
-
- if (status == 0)
- {
- return addr;
- }
- else
- {
- Mf::logWarning(gai_strerror(status));
- return 0;
- }
- }
-
- static int collectAddresses(struct addrinfo* addresses,
- std::vector<SocketAddress>& resolved)
- {
- if (addresses)
- {
- resolved.clear();
-
- for (struct addrinfo* addr = addresses;
- addr != 0;
- addr = addr->ai_next)
- {
- resolved.push_back(SocketAddress(addr));
- }
-
- return 0;
- }
- else return -1;
- }
-
-
- union
- {
- sockaddr sa;
- sockaddr_in in;
- sockaddr_storage storage;
- } mAddr;
- size_t mSize;
- int mType;
-
- std::string mName;
- std::string mService;
-};
-
-
-/**
- * The socket class represents a connection or between this node and a
- * remote node.
- */
-class Socket
-{
- struct Impl
- {
- SocketAddress address;
- int fd;
- bool isConnected;
-
- Impl() :
- fd(-1),
- isConnected(false) {}
-
- Impl(const SocketAddress& address, int flags = 0) :
- address(address),
- fd(::socket(address.family(), address.type(), flags)),
- isConnected(false) {}
- } mImpl;
-
-
-public:
-
- /**
- * Construct a socket with no associated peer.
- */
- Socket() {}
-
- /**
- * Construct a socket with an address.
- * \param address The address.
- * \param flags The socket options.
- */
- Socket(const SocketAddress& address, int flags = 0) :
- mImpl(address, flags) {}
-
- /**
- * 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 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) :
- mImpl(SocketAddress(service, name, type, family), flags) {}
-
- /**
- * Construct a socket without a specified host. The socket can be used
- * to accept sockets on a local port.
- * \param service The service name or port number.
- * \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.
- */
- explicit Socket(const std::string& service,
- int type = SOCK_STREAM,
- int family = AF_UNSPEC,
- int flags = 0) :
- mImpl(SocketAddress(service, type, family), flags) {}
-
-
- /**
- * Deconstruct the socket, closing it.
- */
- ~Socket()
- {
- close();
- }
-
-
- /**
- * Get whether or not the socket is connected.
- * \return True if the socket is connected, false otherwise.
- */
- bool isConnected() const
- {
- return mImpl.isConnected;
- }
-
- /**
- * Get the address associated with the socket.
- */
- const SocketAddress& address() const
- {
- return mImpl.address;
- }
-
-
- /**
- * Connect the socket to its peer.
- * \return 0 on success, -1 on failure.
- */
- int connect()
- {
- int result = ::connect(mImpl.fd,
- mImpl.address.address(),
- mImpl.address.size());
- mImpl.isConnected = result != -1;
- return result;
- }
-
- /**
- * Disconnect a connected socket from its peer.
- * \param flags Specify the socket directions to close.
- * \return 0 on success, -1 on failure.
- */
- int disconnect(int flags = SHUT_RDWR)
- {
- return shutdown(mImpl.fd, flags);
- }
-
-
- /**
- * Bind the socket to interface and port number specified in the
- * address.
- * \return 0 on success, -1 on failure.
- */
- int bind()
- {
- return ::bind(mImpl.fd,
- mImpl.address.address(),
- mImpl.address.size());
- }
-
- /**
- * Listen on the socket for incoming connections. This is only useful
- * for sockets of type SOCK_STREAM.
- * \param backlog The number of unaccepted connections to queue.
- * \return 0 on success, -1 on failure.
- */
- int listen(int backlog = SOMAXCONN)
- {
- return ::listen(mImpl.fd, backlog > 0 ? backlog : SOMAXCONN);
- }
-
- /**
- * Accept a new connection on the socket. This is only useful for
- * sockets of type SOCK_STREAM.
- * \param socket Set to the new socket on return.
- * \return 0 on success, -1 on failure.
- */
- int accept(Socket& socket)
- {
- Socket temp = Socket(mImpl.fd);
- if (temp.mImpl.fd != -1)
- {
- socket = temp;
- return socket.mImpl.fd;
- }
- return -1;
- }
-
-
- /**
- * 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.
- */
- template <class T>
- int set(int option, const T& value, int level = SOL_SOCKET)
- {
-#if defined(_WIN32)
- return setsockopt(mImpl.fd,
- level,
- option,
- reinterpret_cast<const char*>(&value),
- sizeof(value));
-#else
- return setsockopt(mImpl.fd, level, option, &value, sizeof(value));
-#endif
- }
-
- /**
- * 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 level = SOL_SOCKET)
- {
- 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
- union
- {
- sockaddr sa;
- sockaddr_storage storage;
- } addr;
- socklen_t length = sizeof(addr);
-
- mImpl.fd = ::accept(fd, &addr.sa, &length);
- if (mImpl.fd != -1)
- {
- mImpl.isConnected = true;
- mImpl.address = SocketAddress(&addr.sa, length);
- }
- }
-
- void close()
- {
-#if defined(_WIN32)
- if (mImpl.fd != -1) closesocket(mImpl.fd);
-#else
- if (mImpl.fd != -1) ::close(mImpl.fd);
-#endif
- }
-};
-
-
-class SocketMultiplexer
-{
-public:
-
- typedef boost::function<int(SocketMultiplexer&,
- Packet&,
- const SocketAddress&)> Function;
-
- explicit 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.
- */
-class ResolverTask : public ThreadedTask
-{
-public:
-
- /**
- * Construct a resolver task from a service and hostname.
- * \param service Server name or port number.
- * \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& name,
- int type = SOCK_STREAM,
- int family = AF_UNSPEC) :
- mIsDone(false)
- {
- mFunction = boost::bind(&ResolverTask::resolve,
- this, service, name, type, family);
- }
-
-
- /**
- * Get whether or not the task is done.
- * \return True if the task has finished, false otherwise.
- */
- bool isDone() const
- {
- return mIsDone;
- }
-
- /**
- * Start the task. This does nothing if the task was already run or is
- * currently running.
- */
- void run()
- {
- if (!isDone() && !mThread.isValid())
- {
- mThread = Thread::detach(mFunction);
- }
- }
-
-
- /**
- * Get the addresses resolved. This is filled and safe to access after
- * the task finishes.
- * \return List of addresses.
- * \see isDone()
- */
- const std::vector<SocketAddress>& addresses() const
- {
- return mAddressList;
- }
-
-
-private:
-
- int resolve(const std::string& service,
- const std::string& name,
- int type,
- int family)
- {
- int status = SocketAddress::resolve(service, name,
- type, family,
- mAddressList);
- mIsDone = true;
- return status;
- }
-
-
- std::vector<SocketAddress> mAddressList;
- bool mIsDone;
- Thread::Function mFunction;
-};
-
-
-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_
-