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=f1604663b038c37ff408061ca50db4d914ccd38a;hp=4b67887416429835f0ebff9b0cee6afae17faf96;hb=1a9061caa8fe73b4b34a37fe467e145bba7bd2f5;hpb=41f8dd670e963aad94527ce2be0486268993a477 diff --git a/src/Moof/Socket.hh b/src/Moof/Socket.hh index 4b67887..f160466 100644 --- a/src/Moof/Socket.hh +++ b/src/Moof/Socket.hh @@ -17,16 +17,32 @@ #include #include +#if defined(_WIN32) +#include +#include +#include +#else #include #include #include #include +#if HAVE_FCNTL_H +#include +#else +#include +#endif +#endif #include #include #include +#ifndef SO_NONBLOCK +#define SO_NONBLOCK 1024 +#endif + + namespace Mf { @@ -34,47 +50,27 @@ class SocketAddress { public: - SocketAddress(int type = SOCK_STREAM) + SocketAddress() : + mSize(0), + mType(0) { - 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); + mAddress.sa.sa_family = AF_UNSPEC; + mAddress.v4.sin_port = 0; } - SocketAddress(const std::string& name, const std::string& service, - int type = SOCK_STREAM, int family = AF_INET) + SocketAddress(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); - - 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; + init(service, name, type, family); + } - freeaddrinfo(addr); + SocketAddress(const std::string& service, + int type = SOCK_STREAM, int family = AF_UNSPEC) + { + init(service, type, family); } - SocketAddress(const std::string& name, const struct addrinfo* addr) + SocketAddress(const struct addrinfo* addr, const std::string& name) { mType = addr->ai_socktype; memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen); @@ -88,11 +84,56 @@ public: mType = type; memcpy(&mAddress.sa, addr, size); mSize = size; + setNameFromAddress(); + } - char name[128] = {'\0'}; - inet_ntop(addr->sa_family, (struct sockaddr_in*)addr, - name, sizeof(name)); - mName = name; + + static SocketAddress broadcast(const std::string& service) + { + return SocketAddress(service, "255.255.255.255", 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); + + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = type; + hints.ai_flags = AI_PASSIVE; + + struct addrinfo* addr; + int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0, + service.c_str(), &hints, &addr); + if (status == 0) + { + mType = addr->ai_socktype; + memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen); + mSize = addr->ai_addrlen; + + if (name != "") mName = name; + else setNameFromAddress(); + + freeaddrinfo(addr); + } + else + { + Mf::logWarning(gai_strerror(status)); + mType = 0; + mSize = 0; + mAddress.sa.sa_family = AF_UNSPEC; + mAddress.v4.sin_port = 0; + } + } + + void init(const std::string& service, + int type = SOCK_STREAM, int family = AF_UNSPEC) + { + init(service, "", type, family); } @@ -101,9 +142,14 @@ public: return mName; } + void setName(const std::string& name) + { + mName = name; + } + unsigned short port() const { - return ntohs(mAddress.in4.sin_port); + return ntohs(mAddress.v4.sin_port); } int type() const @@ -119,7 +165,7 @@ public: const struct sockaddr* address() const { - return &mAddress.sa; + return mSize != 0 ? &mAddress.sa : 0; } size_t size() const @@ -128,45 +174,64 @@ public: } - 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& 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(); - - const char* canonicalName = list->ai_canonname; - struct addrinfo* addr = list; - while (addr != 0) + if (status == 0) + { + struct addrinfo* addr = list; + while (addr != 0) + { + resolved.push_back(SocketAddress(addr, name)); + addr = addr->ai_next; + } + + freeaddrinfo(list); + } + else { - resolved.push_back(SocketAddress(canonicalName, addr)); - addr = addr->ai_next; + Mf::logWarning(gai_strerror(status)); } - freeaddrinfo(list); return 0; } private: + void setNameFromAddress() + { +#if defined(_WIN32) + // inet_ntop was introduced in Vista + mName = inet_ntoa(mAddress.v4.sin_addr); +#else + char name[INET6_ADDRSTRLEN] = {'\0'}; + inet_ntop(mAddress.sa.sa_family, &mAddress.sa, name, sizeof(name)); + mName = name; +#endif + } + + union { - sockaddr sa; - sockaddr_in in4; - sockaddr_in6 in6; + sockaddr sa; + sockaddr_in v4; + sockaddr_in6 v6; + sockaddr_storage storage; } mAddress; size_t mSize; std::string mName; @@ -179,6 +244,7 @@ class Socket public: Socket(const SocketAddress& address) : + mFd(-1), mAddress(address) { mFd = socket(address.family(), address.type(), 0); @@ -186,13 +252,17 @@ public: ~Socket() { - close(mFd); +#if defined(_WIN32) + if (mFd != -1) closesocket(mFd); +#else + if (mFd != -1) close(mFd); +#endif } bool isConnected() const { - return false; + return mFd != -1; } const SocketAddress& address() const @@ -201,6 +271,71 @@ public: } + int connect() + { + return ::connect(mFd, mAddress.address(), mAddress.size()); + } + + int bind() + { + return ::bind(mFd, mAddress.address(), mAddress.size()); + } + + int listen(int backlog = SOMAXCONN) + { + return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN); + } + + Socket accept() + { + return Socket(mFd); + } + + + int set(int option, int value = 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) + { + return setsockopt(mFd, SOL_SOCKET, option, + value.c_str(), value.length()); + } + + int get(int option, int& value) + { + 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) + { + 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 Packet& packet) { write(mAddress, packet); @@ -233,13 +368,28 @@ public: int size = recvfrom(mFd, buffer, sizeof(buffer), 0, &addr.sa, &length); - address = SocketAddress(&addr.sa, length, SOCK_DGRAM); + address = SocketAddress(&addr.sa, length, mAddress.type()); return Packet(buffer, size); } 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); + mAddress = SocketAddress(&addr.sa, length); + } + + int mFd; SocketAddress mAddress; }; @@ -249,12 +399,12 @@ class ResolverTask : public ThreadedTask { 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); } @@ -277,10 +427,10 @@ public: 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;