#ifndef _MOOF_SOCKET_HH_
#define _MOOF_SOCKET_HH_
+#include <algorithm>
#include <cstring>
#include <sstream>
#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 {
{
public:
- SocketAddress(int type = SOCK_STREAM)
+ SocketAddress() :
+ mSize(0),
+ mType(0)
+ {
+ mAddr.sa.sa_family = AF_UNSPEC;
+ mAddr.in.sin_port = 0;
+ }
+
+ SocketAddress(const std::string& service, const std::string& name,
+ int type = SOCK_STREAM, int family = AF_UNSPEC)
+ {
+ init(service, name, type, family);
+ }
+
+ SocketAddress(const std::string& service,
+ int type = SOCK_STREAM, int family = AF_UNSPEC)
+ {
+ init(service, type, family);
+ }
+
+ SocketAddress(const struct addrinfo* addr, const std::string& name)
+ {
+ mType = addr->ai_socktype;
+ memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
+ mName = name;
+ mSize = addr->ai_addrlen;
+ }
+
+ SocketAddress(const struct sockaddr* addr, size_t size,
+ int type = SOCK_STREAM)
{
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);
+ memcpy(&mAddr.sa, addr, size);
+ mSize = size;
+ setNameFromAddress();
}
- SocketAddress(const std::string& name, const std::string& service,
- int type = SOCK_STREAM, int family = AF_INET)
+
+ 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);
+ }
+
+
+ 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);
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* addr;
int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
- service.length() > 0 ? service.c_str() : 0, &hints, &addr);
- if (status != 0)
+ service.c_str(), &hints, &addr);
+ if (status == 0)
{
- Mf::logError("uh oh, that didn't work!");
- return;
- }
+ mType = addr->ai_socktype;
+ memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
+ mSize = addr->ai_addrlen;
- mType = addr->ai_socktype;
- memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
- mName = addr->ai_canonname;
- mSize = addr->ai_addrlen;
-
- freeaddrinfo(addr);
- }
+ if (name != "") mName = name;
+ else setNameFromAddress();
- SocketAddress(const std::string& name, const struct addrinfo* addr)
- {
- mType = addr->ai_socktype;
- memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
- mName = name;
- mSize = addr->ai_addrlen;
+ freeaddrinfo(addr);
+ }
+ else
+ {
+ Mf::logWarning(gai_strerror(status));
+ mType = 0;
+ mSize = 0;
+ mAddr.sa.sa_family = AF_UNSPEC;
+ mAddr.in.sin_port = 0;
+ }
}
- SocketAddress(const struct sockaddr* addr, size_t size,
- int type = SOCK_STREAM)
+ void init(const std::string& service,
+ int type = SOCK_STREAM, int family = AF_UNSPEC)
{
- mType = type;
- memcpy(&mAddress.sa, addr, size);
- mSize = size;
-
- char name[128] = {'\0'};
- inet_ntop(addr->sa_family, (struct sockaddr_in*)addr,
- name, sizeof(name));
- mName = name;
+ init(service, "", type, family);
}
return mName;
}
+ void setName(const std::string& name)
+ {
+ mName = name;
+ }
+
unsigned short port() const
{
- return ntohs(mAddress.in4.sin_port);
+ return ntohs(mAddr.in.sin_port);
}
int type() const
int family() const
{
- return mAddress.sa.sa_family;
+ return mAddr.sa.sa_family;
}
const struct sockaddr* address() const
{
- return &mAddress.sa;
+ return mSize != 0 ? &mAddr.sa : 0;
}
size_t size() const
}
- 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();
+ if (status == 0)
+ {
+ for (struct addrinfo* addr = list;
+ addr != 0; addr = addr->ai_next)
+ {
+ resolved.push_back(SocketAddress(addr, name));
+ }
- const char* canonicalName = list->ai_canonname;
- struct addrinfo* addr = list;
- while (addr != 0)
+ freeaddrinfo(list);
+ }
+ else
{
- resolved.push_back(SocketAddress(canonicalName, addr));
- addr = addr->ai_next;
+ Mf::logWarning(gai_strerror(status));
+ return -1;
}
- freeaddrinfo(list);
return 0;
}
private:
+ void setNameFromAddress()
+ {
+#if defined(_WIN32)
+ // inet_ntop was introduced in Vista
+ mName = inet_ntoa(mAddr.in.sin_addr);
+#else
+ char name[INET6_ADDRSTRLEN] = {'\0'};
+ inet_ntop(mAddr.sa.sa_family, &mAddr.sa, name, sizeof(name));
+ mName = name;
+#endif
+ }
+
+
union
{
- sockaddr sa;
- sockaddr_in in4;
- sockaddr_in6 in6;
- } mAddress;
+ sockaddr sa;
+ sockaddr_in in;
+ sockaddr_storage storage;
+ } mAddr;
size_t mSize;
std::string mName;
int mType;
class Socket
{
+ struct Impl
+ {
+ int fd;
+ bool isConnected;
+ SocketAddress address;
+ };
+
+
public:
+ Socket() :
+ mFd(-1),
+ mIsConnected(false) {}
+
Socket(const SocketAddress& address) :
- mAddress(address)
+ mFd(-1),
+ mIsConnected(false),
+ mAddress(address) {}
+
+ Socket(const std::string& service, const std::string& name,
+ int type = SOCK_STREAM, int family = AF_UNSPEC) :
+ mFd(-1),
+ mIsConnected(false),
+ mAddress(SocketAddress(service, name, type, family)) {}
+
+ Socket(const std::string& service,
+ int type = SOCK_STREAM, int family = AF_UNSPEC) :
+ mFd(-1),
+ mIsConnected(false),
+ mAddress(SocketAddress(service, type, family)) {}
+
+
+ Socket(Socket& move) :
+ mFd(move.mFd),
+ mIsConnected(move.mIsConnected),
+ mAddress(move.mAddress)
{
- mFd = socket(address.family(), address.type(), 0);
+ move.mFd = -1;
+ move.mIsConnected = false;
}
+ Socket(Impl move) :
+ mFd(move.fd),
+ mIsConnected(move.isConnected),
+ mAddress(move.address) {}
+
+ Socket& operator=(Socket& move)
+ {
+#if defined(_WIN32)
+ if (mFd != -1) closesocket(mFd);
+#else
+ if (mFd != -1) close(mFd);
+#endif
+ mFd = move.mFd;
+ mIsConnected = move.mIsConnected;
+ mAddress = move.mAddress;
+ move.mFd = -1;
+ move.mIsConnected = false;
+ return *this;
+ }
+
+ Socket& operator=(Impl move)
+ {
+#if defined(_WIN32)
+ if (mFd != -1) closesocket(mFd);
+#else
+ if (mFd != -1) close(mFd);
+#endif
+ mFd = move.fd;
+ mIsConnected = move.isConnected;
+ mAddress = move.address;
+ return *this;
+ }
+
+ operator Impl()
+ {
+ Impl impl;
+ impl.fd = mFd;
+ impl.isConnected = mIsConnected;
+ impl.address = mAddress;
+ mFd = -1;
+ mIsConnected = false;
+ return impl;
+ }
+
+
~Socket()
{
- close(mFd);
+#if defined(_WIN32)
+ if (mFd != -1) closesocket(mFd);
+#else
+ if (mFd != -1) close(mFd);
+#endif
}
bool isConnected() const
{
- return false;
+ return mIsConnected;
}
const SocketAddress& address() const
}
- void write(const Packet& packet)
+ int connect()
+ {
+ if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
+ int result = ::connect(mFd, mAddress.address(), mAddress.size());
+ mIsConnected = result != -1;
+ return result;
+ }
+
+ int bind()
+ {
+ if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
+ return ::bind(mFd, mAddress.address(), mAddress.size());
+ }
+
+ int listen(int backlog = SOMAXCONN)
+ {
+ return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN);
+ }
+
+ int accept(Socket& socket)
+ {
+ Socket temp = Socket(mFd);
+ if (temp.mFd != -1)
+ {
+ socket = temp;
+ return socket.mFd;
+ }
+ return -1;
+ }
+
+
+ int set(int option, int value = 0)
+ {
+ if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 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)
+ {
+ if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
+ return setsockopt(mFd, SOL_SOCKET, option,
+ value.data(), value.length());
+ }
+
+ int get(int option, int& value)
+ {
+ if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
+ 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)
{
- write(mAddress, packet);
+ if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
+ 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 SocketAddress& address, const Packet& packet)
+
+ ssize_t write(const void* bytes, size_t size)
+ {
+ return send(mFd, bytes, size, 0);
+ }
+ ssize_t write(const void* bytes, size_t size,
+ const SocketAddress& address)
{
- sendto(mFd, packet.bytes(), packet.size(), 0,
- address.address(), address.size());
+ return sendto(mFd, bytes, size, 0,
+ address.address(), address.size());
}
- Packet read()
+ ssize_t write(const Packet& packet)
{
- char buffer[1024];
- int size = recv(mFd, buffer, sizeof(buffer), 0);
+ return write(packet.bytes(), packet.size());
+ }
- return Packet(buffer, size);
+ ssize_t write(const Packet& packet, const SocketAddress& address)
+ {
+ return write(packet.bytes(), packet.size(), address);
+ }
+
+
+ ssize_t read(void* bytes, size_t size)
+ {
+ return recv(mFd, bytes, size, 0);
}
- Packet read(SocketAddress& address)
+ ssize_t read(void* bytes, size_t size, SocketAddress& address)
{
union
{
} addr;
socklen_t length = sizeof(addr);
- char buffer[1024];
- int size = recvfrom(mFd, buffer, sizeof(buffer), 0,
- &addr.sa, &length);
+ ssize_t result = recvfrom(mFd, bytes, size, 0, &addr.sa, &length);
+ if (result != -1)
+ {
+ address = SocketAddress(&addr.sa, length, mAddress.type());
+ }
+ return result;
+ }
+
+ ssize_t read(Packet& packet)
+ {
+ char buffer[65536];
+ ssize_t result = read(buffer, sizeof(buffer));
+ if (result != -1) packet = Packet(buffer, result);
+ return result;
+ }
- address = SocketAddress(&addr.sa, length, SOCK_DGRAM);
- return Packet(buffer, size);
+ ssize_t read(Packet& packet, SocketAddress& address)
+ {
+ char buffer[65536];
+ ssize_t result = read(buffer, sizeof(buffer), address);
+ if (result != -1) packet = Packet(buffer, result);
+ return result;
}
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);
+ if (mFd != -1)
+ {
+ mIsConnected = true;
+ mAddress = SocketAddress(&addr.sa, length);
+ }
+ }
+
+
int mFd;
+ bool mIsConnected;
SocketAddress mAddress;
};
{
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);
}
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;