From: Charles McGarvey Date: Wed, 5 May 2010 03:40:46 +0000 (-0600) Subject: initial network stuff X-Git-Url: https://git.dogcows.com/gitweb?a=commitdiff_plain;h=41f8dd670e963aad94527ce2be0486268993a477;p=chaz%2Fyoink initial network stuff --- diff --git a/configure.ac b/configure.ac index da42bf0..45ccfc4 100644 --- a/configure.ac +++ b/configure.ac @@ -306,7 +306,7 @@ AC_MSG_NOTICE([Checks for header files.]) AC_HEADER_STDBOOL AC_HEADER_STDC -AC_CHECK_HEADERS([stddef.h stdint.h stdlib.h string.h unistd.h]) +AC_CHECK_HEADERS([byteswap.h stddef.h stdint.h stdlib.h string.h unistd.h]) BOOST_SMART_PTR BOOST_STRING_ALGO @@ -321,8 +321,8 @@ AC_MSG_NOTICE([Checks for types.]) AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T +AC_TYPE_UINT64_T AC_TYPE_SIZE_T -AC_TYPE_SSIZE_T #### diff --git a/src/Main.cc b/src/Main.cc index 8554c7f..277cc3d 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -276,8 +276,70 @@ void goodbye() } +#include + int main(int argc, char* argv[]) { + Mf::ResolverTask task("compy", "4950", SOCK_DGRAM); + task.run(); + + int i = task.wait(); + Mf::logWarning << "task ended with code: " << i << std::endl; + + std::vector::const_iterator it; + for (it = task.addresses().begin(); it != task.addresses().end(); ++it) + { + Mf::SocketAddress addr = *it; + + Mf::logInfo << "address: " << addr.name() << ":" << addr.port() + << " (" << 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; + Mf::logInfo << "packet size: " << packet.size() << std::endl; + packet << (int64_t)-1234567890123456789; + 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; + hi.push_back(34); + hi.push_back(-12345); + hi.push_back(7734); + + for (int a = 0; a < 15900; a++) + { + hi.push_back(a); + } + + packet << hi; + Mf::logInfo << "packet size: " << packet.size() << std::endl; + + packet << "hello world"; + Mf::logInfo << "packet size: " << packet.size() << std::endl; + + packet << false << false << false << true << false; + Mf::logInfo << "packet size: " << packet.size() << std::endl; + + + for (it = task.addresses().begin(); it != task.addresses().end(); ++it) + { + Mf::SocketAddress addr = *it; + Mf::Socket sock(addr); + sock.write(packet); + } + + + return 0; + + if (argc > 1) { std::string arg(argv[1]); diff --git a/src/Makefile.am b/src/Makefile.am index fa6c981..6dd508e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,8 +43,11 @@ libmoof_a_SOURCES = \ Moof/Manager.hh \ Moof/Math.hh \ Moof/ModalDialog.hh \ + Moof/Network.hh \ Moof/Octree.hh \ Moof/OpenGL.hh \ + Moof/Packet.cc \ + Moof/Packet.hh \ Moof/Plane.cc \ Moof/Plane.hh \ Moof/Ray.hh \ @@ -52,9 +55,11 @@ libmoof_a_SOURCES = \ Moof/Resource.hh \ Moof/RigidBody.hh \ Moof/Script.hh \ + Moof/Service.hh \ Moof/Settings.cc \ Moof/Settings.hh \ Moof/Shape.hh \ + Moof/Socket.hh \ Moof/Sound.cc \ Moof/Sound.hh \ Moof/Sphere.hh \ diff --git a/src/Moof/Aabb.cc b/src/Moof/Aabb.cc index 16dd841..4b96f20 100644 --- a/src/Moof/Aabb.cc +++ b/src/Moof/Aabb.cc @@ -20,6 +20,5 @@ void importAabbClass(Script& script) { } - -} // namespace Mf +} // namepsace Mf diff --git a/src/Moof/Network.hh b/src/Moof/Network.hh new file mode 100644 index 0000000..314b9a7 --- /dev/null +++ b/src/Moof/Network.hh @@ -0,0 +1,38 @@ + +/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +**] All rights reserved. +* +* vi:ts=4 sw=4 tw=75 +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +**************************************************************************/ + +#ifndef _MOOF_NETWORK_HH_ +#define _MOOF_NETWORK_HH_ + +#include +#include + + +namespace Mf { + + +class NetworkGamer +{ +}; + + +class NetworkSession +{ +public: + + const std::vector& gamers(); +}; + + +} // namespace Mf + +#endif // _MOOF_NETWORK_HH_ + diff --git a/src/Moof/Packet.cc b/src/Moof/Packet.cc new file mode 100644 index 0000000..4f3b7fd --- /dev/null +++ b/src/Moof/Packet.cc @@ -0,0 +1,244 @@ + +/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +**] All rights reserved. +* +* vi:ts=4 sw=4 tw=75 +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +**************************************************************************/ + +#include "../config.h" + +#include +#if HAVE_BYTESWAP_H +#include +#endif + +#include + +#include + +#include "Packet.hh" + + +#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)) +#endif + +static uint64_t htonll(uint64_t x) +{ +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + return bswap_64(x); +#endif +} + +static uint64_t ntohll(uint64_t x) +{ +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + return bswap_64(x); +#endif +} + + +namespace Mf { + + +Packet::Packet(size_t size) : + mR(0), + mW(0), + mBoolR(0), + mBoolW(0), + mBoolNumR(0), + mBoolNumW(0) +{ + mBuffer = boost::shared_array(new char[size]); + mSize = size; +} + +Packet::Packet(const char* data, size_t size) : + mR(0), + mBoolR(0), + mBoolW(0), + mBoolNumR(0), + mBoolNumW(0) +{ + mBuffer = boost::shared_array(new char[size]); + mSize = size; + mW = size; + memcpy(mBuffer.get(), data, mSize); +} + + +Packet& Packet::operator<<(bool value) +{ + int bit = mBoolNumW % 8; + if (bit == 0) + { + mBoolW = mW; + + unsigned char byte = 0; + if (write(&byte, 1) == 0) return *this; + } + + if (value) mBuffer[mBoolW] |= (1 << bit); + ++mBoolNumW; + + return *this; +} + + +Packet& Packet::operator<<(int8_t value) +{ + return *this << (uint8_t)value; +} + +Packet& Packet::operator<<(int16_t value) +{ + return *this << (uint16_t)value; +} + +Packet& Packet::operator<<(int32_t value) +{ + return *this << (uint32_t)value; +} + +Packet& Packet::operator<<(int64_t value) +{ + return *this << (uint64_t)value; +} + + +Packet& Packet::operator<<(uint8_t value) +{ + write(&value, sizeof(value)); + return *this; +} + +Packet& Packet::operator<<(uint16_t value) +{ + value = htons(value); + write(&value, sizeof(value)); + return *this; +} + +Packet& Packet::operator<<(uint32_t value) +{ + value = htonl(value); + write(&value, sizeof(value)); + return *this; +} + +Packet& Packet::operator<<(uint64_t value) +{ + value = htonll(value); + write(&value, sizeof(value)); + return *this; +} + +//Packet& Packet::operator<<(float value) +//{ +//} + +//Packet& Packet::operator<<(double value) +//{ +//} + +//Packet& Packet::operator<<(long double value) +//{ +//} + + +size_t Packet::write(const void* bytes, size_t size) +{ + size_t nBytes = std::min(size, mSize - mW); + memcpy(&mBuffer[mW], bytes, nBytes); + mW += nBytes; + return nBytes; +} + + +Packet& Packet::operator>>(bool& value) +{ + int bit = mBoolNumR % 8; + if (bit == 0) + { + mBoolR = mR; + + unsigned char byte = 0; + if (read(&byte, 1) == 0) return *this; + } + + value = 1 & (mBuffer[mBoolR] >> bit); + ++mBoolNumR; + + return *this; +} + +Packet& Packet::operator>>(int8_t& value) +{ + return *this >> (uint8_t&)value; +} + +Packet& Packet::operator>>(int16_t& value) +{ + return *this >> (uint16_t&)value; +} + +Packet& Packet::operator>>(int32_t& value) +{ + return *this >> (uint32_t&)value; +} + +Packet& Packet::operator>>(int64_t& value) +{ + return *this >> (uint64_t&)value; +} + +Packet& Packet::operator>>(uint8_t& value) +{ + read(&value, sizeof(value)); + return *this; +} + +Packet& Packet::operator>>(uint16_t& value) +{ + read(&value, sizeof(value)); + value = ntohs(value); + return *this; +} + +Packet& Packet::operator>>(uint32_t& value) +{ + read(&value, sizeof(value)); + value = ntohl(value); + return *this; +} + +Packet& Packet::operator>>(uint64_t& value) +{ + read(&value, sizeof(value)); + value = ntohll(value); + return *this; +} + + +size_t Packet::read(void* bytes, size_t size) +{ + size_t nBytes = std::min(size, mW - mR); + memcpy(bytes, &mBuffer[mR], nBytes); + mR += nBytes; + return nBytes; +} + + +} // namespace Mf + diff --git a/src/Moof/Packet.hh b/src/Moof/Packet.hh new file mode 100644 index 0000000..198212c --- /dev/null +++ b/src/Moof/Packet.hh @@ -0,0 +1,146 @@ + +/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +**] All rights reserved. +* +* vi:ts=4 sw=4 tw=75 +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +**************************************************************************/ + +#ifndef _MOOF_PACKET_HH_ +#define _MOOF_PACKET_HH_ + +#include +#include +#include + +#include + + +namespace Mf { + + +class Packet +{ +public: + + Packet(size_t size = 1024); + Packet(const char* data, size_t size); + + Packet& operator<<(bool value); + Packet& operator<<(int8_t value); + Packet& operator<<(int16_t value); + Packet& operator<<(int32_t value); + Packet& operator<<(int64_t value); + Packet& operator<<(uint8_t value); + 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); + + size_t write(const void* bytes, size_t size); + + Packet& operator>>(bool& value); + Packet& operator>>(int8_t& value); + Packet& operator>>(int16_t& value); + Packet& operator>>(int32_t& value); + Packet& operator>>(int64_t& value); + Packet& operator>>(uint8_t& value); + Packet& operator>>(uint16_t& value); + Packet& operator>>(uint32_t& value); + Packet& operator>>(uint64_t& value); + + size_t read(void* bytes, size_t size); + + + const char* bytes() const + { + return &mBuffer.get()[mR]; + } + + size_t size() const + { + return mW - mR; + } + + +private: + + boost::shared_array mBuffer; + size_t mSize; + + size_t mR; + size_t mW; + + size_t mBoolR; + size_t mBoolW; + size_t mBoolNumR; + size_t mBoolNumW; +}; + + +inline Packet& operator<<(Packet& packet, const char* value) +{ + uint8_t length = strnlen(value, 255); + packet << length; + packet.write(value, length); + return packet; +} + +inline Packet& operator<<(Packet& packet, const std::string& value) +{ + packet << (uint8_t)value.length(); + packet.write(value.c_str(), value.length()); + return packet; +} + +template +inline Packet& operator<<(Packet& packet, const std::vector& value) +{ + packet << (uint8_t)value.size(); + typename std::vector::const_iterator it; + for (it = value.begin(); it != value.end(); ++it) + { + packet << *it; + } + return packet; +} + + +inline Packet& operator>>(Packet& packet, std::string& value) +{ + uint8_t length = 0; + packet >> length; + + char str[256]; + size_t charsRead = packet.read(str, length); + value.assign(str, charsRead); + return packet; +} + +template +inline Packet& operator>>(Packet& packet, std::vector& value) +{ + uint8_t size = 0; + packet >> size; + + value.clear(); + for (uint8_t i = 0; i < size; ++i) + { + T item; + packet >> item; + value.push_back(item); + } + return packet; +} + + + +} // namespace Mf + +#endif // _MOOF_PACKET_HH_ + diff --git a/src/Moof/Service.hh b/src/Moof/Service.hh new file mode 100644 index 0000000..5870d57 --- /dev/null +++ b/src/Moof/Service.hh @@ -0,0 +1,44 @@ + +/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +**] All rights reserved. +* +* vi:ts=4 sw=4 tw=75 +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +**************************************************************************/ + +#ifndef _MOOF_SERVICE_HH_ +#define _MOOF_SERVICE_HH_ + +#include + + +namespace Mf { + + +class ServiceBroadcaster +{ +public: + + ServiceBroadcaster(const std::string& name); + + void update(Scalar t, Scalar dt); +}; + + +class ServiceLocator +{ +public: + + ServiceLocator(const std::string& name); + + void update(Scalar t, Scalar dt); +}; + + +} // namespace Mf + +#endif // _MOOF_SERVICE_HH_ + diff --git a/src/Moof/Socket.hh b/src/Moof/Socket.hh new file mode 100644 index 0000000..4b67887 --- /dev/null +++ b/src/Moof/Socket.hh @@ -0,0 +1,299 @@ + +/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +**] All rights reserved. +* +* vi:ts=4 sw=4 tw=75 +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +**************************************************************************/ + +#ifndef _MOOF_SOCKET_HH_ +#define _MOOF_SOCKET_HH_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +namespace Mf { + + +class SocketAddress +{ +public: + + SocketAddress(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); + } + + SocketAddress(const std::string& name, const std::string& service, + int type = SOCK_STREAM, int family = AF_INET) + { + 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; + + freeaddrinfo(addr); + } + + 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; + } + + SocketAddress(const struct sockaddr* addr, size_t size, + int type = SOCK_STREAM) + { + 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; + } + + + const std::string& name() const + { + return mName; + } + + unsigned short port() const + { + return ntohs(mAddress.in4.sin_port); + } + + int type() const + { + return mType; + } + + int family() const + { + return mAddress.sa.sa_family; + } + + + const struct sockaddr* address() const + { + return &mAddress.sa; + } + + size_t size() const + { + return mSize; + } + + + static int resolve(const std::string& name, const std::string& service, + int type, int family, std::vector& resolved) + { + 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* 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) + { + resolved.push_back(SocketAddress(canonicalName, addr)); + addr = addr->ai_next; + } + + freeaddrinfo(list); + return 0; + } + + +private: + + union + { + sockaddr sa; + sockaddr_in in4; + sockaddr_in6 in6; + } mAddress; + size_t mSize; + std::string mName; + int mType; +}; + + +class Socket +{ +public: + + Socket(const SocketAddress& address) : + mAddress(address) + { + mFd = socket(address.family(), address.type(), 0); + } + + ~Socket() + { + close(mFd); + } + + + bool isConnected() const + { + return false; + } + + const SocketAddress& address() const + { + return mAddress; + } + + + void write(const Packet& packet) + { + write(mAddress, packet); + } + + void write(const SocketAddress& address, const Packet& packet) + { + sendto(mFd, packet.bytes(), packet.size(), 0, + address.address(), address.size()); + } + + Packet read() + { + char buffer[1024]; + int size = recv(mFd, buffer, sizeof(buffer), 0); + + return Packet(buffer, size); + } + + Packet read(SocketAddress& address) + { + union + { + sockaddr sa; + sockaddr_storage storage; + } addr; + socklen_t length = sizeof(addr); + + char buffer[1024]; + int size = recvfrom(mFd, buffer, sizeof(buffer), 0, + &addr.sa, &length); + + address = SocketAddress(&addr.sa, length, SOCK_DGRAM); + return Packet(buffer, size); + } + + +private: + + int mFd; + SocketAddress mAddress; +}; + + +class ResolverTask : public ThreadedTask +{ +public: + + ResolverTask(const std::string& name, const std::string& service, + int type = SOCK_STREAM, int family = AF_UNSPEC) : + mIsDone(false) + { + mFunction = boost::bind(&ResolverTask::resolve, + this, name, service, type, family); + } + + + bool isDone() const + { + return mIsDone; + } + + void run() + { + if (!mThread) mThread = Mf::detachFunction(mFunction); + } + + + const std::vector& addresses() const + { + return mAddressList; + } + + +private: + + int resolve(const std::string& name, const std::string& service, + int type, int family) + { + int status = SocketAddress::resolve(name, service, + type, family, mAddressList); + mIsDone = true; + return status; + } + + + std::vector mAddressList; + bool mIsDone; + Function mFunction; +}; + + +} // namespace Mf + +#endif // _MOOF_SOCKET_HH_ + diff --git a/src/Moof/Thread.hh b/src/Moof/Thread.hh index 52a878a..3e0bd82 100644 --- a/src/Moof/Thread.hh +++ b/src/Moof/Thread.hh @@ -23,6 +23,7 @@ namespace Mf { + // // The detach function detaches a separate thread by calling 'func' with // the 'arg' parameter. @@ -80,6 +81,41 @@ inline unsigned getThreadIdentifier(Thread thread) } +class AsyncTask +{ +public: + + virtual ~AsyncTask() {} + + virtual bool isDone() const = 0; + + virtual void run() = 0; + virtual int wait() = 0; +}; + +class ThreadedTask +{ +public: + + ThreadedTask() : + mThread(0) {} + + Thread thread() const { return mThread; } + + int wait() + { + int code = waitOnThread(mThread); + mThread = 0; + return code; + } + + +protected: + + Thread mThread; +}; + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class Mutex