X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FSocket.hh;fp=src%2FMoof%2FSocket.hh;h=4b67887416429835f0ebff9b0cee6afae17faf96;hp=0000000000000000000000000000000000000000;hb=41f8dd670e963aad94527ce2be0486268993a477;hpb=40755d4c6251206c18ce4784967d3a910cee096f diff --git a/src/Moof/Socket.hh b/src/Moof/Socket.hh new file mode 100644 index 0000000..4b67887 --- /dev/null +++ b/src/Moof/Socket.hh @@ -0,0 +1,299 @@ + +/*] 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_ +