X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FSocket.hh;h=c53ca06289974869f8d1b31fe438605aea827835;hp=4b67887416429835f0ebff9b0cee6afae17faf96;hb=351a86a5275f355b55f3827175a72853995f2aaa;hpb=41f8dd670e963aad94527ce2be0486268993a477 diff --git a/src/Moof/Socket.hh b/src/Moof/Socket.hh index 4b67887..c53ca06 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,65 @@ 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) + { + 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); + + 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 +151,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 +174,7 @@ public: const struct sockaddr* address() const { - return &mAddress.sa; + return mSize != 0 ? &mAddress.sa : 0; } size_t size() const @@ -128,45 +183,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(); + 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(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 +253,8 @@ class Socket public: Socket(const SocketAddress& address) : + mFd(-1), + mIsConnected(false), mAddress(address) { mFd = socket(address.family(), address.type(), 0); @@ -186,13 +262,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 mIsConnected; } const SocketAddress& address() const @@ -201,26 +281,102 @@ public: } - void write(const Packet& packet) + int connect() + { + int result = ::connect(mFd, mAddress.address(), mAddress.size()); + mIsConnected = result != -1; + return result; + } + + 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.data(), 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; + } + + + 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) { - write(mAddress, packet); + return sendto(mFd, bytes, size, 0, + address.address(), address.size()); } - void write(const SocketAddress& address, const Packet& packet) + ssize_t write(const Packet& packet) { - sendto(mFd, packet.bytes(), packet.size(), 0, - address.address(), address.size()); + return write(packet.bytes(), packet.size()); } - Packet read() + ssize_t write(const Packet& packet, const SocketAddress& address) { - char buffer[1024]; - int size = recv(mFd, buffer, sizeof(buffer), 0); + return write(packet.bytes(), packet.size(), address); + } + - return Packet(buffer, size); + 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 { @@ -229,18 +385,50 @@ public: } 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; + } - address = SocketAddress(&addr.sa, length, SOCK_DGRAM); - return Packet(buffer, size); + ssize_t read(Packet& packet) + { + char buffer[65536]; + ssize_t result = read(buffer, sizeof(buffer)); + if (result != -1) packet = Packet(buffer, result); + return result; + } + + 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); + mAddress = SocketAddress(&addr.sa, length); + } + + int mFd; + bool mIsConnected; SocketAddress mAddress; }; @@ -249,12 +437,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 +465,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;