if (magic == SOLICIT)
{
Packet out;
- out << RESPONSE << mAddress.service() << mText;
+ out << RESPONSE << mType << mName << mText;
sock.socket().write(out);
return 0;
}
packet >> magic;
if (magic == RESPONSE)
{
- std::string service;
- std::string text;
-
- packet >> service >> text;
- if (service == mService)
+ std::string type;
+ packet >> type;
+ if (type == mType)
{
- mServices.push_back(Service(address, text));
+ std::string name;
+ std::string text;
+ packet >> name >> text;
+ mServices.insert(std::make_pair(name,
+ Service(address, name, text)));
return 0;
}
}
return -1;
}
-ServiceFinder::ServiceFinder(const std::string& service, int type)
+ServiceFinder::ServiceFinder(const std::string& type, int sockType)
{
}
#ifndef _MOOF_SERVICE_HH_
#define _MOOF_SERVICE_HH_
-#include <vector>
+#include <map>
#include <Moof/Math.hh>
#include <Moof/Socket.hh>
public:
/**
- * Construct a network service.
+ * Construct a network service. The type of service will be inferred
+ * from the address.
* \param address The address of the host.
+ * \param name The service name.
* \param text The service information.
*/
- Service(const SocketAddress& address, const std::string& text);
+ Service(const SocketAddress& address,
+ const std::string& name,
+ const std::string& text);
+
+ /**
+ * Construct a network service with an explicit type.
+ * \param address The address of the host.
+ * \param type The type of service.
+ * \param name The service name.
+ * \param text The service information.
+ */
+ Service(const SocketAddress& address,
+ const std::string& type,
+ const std::string& name,
+ const std::string& text);
/**
- * Publish the service on the local network.
+ * Publish the service on the network.
*/
void publish();
+ /**
+ * Stop publishing the service on the network.
+ */
void stop();
return mAddress;
}
+ /**
+ * Get the type of the service.
+ * \return The service type.
+ */
+ const std::string& type() const
+ {
+ return mType;
+ }
+
+ /**
+ * Get the service name.
+ * \return The service name.
+ */
+ const std::string& name() const
+ {
+ return mName;
+ }
+
/**
* Get the service information.
* \return The service information as a string.
}
+ ~Service();
+
+
private:
int handlePacket(SocketMultiplexer& sock,
const SocketAddress& address);
SocketAddress mAddress;
+ std::string mType;
+ std::string mName;
std::string mText;
};
{
public:
- ServiceFinder(const std::string& service, int type = SOCK_STREAM);
+ /**
+ * Construct a service finder to find services of the same type as an
+ * address.
+ * \address The address.
+ */
+ ServiceFinder(const SocketAddress& address);
+
+ /**
+ * Construct a service finder to find services of a certain type.
+ * \param type The type of the service.
+ * \param sockType The type of socket.
+ */
+ ServiceFinder(const std::string& type, int sockType = SOCK_STREAM);
- const std::vector<Service>& services() const
+ const std::map<std::string,Service>& services() const
{
return mServices;
}
Packet& packet,
const SocketAddress& address);
- std::string mService;
- std::vector<Service> mServices;
+ std::string mType;
+ std::map<std::string,Service> mServices;
};
* \param flags The send options.
* \return The number of bytes written.
*/
- ssize_t write(const void* bytes, size_t size,
- const SocketAddress& address, int flags = 0)
+ ssize_t write(const void* bytes,
+ size_t size,
+ const SocketAddress& address,
+ int flags = 0)
{
return sendto(mImpl.fd, bytes, size, flags,
- address.address(), address.size());
+ address.address(), address.size());
}
/**
* \param flags The send options.
* \return The number of bytes written.
*/
- ssize_t write(const Packet& packet, const SocketAddress& address,
- int flags = 0)
+ ssize_t write(const Packet& packet,
+ const SocketAddress& address,
+ int flags = 0)
{
return write(packet.bytes(), packet.size(), address, flags);
}
*/
ssize_t read(void* bytes, size_t size, int flags = 0)
{
- return recv(mImpl.fd, bytes, size, flags);
+ ssize_t result = recv(mImpl.fd, bytes, size, flags);
+ if (result == 0) mImpl.isConnected = false;
+ return result;
}
/**
* \param flags The recv options.
* \return The number of bytes read.
*/
- ssize_t read(void* bytes, size_t size, SocketAddress& address,
- int flags = 0)
+ ssize_t read(void* bytes,
+ size_t size,
+ SocketAddress& address,
+ int flags = 0)
{
union
{
{
address = SocketAddress(&addr.sa, length, mImpl.address.type());
}
+ else if (result == 0)
+ {
+ mImpl.isConnected = false;
+ }
return result;
}
--- /dev/null
+
+/*] 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 <algorithm>
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif
+#include <cstdlib>
+
+#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) (((x) << 56) | \
+ (((x) << 40) & 0xff000000000000ULL) | \
+ (((x) << 24) & 0xff0000000000ULL) | \
+ (((x) << 8) & 0xff00000000ULL) | \
+ (((x) >> 8) & 0xff000000ULL) | \
+ (((x) >> 24) & 0xff0000ULL) | \
+ (((x) >> 40) & 0xff00ULL) | \
+ ((x) >> 56))
+#endif
+
+
+#if !HAVE_ARPA_INET_H
+static uint16_t htons(uint16_t x)
+{
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+ return bswap_16(x);
+#else
+ return x;
+#endif
+}
+static uint16_t ntohs(uint16_t x)
+{
+ return htons(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 {
+
+
+Packet::Packet(size_t capacity) :
+ mBuffer((char*)malloc(capacity)),
+ mSize(capacity),
+ mR(0),
+ mW(0),
+ mOriginalW(0),
+ mBoolR(0),
+ mBoolW(0),
+ mBoolNumR(0),
+ mBoolNumW(0) {}
+
+Packet::Packet(const char* data, size_t size) :
+ mBuffer((char*)malloc(size)),
+ mSize(size),
+ mR(0),
+ mW(size),
+ mOriginalW(size),
+ mBoolR(0),
+ mBoolW(0),
+ mBoolNumR(0),
+ mBoolNumW(0)
+{
+ if (mBuffer) memcpy(mBuffer, data, size);
+}
+
+
+Packet::Packet(const Packet& copy) :
+ mBuffer((char*)malloc(copy.mSize)),
+ mSize(copy.mSize),
+ mR(copy.mR),
+ mW(copy.mW),
+ mOriginalW(copy.mOriginalW),
+ mBoolR(copy.mBoolR),
+ mBoolW(copy.mBoolW),
+ mBoolNumR(copy.mBoolNumR),
+ mBoolNumW(copy.mBoolNumW)
+{
+ if (mBuffer) memcpy(mBuffer, copy.mBuffer, mSize);
+}
+
+Packet& Packet::operator=(const Packet& copy)
+{
+ free(mBuffer);
+
+ mBuffer = (char*)malloc(copy.mSize);
+ mSize = copy.mSize;
+ mR = copy.mR;
+ mW = copy.mW;
+ mOriginalW = copy.mOriginalW;
+ mBoolR = copy.mBoolR;
+ mBoolW = copy.mBoolW;
+ mBoolNumR = copy.mBoolNumR;
+ mBoolNumW = copy.mBoolNumW;
+ if (mBuffer) memcpy(mBuffer, copy.mBuffer, mSize);
+ return *this;
+}
+
+
+Packet::~Packet()
+{
+ free(mBuffer);
+}
+
+
+bool Packet::put(bool value)
+{
+ int bit = mBoolNumW % 8;
+ if (bit == 0)
+ {
+ mBoolW = mW;
+
+ unsigned char byte = 0;
+ if (write(&byte, 1) == 0) return false;
+ }
+
+ if (value) mBuffer[mBoolW] |= (1 << bit);
+ ++mBoolNumW;
+ return true;
+}
+
+
+bool Packet::put(int8_t value)
+{
+ return put(uint8_t(value));
+}
+
+bool Packet::put(int16_t value)
+{
+ return put(uint16_t(value));
+}
+
+bool Packet::put(int32_t value)
+{
+ return put(uint32_t(value));
+}
+
+bool Packet::put(int64_t value)
+{
+ return put(uint64_t(value));
+}
+
+
+bool Packet::put(uint8_t value)
+{
+ return write(&value, sizeof(value)) == sizeof(value);
+}
+
+bool Packet::put(uint16_t value)
+{
+ value = htons(value);
+ return write(&value, sizeof(value)) == sizeof(value);
+}
+
+bool Packet::put(uint32_t value)
+{
+ value = htonl(value);
+ return write(&value, sizeof(value)) == sizeof(value);
+}
+
+bool Packet::put(uint64_t value)
+{
+ value = htonll(value);
+ return write(&value, sizeof(value)) == sizeof(value);
+}
+
+bool Packet::put(float value)
+{
+ // XXX: assumes the ieee-754
+ uint32_t* integer = reinterpret_cast<uint32_t*>(&value);
+ *integer = htonl(*integer);
+ return write(integer, sizeof(value)) == sizeof(value);
+}
+
+bool Packet::put(double value)
+{
+ // XXX: assumes the ieee-754
+ uint64_t* integer = reinterpret_cast<uint64_t*>(&value);
+ *integer = htonll(*integer);
+ return write(integer, sizeof(value)) == sizeof(value);
+}
+
+
+size_t Packet::write(const void* bytes, size_t size)
+{
+ size_t nBytes = std::min(size, mSize - mW);
+ if (!mBuffer || nBytes < size)
+ {
+ int nPages = 1 + size / PAGE_SIZE;
+ int newSize = mSize + nPages * PAGE_SIZE;
+ char* newBuffer = (char*)realloc(mBuffer, newSize);
+ if (newBuffer)
+ {
+ mBuffer = newBuffer;
+ mSize = newSize;
+ nBytes = size;
+ }
+ if (!mBuffer) return 0;
+ }
+ memcpy(mBuffer + mW, bytes, nBytes);
+ mW += nBytes;
+ return nBytes;
+}
+
+
+bool Packet::get(bool& value, int flags)
+{
+ int bit = mBoolNumR % 8;
+ if (bit == 0)
+ {
+ mBoolR = mR;
+
+ unsigned char byte = 0;
+ if (read(&byte, 1, flags) == 0) return false;
+ }
+
+ value = 1 & (mBuffer[mBoolR] >> bit);
+ if (!(flags & PEEK)) ++mBoolNumR;
+ return true;
+}
+
+bool Packet::get(int8_t& value, int flags)
+{
+ return get((uint8_t&)value, flags);
+}
+
+bool Packet::get(int16_t& value, int flags)
+{
+ return get((uint16_t&)value, flags);
+}
+
+bool Packet::get(int32_t& value, int flags)
+{
+ return get((uint32_t&)value, flags);
+}
+
+bool Packet::get(int64_t& value, int flags)
+{
+ return get((uint64_t&)value, flags);
+}
+
+bool Packet::get(uint8_t& value, int flags)
+{
+ size_t numBytes = read(&value, sizeof(value), flags);
+ return numBytes == sizeof(value);
+}
+
+bool Packet::get(uint16_t& value, int flags)
+{
+ size_t numBytes = read(&value, sizeof(value), flags);
+ value = ntohs(value);
+ return numBytes == sizeof(value);
+}
+
+bool Packet::get(uint32_t& value, int flags)
+{
+ size_t numBytes = read(&value, sizeof(value), flags);
+ value = ntohl(value);
+ return numBytes == sizeof(value);
+}
+
+bool Packet::get(uint64_t& value, int flags)
+{
+ size_t numBytes = read(&value, sizeof(value), flags);
+ value = ntohll(value);
+ return numBytes == sizeof(value);
+}
+
+bool Packet::get(float& value, int flags)
+{
+ // XXX: assumes the ieee-754
+ uint32_t* integer = reinterpret_cast<uint32_t*>(&value);
+ size_t numBytes = read(integer, sizeof(value));
+ *integer = htonl(*integer);
+ return numBytes == sizeof(value);
+}
+
+bool Packet::get(double& value, int flags)
+{
+ // XXX: assumes the ieee-754
+ uint64_t* integer = reinterpret_cast<uint64_t*>(&value);
+ size_t numBytes = read(integer, sizeof(value));
+ *integer = htonll(*integer);
+ return numBytes == sizeof(value);
+}
+
+
+size_t Packet::read(void* bytes, size_t size, int flags)
+{
+ size_t nBytes = std::min(size, mW - mR);
+ memcpy(bytes, mBuffer + mR, nBytes);
+ if (!(flags & PEEK)) mR += nBytes;
+ return nBytes;
+}
+
+
+void Packet::clear()
+{
+ mR = 0;
+ mW = 0;
+ mBoolR = 0;
+ mBoolW = 0;
+ mBoolNumR = 0;
+ mBoolNumW = 0;
+}
+
+
+void Packet::reset()
+{
+ mR = 0;
+ mW = mOriginalW;
+ mBoolR = 0;
+ mBoolW = 0;
+ mBoolNumR = 0;
+ mBoolNumW = 0;
+}
+
+
+} // namespace Mf
+
--- /dev/null
+
+/*] 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.
+*
+**************************************************************************/
+
+/**
+ * \file Packet.hh
+ * Classes for building and interpreting datagram packets.
+ */
+
+#ifndef _MOOF_PACKET_HH_
+#define _MOOF_PACKET_HH_
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+
+namespace Mf {
+
+
+/**
+ * Represents a packet of serialized variables ready for transfer over the
+ * network. This method is most suitable for representing datagram
+ * packets, but it may also be useful for seralizing data for persistent
+ * state storage. The semantics are similar to that of a FIFO queue or
+ * stream where packets are written and read by inserting and extracting
+ * variables to and from the packet, although the actual order of the
+ * variables in the buffer may be different. At any time, a pointer to a
+ * buffer and the size of the buffer can be retrieved. This class also
+ * handles endian differences by serializing variables in network byte
+ * order (big endian).
+ */
+class Packet
+{
+public:
+
+ /**
+ * Packet flags.
+ */
+ enum Flags
+ {
+ PEEK = 0x01 /// Do not actually remove anything.
+ };
+
+
+ /**
+ * Construct a packet with an initial capacity.
+ * \param capacity Initial capacity of the packet.
+ */
+ Packet(size_t capacity = PAGE_SIZE);
+
+ /**
+ * Construct a packet with some bytes from a buffer. The bytes will be
+ * copied into the packet, so you don't need to keep the original
+ * buffer.
+ * \param data The bytes.
+ * \param size The number of bytes.
+ */
+ Packet(const char* data, size_t size);
+
+
+ /**
+ * Insert a variable into the packet, serializing it. This usually
+ * increases the size of the packet by the size of the data type.
+ * \param value The value to insert.
+ * \return This.
+ */
+ bool put(bool value);
+ bool put(int8_t value);
+ bool put(int16_t value);
+ bool put(int32_t value);
+ bool put(int64_t value);
+ bool put(uint8_t value);
+ bool put(uint16_t value);
+ bool put(uint32_t value);
+ bool put(uint64_t value);
+ bool put(float value);
+ bool put(double value);
+
+ bool put(const char* value)
+ {
+ uint16_t length = strlen(value);
+ if (put(length))
+ {
+ size_t numBytes = write(value, length);
+ return numBytes == length;
+ }
+ return false;
+ }
+
+ template <class T>
+ bool put(const std::basic_string<T>& value)
+ {
+ if (put(uint16_t(value.length())))
+ {
+ size_t byteLength = value.length() * sizeof(T);
+ size_t numBytes = write(value.data(), byteLength);
+ return numBytes == byteLength;
+ }
+ return false;
+ }
+
+ template <class T>
+ bool put(const std::vector<T>& value)
+ {
+ if (put(uint16_t(value.size())))
+ {
+ typename std::vector<T>::const_iterator it;
+ for (it = value.begin(); it != value.end(); ++it)
+ {
+ if (!put(*it)) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Write some bytes to the packet.
+ * \param bytes The bytes.
+ * \param size The number of bytes.
+ * return The number of bytes actually written.
+ */
+ size_t write(const void* bytes, size_t size);
+
+
+ /**
+ * Extract a variable from the packet. This usually decreases the size
+ * of the packet by the size of the data type.
+ * \param value Reference to the variable to extract.
+ * \return This.
+ */
+ bool get(bool& value, int flags = 0);
+ bool get(int8_t& value, int flags = 0);
+ bool get(int16_t& value, int flags = 0);
+ bool get(int32_t& value, int flags = 0);
+ bool get(int64_t& value, int flags = 0);
+ bool get(uint8_t& value, int flags = 0);
+ bool get(uint16_t& value, int flags = 0);
+ bool get(uint32_t& value, int flags = 0);
+ bool get(uint64_t& value, int flags = 0);
+ bool get(float& value, int flags = 0);
+ bool get(double& value, int flags = 0);
+
+ template <class T>
+ bool get(std::basic_string<T>& value, int flags = 0)
+ {
+ uint16_t length = 0;
+ if (get(length, flags))
+ {
+ size_t byteLength = length * sizeof(T);
+ T str[length];
+ size_t numBytes = read(str, byteLength, flags);
+ value.assign(str, numBytes);
+ return numBytes == byteLength;
+ }
+ return false;
+ }
+
+ template <class T>
+ bool get(std::vector<T>& value, int flags = 0)
+ {
+ uint16_t size = 0;
+ if (get(size, flags))
+ {
+ value.clear();
+ for (uint16_t i = 0; i < size; ++i)
+ {
+ T item;
+ if (get(item, flags)) value.push_back(item);
+ else return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Read some bytes from the packet.
+ * \param bytes The buffer to hold the bytes read.
+ * \param size The size of the read buffer.
+ * \return The number of bytes actually read.
+ */
+ size_t read(void* bytes, size_t size, int flags = 0);
+
+
+ /**
+ * Clear the contents of the packet, setting the size of the packet to
+ * zero.
+ */
+ void clear();
+
+
+ /**
+ * Reset the read/write markers to their initial positions, putting the
+ * packet in the state it was at right after construction.
+ */
+ void reset();
+
+
+ /**
+ * Get a pointer to an internal structure holding the serialized bytes
+ * of the packet.
+ * return The pointer.
+ */
+ const char* bytes() const
+ {
+ return mBuffer + mR;
+ }
+
+ /**
+ * Get the size of the buffer holding the serialized bytes of the
+ * packet.
+ * \return The number of bytes.
+ */
+ size_t size() const
+ {
+ return mW - mR;
+ }
+
+ // The rest of this stuff is just to implement correct copy semantics.
+
+ Packet(const Packet& copy);
+ Packet& operator=(const Packet& copy);
+ ~Packet();
+
+
+private:
+
+ char* mBuffer;
+ size_t mSize;
+
+ size_t mR;
+ size_t mW;
+ size_t mOriginalW;
+
+ size_t mBoolR;
+ size_t mBoolW;
+ size_t mBoolNumR;
+ size_t mBoolNumW;
+};
+
+
+} // namespace Mf
+
+#endif // _MOOF_PACKET_HH_
+