X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FSocket.hh;h=fcf1a3edbfc0464395941929c222d699d53a1e91;hp=4b67887416429835f0ebff9b0cee6afae17faf96;hb=7ade2da0367685e098181d7124c9ba145a010626;hpb=41f8dd670e963aad94527ce2be0486268993a477 diff --git a/src/Moof/Socket.hh b/src/Moof/Socket.hh index 4b67887..fcf1a3e 100644 --- a/src/Moof/Socket.hh +++ b/src/Moof/Socket.hh @@ -12,21 +12,38 @@ #ifndef _MOOF_SOCKET_HH_ #define _MOOF_SOCKET_HH_ +#include #include #include #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,19 +51,61 @@ class SocketAddress { public: - SocketAddress(int type = SOCK_STREAM) + SocketAddress() : + mSize(0), + mType(0) + { + mAddr.sa.sa_family = AF_UNSPEC; + mAddr.in.sin_port = 0; + } + + SocketAddress(const std::string& service, const std::string& name, + int type = SOCK_STREAM, int family = AF_UNSPEC) + { + init(service, name, type, family); + } + + SocketAddress(const std::string& service, + int type = SOCK_STREAM, int family = AF_UNSPEC) + { + init(service, type, family); + } + + SocketAddress(const struct addrinfo* addr, const std::string& name) + { + mType = addr->ai_socktype; + memcpy(&mAddr.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; - 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); + memcpy(&mAddr.sa, addr, size); + mSize = size; + setNameFromAddress(); } - SocketAddress(const std::string& name, const std::string& service, - int type = SOCK_STREAM, int family = AF_INET) + + 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); @@ -55,44 +114,36 @@ public: 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* addr; int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0, - service.length() > 0 ? service.c_str() : 0, &hints, &addr); - if (status != 0) + service.c_str(), &hints, &addr); + if (status == 0) { - Mf::logError("uh oh, that didn't work!"); - return; - } + mType = addr->ai_socktype; + memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen); + mSize = addr->ai_addrlen; - mType = addr->ai_socktype; - memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen); - mName = addr->ai_canonname; - mSize = addr->ai_addrlen; - - freeaddrinfo(addr); - } + if (name != "") mName = name; + else setNameFromAddress(); - 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; + freeaddrinfo(addr); + } + else + { + Mf::logWarning(gai_strerror(status)); + mType = 0; + mSize = 0; + mAddr.sa.sa_family = AF_UNSPEC; + mAddr.in.sin_port = 0; + } } - SocketAddress(const struct sockaddr* addr, size_t size, - int type = SOCK_STREAM) + void init(const std::string& service, + int type = SOCK_STREAM, int family = AF_UNSPEC) { - 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; + init(service, "", type, family); } @@ -101,9 +152,14 @@ public: return mName; } + void setName(const std::string& name) + { + mName = name; + } + unsigned short port() const { - return ntohs(mAddress.in4.sin_port); + return ntohs(mAddr.in.sin_port); } int type() const @@ -113,13 +169,13 @@ public: int family() const { - return mAddress.sa.sa_family; + return mAddr.sa.sa_family; } const struct sockaddr* address() const { - return &mAddress.sa; + return mSize != 0 ? &mAddr.sa : 0; } size_t size() const @@ -128,46 +184,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(mAddr.in.sin_addr); +#else + char name[INET6_ADDRSTRLEN] = {'\0'}; + inet_ntop(mAddr.sa.sa_family, &mAddr.sa, name, sizeof(name)); + mName = name; +#endif + } + + union { - sockaddr sa; - sockaddr_in in4; - sockaddr_in6 in6; - } mAddress; + sockaddr sa; + sockaddr_in in; + sockaddr_storage storage; + } mAddr; size_t mSize; std::string mName; int mType; @@ -176,23 +250,105 @@ private: class Socket { + struct Impl + { + int fd; + bool isConnected; + SocketAddress address; + }; + + public: + Socket() : + mFd(-1), + mIsConnected(false) {} + Socket(const SocketAddress& address) : - mAddress(address) + mFd(-1), + mIsConnected(false), + mAddress(address) {} + + Socket(const std::string& service, const std::string& name, + int type = SOCK_STREAM, int family = AF_UNSPEC) : + mFd(-1), + mIsConnected(false), + mAddress(SocketAddress(service, name, type, family)) {} + + Socket(const std::string& service, + int type = SOCK_STREAM, int family = AF_UNSPEC) : + mFd(-1), + mIsConnected(false), + mAddress(SocketAddress(service, type, family)) {} + + + Socket(Socket& move) : + mFd(move.mFd), + mIsConnected(move.mIsConnected), + mAddress(move.mAddress) { - mFd = socket(address.family(), address.type(), 0); + move.mFd = -1; + move.mIsConnected = false; } + Socket(Impl move) : + mFd(move.fd), + mIsConnected(move.isConnected), + mAddress(move.address) {} + + Socket& operator=(Socket& move) + { +#if defined(_WIN32) + if (mFd != -1) closesocket(mFd); +#else + if (mFd != -1) close(mFd); +#endif + mFd = move.mFd; + mIsConnected = move.mIsConnected; + mAddress = move.mAddress; + move.mFd = -1; + move.mIsConnected = false; + return *this; + } + + Socket& operator=(Impl move) + { +#if defined(_WIN32) + if (mFd != -1) closesocket(mFd); +#else + if (mFd != -1) close(mFd); +#endif + mFd = move.fd; + mIsConnected = move.isConnected; + mAddress = move.address; + return *this; + } + + operator Impl() + { + Impl impl; + impl.fd = mFd; + impl.isConnected = mIsConnected; + impl.address = mAddress; + mFd = -1; + mIsConnected = false; + return impl; + } + + ~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 +357,114 @@ public: } - void write(const Packet& packet) + int connect() + { + if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0); + int result = ::connect(mFd, mAddress.address(), mAddress.size()); + mIsConnected = result != -1; + return result; + } + + int bind() + { + if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0); + return ::bind(mFd, mAddress.address(), mAddress.size()); + } + + int listen(int backlog = SOMAXCONN) + { + return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN); + } + + int accept(Socket& socket) + { + Socket temp = Socket(mFd); + if (temp.mFd != -1) + { + socket = temp; + return socket.mFd; + } + return -1; + } + + + int set(int option, int value = 0) + { + if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 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) + { + if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0); + return setsockopt(mFd, SOL_SOCKET, option, + value.data(), value.length()); + } + + int get(int option, int& value) + { + if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0); + 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) { - write(mAddress, packet); + if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0); + 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 SocketAddress& address, const Packet& packet) + + 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) { - sendto(mFd, packet.bytes(), packet.size(), 0, - address.address(), address.size()); + return sendto(mFd, bytes, size, 0, + address.address(), address.size()); } - Packet read() + ssize_t write(const Packet& packet) { - char buffer[1024]; - int size = recv(mFd, buffer, sizeof(buffer), 0); + return write(packet.bytes(), packet.size()); + } - return Packet(buffer, size); + ssize_t write(const Packet& packet, const SocketAddress& address) + { + return write(packet.bytes(), packet.size(), address); + } + + + 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 +473,54 @@ 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; + } + + ssize_t read(Packet& packet) + { + char buffer[65536]; + ssize_t result = read(buffer, sizeof(buffer)); + if (result != -1) packet = Packet(buffer, result); + return result; + } - address = SocketAddress(&addr.sa, length, SOCK_DGRAM); - return Packet(buffer, size); + 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); + if (mFd != -1) + { + mIsConnected = true; + mAddress = SocketAddress(&addr.sa, length); + } + } + + int mFd; + bool mIsConnected; SocketAddress mAddress; }; @@ -249,12 +529,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 +557,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;