#include <byteswap.h>
#endif
+#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
+#endif
#include <SDL/SDL.h>
#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 {
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<uint32_t*>(&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<uint64_t*>(&value);
+ *integer = htonll(*integer);
+ write(integer, sizeof(value));
+ return *this;
+}
size_t Packet::write(const void* bytes, size_t size)
{
return *this;
}
+Packet& Packet::operator>>(float& value)
+{
+ // XXX: assumes the ieee-754
+ uint32_t* integer = reinterpret_cast<uint32_t*>(&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<uint64_t*>(&value);
+ read(integer, sizeof(value));
+ *integer = htonll(*integer);
+ return *this;
+}
size_t Packet::read(void* bytes, size_t size)
{
#include <string>
#include <vector>
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <wspiapi.h>
+#else
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#endif
#include <Moof/Log.hh>
#include <Moof/Packet.hh>
#include <Moof/Thread.hh>
+#ifndef SO_NONBLOCK
+#define SO_NONBLOCK 1024
+#endif
+
+
namespace Mf {
{
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);
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);
}
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
const struct sockaddr* address() const
{
- return &mAddress.sa;
+ return mSize != 0 ? &mAddress.sa : 0;
}
size_t size() const
}
- 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<SocketAddress>& 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;
public:
Socket(const SocketAddress& address) :
+ mFd(-1),
mAddress(address)
{
mFd = socket(address.family(), address.type(), 0);
~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
}
+ 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);
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;
};
{
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);
}
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;