From 1a9061caa8fe73b4b34a37fe467e145bba7bd2f5 Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Thu, 6 May 2010 22:46:09 -0600 Subject: [PATCH] win32 port of new sockets, with fixes --- configure.ac | 10 +- src/Main.cc | 37 ++++-- src/Moof/Packet.cc | 108 ++++++++++++++---- src/Moof/Packet.hh | 11 +- src/Moof/Socket.hh | 274 +++++++++++++++++++++++++++++++++++---------- 5 files changed, 341 insertions(+), 99 deletions(-) diff --git a/configure.ac b/configure.ac index 45ccfc4..6820114 100644 --- a/configure.ac +++ b/configure.ac @@ -294,6 +294,12 @@ then AC_MSG_WARN([Missing QT4 ($website)])]) fi +if test x$WIN32 = xyes +then + # On Windows, sockets are in the ws2_32 library. + LIBS="$LIBS -lws2_32" +fi + if test x$missing = xyes then AC_MSG_ERROR([You are missing some required libraries.]) @@ -306,7 +312,7 @@ AC_MSG_NOTICE([Checks for header files.]) AC_HEADER_STDBOOL AC_HEADER_STDC -AC_CHECK_HEADERS([byteswap.h stddef.h stdint.h stdlib.h string.h unistd.h]) +AC_CHECK_HEADERS([arpa/inet.h byteswap.h fcntl.h stddef.h stdint.h stdlib.h string.h unistd.h]) BOOST_SMART_PTR BOOST_STRING_ALGO @@ -339,7 +345,7 @@ AC_MSG_NOTICE([Checks for library functions.]) AC_FUNC_ERROR_AT_LINE AC_FUNC_STRTOD -AC_CHECK_FUNCS([nanosleep strchr strcspn strrchr strstr]) +AC_CHECK_FUNCS([fcntl ioctl nanosleep strchr strcspn strrchr strstr]) if test x$clock_gettime = xyes then diff --git a/src/Main.cc b/src/Main.cc index 277cc3d..c6df957 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -280,7 +280,7 @@ void goodbye() int main(int argc, char* argv[]) { - Mf::ResolverTask task("compy", "4950", SOCK_DGRAM); + Mf::ResolverTask task("4950", "255.255.255.255", SOCK_DGRAM); task.run(); int i = task.wait(); @@ -295,21 +295,27 @@ int main(int argc, char* argv[]) << " (" << addr.type() << ")" << std::endl; } - Mf::SocketAddress addr("www.apple.com", "80", SOCK_DGRAM); - - Mf::logInfo << "address: " << addr.name() << ":" << addr.port() - << " (" << addr.type() << ")" << std::endl; Mf::Packet packet(1000000); - packet << (uint16_t)45; + + packet << 5.1234f; + Mf::logInfo << "packet size: " << packet.size() << std::endl; + + float meh3; + packet >> meh3; + Mf::logInfo << "float: " << meh3 << std::endl; + Mf::logInfo << "packet size: " << packet.size() << std::endl; + + + packet << uint16_t(45); Mf::logInfo << "packet size: " << packet.size() << std::endl; - packet << (int64_t)-1234567890123456789; + packet << uint64_t(1234567812345679ULL); Mf::logInfo << "packet size: " << packet.size() << std::endl; packet << true << false << false << true << false << true << true; Mf::logInfo << "packet size: " << packet.size() << std::endl; - std::vector hi; + std::vector hi; hi.push_back(34); hi.push_back(-12345); hi.push_back(7734); @@ -329,10 +335,25 @@ int main(int argc, char* argv[]) Mf::logInfo << "packet size: " << packet.size() << std::endl; + Mf::SocketAddress addr("634", "lappy"); + Mf::logInfo << "local addr: " << addr.name() << std::endl; + for (it = task.addresses().begin(); it != task.addresses().end(); ++it) { + int bcast = 0; + Mf::SocketAddress addr = *it; Mf::Socket sock(addr); + + sock.get(SO_BROADCAST, bcast); + Mf::logInfo << "bcast: " << bcast << std::endl; + + sock.set(SO_REUSEADDR, 1); + sock.set(SO_BROADCAST, 1); + + sock.get(SO_BROADCAST, bcast); + Mf::logInfo << "bcast: " << bcast << std::endl; + sock.write(packet); } diff --git a/src/Moof/Packet.cc b/src/Moof/Packet.cc index 4f3b7fd..62da00b 100644 --- a/src/Moof/Packet.cc +++ b/src/Moof/Packet.cc @@ -16,37 +16,79 @@ #include #endif +#if HAVE_ARPA_INET_H #include +#endif #include #include "Packet.hh" +#ifndef bswap_16 +#define bswap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) +#endif + +#ifndef bswap_32 +#define bswap_32(x) ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#endif + #ifndef bswap_64 -#define bswap_64(x) (((uint64_t)(x) << 56) | \ - (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ - (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ - (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ - (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ - (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ - (((uint64_t)(x) >> 40) & 0xff00ULL) | \ - ((uint64_t)(x) >> 56)) +#define bswap_64(x) (((x) << 56) | \ + (((x) << 40) & 0xff000000000000ULL) | \ + (((x) << 24) & 0xff0000000000ULL) | \ + (((x) << 8) & 0xff00000000ULL) | \ + (((x) >> 8) & 0xff000000ULL) | \ + (((x) >> 24) & 0xff0000ULL) | \ + (((x) >> 40) & 0xff00ULL) | \ + ((x) >> 56)) #endif -static uint64_t htonll(uint64_t x) + +#if !HAVE_ARPA_INET_H +static uint16_t htons(uint16_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN - return bswap_64(x); + return bswap_16(x); +#else + return x; #endif } +static uint16_t ntohs(uint16_t x) +{ + return htons(x); +} -static uint64_t ntohll(uint64_t x) +static uint32_t htonl(uint32_t x) +{ +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + return bswap_32(x); +#else + return x; +#endif +} +static uint32_t ntohl(uint32_t x) +{ + return htonl(x); +} +#endif + + +static uint64_t htonll(uint64_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN return bswap_64(x); +#else + return x; #endif } +static uint64_t ntohll(uint64_t x) +{ + return htonll(x); +} namespace Mf { @@ -144,18 +186,23 @@ Packet& Packet::operator<<(uint64_t value) return *this; } -//Packet& Packet::operator<<(float value) -//{ -//} - -//Packet& Packet::operator<<(double value) -//{ -//} - -//Packet& Packet::operator<<(long double value) -//{ -//} +Packet& Packet::operator<<(float value) +{ + // XXX: assumes the ieee-754 + uint32_t* integer = reinterpret_cast(&value); + *integer = htonl(*integer); + write(integer, sizeof(value)); + return *this; +} +Packet& Packet::operator<<(double value) +{ + // XXX: assumes the ieee-754 + uint64_t* integer = reinterpret_cast(&value); + *integer = htonll(*integer); + write(integer, sizeof(value)); + return *this; +} size_t Packet::write(const void* bytes, size_t size) { @@ -230,6 +277,23 @@ Packet& Packet::operator>>(uint64_t& value) return *this; } +Packet& Packet::operator>>(float& value) +{ + // XXX: assumes the ieee-754 + uint32_t* integer = reinterpret_cast(&value); + read(integer, sizeof(value)); + *integer = htonl(*integer); + return *this; +} + +Packet& Packet::operator>>(double& value) +{ + // XXX: assumes the ieee-754 + uint64_t* integer = reinterpret_cast(&value); + read(integer, sizeof(value)); + *integer = htonll(*integer); + return *this; +} size_t Packet::read(void* bytes, size_t size) { diff --git a/src/Moof/Packet.hh b/src/Moof/Packet.hh index 198212c..208b22e 100644 --- a/src/Moof/Packet.hh +++ b/src/Moof/Packet.hh @@ -38,9 +38,8 @@ public: Packet& operator<<(uint16_t value); Packet& operator<<(uint32_t value); Packet& operator<<(uint64_t value); - //Packet& operator<<(float value); - //Packet& operator<<(double value); - //Packet& operator<<(long double value); + Packet& operator<<(float value); + Packet& operator<<(double value); size_t write(const void* bytes, size_t size); @@ -53,6 +52,8 @@ public: Packet& operator>>(uint16_t& value); Packet& operator>>(uint32_t& value); Packet& operator>>(uint64_t& value); + Packet& operator>>(float& value); + Packet& operator>>(double& value); size_t read(void* bytes, size_t size); @@ -85,7 +86,7 @@ private: inline Packet& operator<<(Packet& packet, const char* value) { - uint8_t length = strnlen(value, 255); + uint16_t length = strlen(value); packet << length; packet.write(value, length); return packet; @@ -93,7 +94,7 @@ inline Packet& operator<<(Packet& packet, const char* value) inline Packet& operator<<(Packet& packet, const std::string& value) { - packet << (uint8_t)value.length(); + packet << (uint16_t)value.length(); packet.write(value.c_str(), value.length()); return packet; } 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; -- 2.43.0