/*] 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. * **************************************************************************/ #ifndef _MOOF_SOCKET_HH_ #define _MOOF_SOCKET_HH_ #include #include #include #include #include #include #include #include #include #include #include namespace Mf { class SocketAddress { public: SocketAddress(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); } SocketAddress(const std::string& name, const std::string& service, int type = SOCK_STREAM, int family = AF_INET) { 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; freeaddrinfo(addr); } 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; } SocketAddress(const struct sockaddr* addr, size_t size, int type = SOCK_STREAM) { 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; } const std::string& name() const { return mName; } unsigned short port() const { return ntohs(mAddress.in4.sin_port); } int type() const { return mType; } int family() const { return mAddress.sa.sa_family; } const struct sockaddr* address() const { return &mAddress.sa; } size_t size() const { return mSize; } static int resolve(const std::string& name, const std::string& service, int type, int family, std::vector& resolved) { 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* 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) { resolved.push_back(SocketAddress(canonicalName, addr)); addr = addr->ai_next; } freeaddrinfo(list); return 0; } private: union { sockaddr sa; sockaddr_in in4; sockaddr_in6 in6; } mAddress; size_t mSize; std::string mName; int mType; }; class Socket { public: Socket(const SocketAddress& address) : mAddress(address) { mFd = socket(address.family(), address.type(), 0); } ~Socket() { close(mFd); } bool isConnected() const { return false; } const SocketAddress& address() const { return mAddress; } void write(const Packet& packet) { write(mAddress, packet); } void write(const SocketAddress& address, const Packet& packet) { sendto(mFd, packet.bytes(), packet.size(), 0, address.address(), address.size()); } Packet read() { char buffer[1024]; int size = recv(mFd, buffer, sizeof(buffer), 0); return Packet(buffer, size); } Packet read(SocketAddress& address) { union { sockaddr sa; sockaddr_storage storage; } addr; socklen_t length = sizeof(addr); char buffer[1024]; int size = recvfrom(mFd, buffer, sizeof(buffer), 0, &addr.sa, &length); address = SocketAddress(&addr.sa, length, SOCK_DGRAM); return Packet(buffer, size); } private: int mFd; SocketAddress mAddress; }; class ResolverTask : public ThreadedTask { public: ResolverTask(const std::string& name, const std::string& service, int type = SOCK_STREAM, int family = AF_UNSPEC) : mIsDone(false) { mFunction = boost::bind(&ResolverTask::resolve, this, name, service, type, family); } bool isDone() const { return mIsDone; } void run() { if (!mThread) mThread = Mf::detachFunction(mFunction); } const std::vector& addresses() const { return mAddressList; } private: int resolve(const std::string& name, const std::string& service, int type, int family) { int status = SocketAddress::resolve(name, service, type, family, mAddressList); mIsDone = true; return status; } std::vector mAddressList; bool mIsDone; Function mFunction; }; } // namespace Mf #endif // _MOOF_SOCKET_HH_