--- /dev/null
+
+/*] 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 <cstring>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <Moof/Log.hh>
+#include <Moof/Packet.hh>
+#include <Moof/Thread.hh>
+
+
+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<SocketAddress>& 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<SocketAddress>& 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<SocketAddress> mAddressList;
+ bool mIsDone;
+ Function mFunction;
+};
+
+
+} // namespace Mf
+
+#endif // _MOOF_SOCKET_HH_
+