headers "msp/net"
{
- source "source";
+ source "source/net";
install true;
};
library "mspnet"
{
- source "source";
+ source "source/net";
install true;
};
+++ /dev/null
-#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <cerrno>
-#include <sys/socket.h>
-#endif
-#include <msp/core/systemerror.h>
-#include "clientsocket.h"
-#include "socket_private.h"
-
-namespace Msp {
-namespace Net {
-
-ClientSocket::ClientSocket(Family af, int type, int proto):
- Socket(af, type, proto),
- connecting(false),
- connected(false),
- peer_addr(0)
-{ }
-
-ClientSocket::ClientSocket(const Private &p, const SockAddr &paddr):
- Socket(p),
- connecting(false),
- connected(true),
- peer_addr(paddr.copy())
-{ }
-
-ClientSocket::~ClientSocket()
-{
- signal_flush_required.emit();
-
- delete peer_addr;
-}
-
-const SockAddr &ClientSocket::get_peer_address() const
-{
- if(peer_addr==0)
- throw bad_socket_state("not connected");
- return *peer_addr;
-}
-
-unsigned ClientSocket::do_write(const char *buf, unsigned size)
-{
- if(!connected)
- throw bad_socket_state("not connected");
-
- if(size==0)
- return 0;
-
- int ret = ::send(priv->handle, buf, size, 0);
- if(ret<0)
- {
- if(errno==EAGAIN)
- return 0;
- else
- throw system_error("send");
- }
-
- return ret;
-}
-
-unsigned ClientSocket::do_read(char *buf, unsigned size)
-{
- if(!connected)
- throw bad_socket_state("not connected");
-
- if(size==0)
- return 0;
-
- int ret = ::recv(priv->handle, buf, size, 0);
- if(ret<0)
- {
- if(errno==EAGAIN)
- return 0;
- else
- throw system_error("recv");
- }
- else if(ret==0 && !eof_flag)
- {
- eof_flag = true;
- signal_end_of_file.emit();
- set_events(IO::P_NONE);
- }
-
- return ret;
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_CLIENTSOCKET_H_
-#define MSP_NET_CLIENTSOCKET_H_
-
-#include "socket.h"
-
-namespace Msp {
-namespace Net {
-
-/**
-ClientSockets are used for sending and receiving data over the network.
-*/
-class ClientSocket: public Socket
-{
-public:
- /** Emitted when the socket finishes connecting. */
- sigc::signal<void, const std::exception *> signal_connect_finished;
-
-protected:
- bool connecting;
- bool connected;
- SockAddr *peer_addr;
-
- ClientSocket(const Private &, const SockAddr &);
- ClientSocket(Family, int, int);
-public:
- virtual ~ClientSocket();
-
- /** Connects to a remote address. Exact semantics depend on the socket
- type. Returns true if the connection was established, false if it's in
- progress. */
- virtual bool connect(const SockAddr &) = 0;
-
- /** Checks the status of a connection being established. Returns true if
- the connection was established successfully, false if it's still in
- progress. If an error occurred, an exception is thrown. */
- virtual bool poll_connect(const Time::TimeDelta &) = 0;
-
- bool is_connecting() const { return connecting; }
- bool is_connected() const { return connected; }
-
- const SockAddr &get_peer_address() const;
-protected:
- virtual unsigned do_write(const char *, unsigned);
- virtual unsigned do_read(char *, unsigned);
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <cstring>
-#include "communicator.h"
-
-namespace {
-
-using namespace Msp::Net;
-
-struct Handshake
-{
- unsigned hash;
-};
-
-
-class HandshakeProtocol: public Protocol
-{
-public:
- HandshakeProtocol();
-};
-
-HandshakeProtocol::HandshakeProtocol():
- Protocol(0x7F00)
-{
- add<Handshake>()(&Handshake::hash);
-}
-
-
-class HandshakeReceiver: public PacketReceiver<Handshake>
-{
-private:
- unsigned hash;
-
-public:
- HandshakeReceiver();
- unsigned get_hash() const { return hash; }
- virtual void receive(const Handshake &);
-};
-
-HandshakeReceiver::HandshakeReceiver():
- hash(0)
-{ }
-
-void HandshakeReceiver::receive(const Handshake &shake)
-{
- hash = shake.hash;
-}
-
-}
-
-
-namespace Msp {
-namespace Net {
-
-Communicator::Communicator(StreamSocket &s, const Protocol &p, ReceiverBase &r):
- socket(s),
- protocol(p),
- receiver(r),
- handshake_status(0),
- buf_size(1024),
- in_buf(new char[buf_size]),
- in_begin(in_buf),
- in_end(in_buf),
- out_buf(new char[buf_size]),
- good(true)
-{
- socket.signal_data_available.connect(sigc::mem_fun(this, &Communicator::data_available));
-}
-
-Communicator::~Communicator()
-{
- delete[] in_buf;
- delete[] out_buf;
-}
-
-void Communicator::initiate_handshake()
-{
- if(handshake_status!=0)
- throw sequence_error("handshaking already done");
-
- send_handshake();
- handshake_status = 1;
-}
-
-void Communicator::data_available()
-{
- if(!good)
- return;
-
- in_end += socket.read(in_end, in_buf+buf_size-in_end);
- try
- {
- bool more = true;
- while(more)
- {
- if(handshake_status==2)
- {
- more = receive_packet(protocol, receiver);
- }
- else
- {
- HandshakeProtocol hsproto;
- HandshakeReceiver hsrecv;
- if((more = receive_packet(hsproto, hsrecv)))
- {
- if(hsrecv.get_hash()==protocol.get_hash())
- {
- if(handshake_status==0)
- send_handshake();
- handshake_status = 2;
- signal_handshake_done.emit();
- }
- else
- good = false;
- }
- }
- }
- }
- catch(...)
- {
- good = false;
- throw;
- }
-}
-
-bool Communicator::receive_packet(const Protocol &proto, ReceiverBase &recv)
-{
- int psz = proto.get_packet_size(in_begin, in_end-in_begin);
- if(psz && psz<=in_end-in_begin)
- {
- char *pkt = in_begin;
- in_begin += psz;
- proto.disassemble(recv, pkt, psz);
- return true;
- }
- else
- {
- if(in_end==in_buf+buf_size)
- {
- unsigned used = in_end-in_begin;
- memmove(in_buf, in_begin, used);
- in_begin = in_buf;
- in_end = in_begin+used;
- }
- return false;
- }
-}
-
-void Communicator::send_handshake()
-{
- Handshake shake;
- shake.hash = protocol.get_hash();
-
- HandshakeProtocol hsproto;
- unsigned size = hsproto.assemble(shake, out_buf, buf_size);
- socket.write(out_buf, size);
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_COMMUNICATOR_H_
-#define MSP_NET_COMMUNICATOR_H_
-
-#include "protocol.h"
-#include "streamsocket.h"
-
-namespace Msp {
-namespace Net {
-
-class sequence_error: public std::logic_error
-{
-public:
- sequence_error(const std::string &w): std::logic_error(w) { }
- virtual ~sequence_error() throw() { }
-};
-
-
-class Communicator
-{
-public:
- sigc::signal<void> signal_handshake_done;
-
-private:
- StreamSocket &socket;
- const Protocol &protocol;
- ReceiverBase &receiver;
- int handshake_status;
- unsigned buf_size;
- char *in_buf;
- char *in_begin;
- char *in_end;
- char *out_buf;
- bool good;
-
-public:
- Communicator(StreamSocket &, const Protocol &, ReceiverBase &);
- ~Communicator();
-
- void initiate_handshake();
- bool is_handshake_done() const { return handshake_status==2; }
-
- template<typename P>
- void send(const P &pkt)
- {
- if(!good)
- throw sequence_error("connection aborted");
- if(handshake_status!=2)
- throw sequence_error("handshaking not done");
- unsigned size = protocol.assemble(pkt, out_buf, buf_size);
- socket.write(out_buf, size);
- }
-
-private:
- void data_available();
- bool receive_packet(const Protocol &, ReceiverBase &);
- void send_handshake();
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <stdexcept>
-#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#endif
-#include "constants.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-int family_to_sys(Family f)
-{
- switch(f)
- {
- case UNSPEC: return AF_UNSPEC;
- case INET: return AF_INET;
- case INET6: return AF_INET6;
- case UNIX: return AF_UNIX;
- default: throw invalid_argument("family_to_sys");
- }
-}
-
-Family family_from_sys(int f)
-{
- switch(f)
- {
- case AF_UNSPEC: return UNSPEC;
- case AF_INET: return INET;
- case AF_INET6: return INET6;
- case AF_UNIX: return UNIX;
- default: throw invalid_argument("family_from_sys");
- }
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_CONSTANTS_H_
-#define MSP_NET_CONSTANTS_H_
-
-namespace Msp {
-namespace Net {
-
-enum Family
-{
- UNSPEC,
- INET,
- INET6,
- UNIX
-};
-
-int family_to_sys(Family);
-Family family_from_sys(int);
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <cerrno>
-#include <msp/core/systemerror.h>
-#include <msp/io/handle_private.h>
-#include <msp/strings/format.h>
-#include "datagramsocket.h"
-#include "sockaddr_private.h"
-#include "socket_private.h"
-
-namespace Msp {
-namespace Net {
-
-DatagramSocket::DatagramSocket(Family f, int p):
- ClientSocket(f, SOCK_DGRAM, p)
-{
-#ifdef WIN32
- WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
- set_events(IO::P_INPUT);
-}
-
-bool DatagramSocket::connect(const SockAddr &addr)
-{
- SockAddr::SysAddr sa = addr.to_sys();
-
- int err = ::connect(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
- if(err==-1)
- {
-#ifdef WIN32
- throw system_error("connect", WSAGetLastError());
-#else
- throw system_error("connect");
-#endif
- }
-
- delete peer_addr;
- peer_addr = addr.copy();
-
- delete local_addr;
- SockAddr::SysAddr lsa;
- getsockname(priv->handle, reinterpret_cast<sockaddr *>(&lsa.addr), &lsa.size);
- local_addr = SockAddr::new_from_sys(lsa);
-
- connected = true;
-
- return true;
-}
-
-unsigned DatagramSocket::sendto(const char *buf, unsigned size, const SockAddr &addr)
-{
- if(size==0)
- return 0;
-
- SockAddr::SysAddr sa = addr.to_sys();
-
- int ret = ::sendto(priv->handle, buf, size, 0, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
- if(ret<0)
- {
- if(errno==EAGAIN)
- return 0;
- else
- {
-#ifdef WIN32
- throw system_error("sendto", WSAGetLastError());
-#else
- throw system_error("sendto");
-#endif
- }
- }
-
- return ret;
-}
-
-unsigned DatagramSocket::recvfrom(char *buf, unsigned size, SockAddr *&from_addr)
-{
- if(size==0)
- return 0;
-
- SockAddr::SysAddr sa;
- int ret = ::recvfrom(priv->handle, buf, size, 0, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
- if(ret<0)
- {
- if(errno==EAGAIN)
- return 0;
- else
- {
-#ifdef WIN32
- throw system_error("recvfrom", WSAGetLastError());
-#else
- throw system_error("recvfrom");
-#endif
- }
- }
-
- from_addr = SockAddr::new_from_sys(sa);
-
- return ret;
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_DATAGRAMSOCKET_H_
-#define MSP_NET_DATAGRAMSOCKET_H_
-
-#include "clientsocket.h"
-
-namespace Msp {
-namespace Net {
-
-class DatagramSocket: public ClientSocket
-{
-public:
- DatagramSocket(Family, int = 0);
-
- virtual bool connect(const SockAddr &);
- virtual bool poll_connect(const Time::TimeDelta &) { return false; }
-
- unsigned sendto(const char *, unsigned, const SockAddr &);
- unsigned recvfrom(char *, unsigned, SockAddr *&);
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <netinet/in.h>
-#endif
-#include <msp/strings/format.h>
-#include "inet.h"
-#include "sockaddr_private.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-InetAddr::InetAddr():
- port(0)
-{
- fill(addr, addr+4, 0);
-}
-
-InetAddr::InetAddr(const SysAddr &sa)
-{
- const sockaddr_in &sai = reinterpret_cast<const sockaddr_in &>(sa.addr);
- addr[0] = sai.sin_addr.s_addr>>24;
- addr[1] = sai.sin_addr.s_addr>>16;
- addr[2] = sai.sin_addr.s_addr>>8;
- addr[3] = sai.sin_addr.s_addr;
- port = ntohs(sai.sin_port);
-}
-
-SockAddr::SysAddr InetAddr::to_sys() const
-{
- SysAddr sa;
- sa.size = sizeof(sockaddr_in);
- sockaddr_in &sai = reinterpret_cast<sockaddr_in &>(sa.addr);
- sai.sin_family = AF_INET;
- sai.sin_addr.s_addr = (addr[0]<<24) | (addr[1]<<16) | (addr[2]<<8) | (addr[3]);
- sai.sin_port = htons(port);
-
- return sa;
-}
-
-string InetAddr::str() const
-{
- string result = format("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
- if(port)
- result += format(":%d", port);
- return result;
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_INET_H_
-#define MSP_NET_INET_H_
-
-#include "sockaddr.h"
-
-namespace Msp {
-namespace Net {
-
-/**
-Address class for IPv4 sockets.
-*/
-class InetAddr: public SockAddr
-{
-private:
- unsigned char addr[4];
- unsigned port;
-
-public:
- InetAddr();
- InetAddr(const SysAddr &);
-
- virtual InetAddr *copy() const { return new InetAddr(*this); }
-
- virtual SysAddr to_sys() const;
-
- virtual Family get_family() const { return INET; }
- unsigned get_port() const { return port; }
- virtual std::string str() const;
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifdef WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <netinet/in.h>
-#endif
-#include <msp/strings/format.h>
-#include "inet6.h"
-#include "sockaddr_private.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-Inet6Addr::Inet6Addr():
- port(0)
-{
- fill(addr, addr+16, 0);
-}
-
-Inet6Addr::Inet6Addr(const SysAddr &sa)
-{
- const sockaddr_in6 &sai6 = reinterpret_cast<const sockaddr_in6 &>(sa.addr);
- std::copy(sai6.sin6_addr.s6_addr, sai6.sin6_addr.s6_addr+16, addr);
- port = htons(sai6.sin6_port);
-}
-
-SockAddr::SysAddr Inet6Addr::to_sys() const
-{
- SysAddr sa;
- sa.size = sizeof(sockaddr_in6);
- sockaddr_in6 &sai6 = reinterpret_cast<sockaddr_in6 &>(sa.addr);
- sai6.sin6_family = AF_INET6;
- std::copy(addr, addr+16, sai6.sin6_addr.s6_addr);
- sai6.sin6_port = htons(port);
- sai6.sin6_flowinfo = 0;
- sai6.sin6_scope_id = 0;
-
- return sa;
-}
-
-string Inet6Addr::str() const
-{
- string result = "[";
- for(unsigned i=0; i<16; i+=2)
- {
- unsigned short part = (addr[i]<<8) | addr[i+1];
- if(i>0)
- result += ':';
- result += format("%x", part);
- }
- result += ']';
- if(port)
- result += format(":%d", port);
-
- return result;
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_INET6_H_
-#define NSP_NET_INET6_H_
-
-#include "sockaddr.h"
-
-namespace Msp {
-namespace Net {
-
-class Inet6Addr: public SockAddr
-{
-private:
- unsigned char addr[16];
- unsigned port;
-
-public:
- Inet6Addr();
- Inet6Addr(const SysAddr &);
-
- virtual Inet6Addr *copy() const { return new Inet6Addr(*this); }
-
- virtual SysAddr to_sys() const;
-
- virtual Family get_family() const { return INET6; }
- unsigned get_port() const { return port; }
- virtual std::string str() const;
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
--- /dev/null
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <cerrno>
+#include <sys/socket.h>
+#endif
+#include <msp/core/systemerror.h>
+#include "clientsocket.h"
+#include "socket_private.h"
+
+namespace Msp {
+namespace Net {
+
+ClientSocket::ClientSocket(Family af, int type, int proto):
+ Socket(af, type, proto),
+ connecting(false),
+ connected(false),
+ peer_addr(0)
+{ }
+
+ClientSocket::ClientSocket(const Private &p, const SockAddr &paddr):
+ Socket(p),
+ connecting(false),
+ connected(true),
+ peer_addr(paddr.copy())
+{ }
+
+ClientSocket::~ClientSocket()
+{
+ signal_flush_required.emit();
+
+ delete peer_addr;
+}
+
+const SockAddr &ClientSocket::get_peer_address() const
+{
+ if(peer_addr==0)
+ throw bad_socket_state("not connected");
+ return *peer_addr;
+}
+
+unsigned ClientSocket::do_write(const char *buf, unsigned size)
+{
+ if(!connected)
+ throw bad_socket_state("not connected");
+
+ if(size==0)
+ return 0;
+
+ int ret = ::send(priv->handle, buf, size, 0);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw system_error("send");
+ }
+
+ return ret;
+}
+
+unsigned ClientSocket::do_read(char *buf, unsigned size)
+{
+ if(!connected)
+ throw bad_socket_state("not connected");
+
+ if(size==0)
+ return 0;
+
+ int ret = ::recv(priv->handle, buf, size, 0);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw system_error("recv");
+ }
+ else if(ret==0 && !eof_flag)
+ {
+ eof_flag = true;
+ signal_end_of_file.emit();
+ set_events(IO::P_NONE);
+ }
+
+ return ret;
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_CLIENTSOCKET_H_
+#define MSP_NET_CLIENTSOCKET_H_
+
+#include "socket.h"
+
+namespace Msp {
+namespace Net {
+
+/**
+ClientSockets are used for sending and receiving data over the network.
+*/
+class ClientSocket: public Socket
+{
+public:
+ /** Emitted when the socket finishes connecting. */
+ sigc::signal<void, const std::exception *> signal_connect_finished;
+
+protected:
+ bool connecting;
+ bool connected;
+ SockAddr *peer_addr;
+
+ ClientSocket(const Private &, const SockAddr &);
+ ClientSocket(Family, int, int);
+public:
+ virtual ~ClientSocket();
+
+ /** Connects to a remote address. Exact semantics depend on the socket
+ type. Returns true if the connection was established, false if it's in
+ progress. */
+ virtual bool connect(const SockAddr &) = 0;
+
+ /** Checks the status of a connection being established. Returns true if
+ the connection was established successfully, false if it's still in
+ progress. If an error occurred, an exception is thrown. */
+ virtual bool poll_connect(const Time::TimeDelta &) = 0;
+
+ bool is_connecting() const { return connecting; }
+ bool is_connected() const { return connected; }
+
+ const SockAddr &get_peer_address() const;
+protected:
+ virtual unsigned do_write(const char *, unsigned);
+ virtual unsigned do_read(char *, unsigned);
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <cstring>
+#include "communicator.h"
+
+namespace {
+
+using namespace Msp::Net;
+
+struct Handshake
+{
+ unsigned hash;
+};
+
+
+class HandshakeProtocol: public Protocol
+{
+public:
+ HandshakeProtocol();
+};
+
+HandshakeProtocol::HandshakeProtocol():
+ Protocol(0x7F00)
+{
+ add<Handshake>()(&Handshake::hash);
+}
+
+
+class HandshakeReceiver: public PacketReceiver<Handshake>
+{
+private:
+ unsigned hash;
+
+public:
+ HandshakeReceiver();
+ unsigned get_hash() const { return hash; }
+ virtual void receive(const Handshake &);
+};
+
+HandshakeReceiver::HandshakeReceiver():
+ hash(0)
+{ }
+
+void HandshakeReceiver::receive(const Handshake &shake)
+{
+ hash = shake.hash;
+}
+
+}
+
+
+namespace Msp {
+namespace Net {
+
+Communicator::Communicator(StreamSocket &s, const Protocol &p, ReceiverBase &r):
+ socket(s),
+ protocol(p),
+ receiver(r),
+ handshake_status(0),
+ buf_size(1024),
+ in_buf(new char[buf_size]),
+ in_begin(in_buf),
+ in_end(in_buf),
+ out_buf(new char[buf_size]),
+ good(true)
+{
+ socket.signal_data_available.connect(sigc::mem_fun(this, &Communicator::data_available));
+}
+
+Communicator::~Communicator()
+{
+ delete[] in_buf;
+ delete[] out_buf;
+}
+
+void Communicator::initiate_handshake()
+{
+ if(handshake_status!=0)
+ throw sequence_error("handshaking already done");
+
+ send_handshake();
+ handshake_status = 1;
+}
+
+void Communicator::data_available()
+{
+ if(!good)
+ return;
+
+ in_end += socket.read(in_end, in_buf+buf_size-in_end);
+ try
+ {
+ bool more = true;
+ while(more)
+ {
+ if(handshake_status==2)
+ {
+ more = receive_packet(protocol, receiver);
+ }
+ else
+ {
+ HandshakeProtocol hsproto;
+ HandshakeReceiver hsrecv;
+ if((more = receive_packet(hsproto, hsrecv)))
+ {
+ if(hsrecv.get_hash()==protocol.get_hash())
+ {
+ if(handshake_status==0)
+ send_handshake();
+ handshake_status = 2;
+ signal_handshake_done.emit();
+ }
+ else
+ good = false;
+ }
+ }
+ }
+ }
+ catch(...)
+ {
+ good = false;
+ throw;
+ }
+}
+
+bool Communicator::receive_packet(const Protocol &proto, ReceiverBase &recv)
+{
+ int psz = proto.get_packet_size(in_begin, in_end-in_begin);
+ if(psz && psz<=in_end-in_begin)
+ {
+ char *pkt = in_begin;
+ in_begin += psz;
+ proto.disassemble(recv, pkt, psz);
+ return true;
+ }
+ else
+ {
+ if(in_end==in_buf+buf_size)
+ {
+ unsigned used = in_end-in_begin;
+ memmove(in_buf, in_begin, used);
+ in_begin = in_buf;
+ in_end = in_begin+used;
+ }
+ return false;
+ }
+}
+
+void Communicator::send_handshake()
+{
+ Handshake shake;
+ shake.hash = protocol.get_hash();
+
+ HandshakeProtocol hsproto;
+ unsigned size = hsproto.assemble(shake, out_buf, buf_size);
+ socket.write(out_buf, size);
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_COMMUNICATOR_H_
+#define MSP_NET_COMMUNICATOR_H_
+
+#include "protocol.h"
+#include "streamsocket.h"
+
+namespace Msp {
+namespace Net {
+
+class sequence_error: public std::logic_error
+{
+public:
+ sequence_error(const std::string &w): std::logic_error(w) { }
+ virtual ~sequence_error() throw() { }
+};
+
+
+class Communicator
+{
+public:
+ sigc::signal<void> signal_handshake_done;
+
+private:
+ StreamSocket &socket;
+ const Protocol &protocol;
+ ReceiverBase &receiver;
+ int handshake_status;
+ unsigned buf_size;
+ char *in_buf;
+ char *in_begin;
+ char *in_end;
+ char *out_buf;
+ bool good;
+
+public:
+ Communicator(StreamSocket &, const Protocol &, ReceiverBase &);
+ ~Communicator();
+
+ void initiate_handshake();
+ bool is_handshake_done() const { return handshake_status==2; }
+
+ template<typename P>
+ void send(const P &pkt)
+ {
+ if(!good)
+ throw sequence_error("connection aborted");
+ if(handshake_status!=2)
+ throw sequence_error("handshaking not done");
+ unsigned size = protocol.assemble(pkt, out_buf, buf_size);
+ socket.write(out_buf, size);
+ }
+
+private:
+ void data_available();
+ bool receive_packet(const Protocol &, ReceiverBase &);
+ void send_handshake();
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <stdexcept>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+#include "constants.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+int family_to_sys(Family f)
+{
+ switch(f)
+ {
+ case UNSPEC: return AF_UNSPEC;
+ case INET: return AF_INET;
+ case INET6: return AF_INET6;
+ case UNIX: return AF_UNIX;
+ default: throw invalid_argument("family_to_sys");
+ }
+}
+
+Family family_from_sys(int f)
+{
+ switch(f)
+ {
+ case AF_UNSPEC: return UNSPEC;
+ case AF_INET: return INET;
+ case AF_INET6: return INET6;
+ case AF_UNIX: return UNIX;
+ default: throw invalid_argument("family_from_sys");
+ }
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_CONSTANTS_H_
+#define MSP_NET_CONSTANTS_H_
+
+namespace Msp {
+namespace Net {
+
+enum Family
+{
+ UNSPEC,
+ INET,
+ INET6,
+ UNIX
+};
+
+int family_to_sys(Family);
+Family family_from_sys(int);
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#include <msp/strings/format.h>
+#include "datagramsocket.h"
+#include "sockaddr_private.h"
+#include "socket_private.h"
+
+namespace Msp {
+namespace Net {
+
+DatagramSocket::DatagramSocket(Family f, int p):
+ ClientSocket(f, SOCK_DGRAM, p)
+{
+#ifdef WIN32
+ WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
+#endif
+ set_events(IO::P_INPUT);
+}
+
+bool DatagramSocket::connect(const SockAddr &addr)
+{
+ SockAddr::SysAddr sa = addr.to_sys();
+
+ int err = ::connect(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
+ if(err==-1)
+ {
+#ifdef WIN32
+ throw system_error("connect", WSAGetLastError());
+#else
+ throw system_error("connect");
+#endif
+ }
+
+ delete peer_addr;
+ peer_addr = addr.copy();
+
+ delete local_addr;
+ SockAddr::SysAddr lsa;
+ getsockname(priv->handle, reinterpret_cast<sockaddr *>(&lsa.addr), &lsa.size);
+ local_addr = SockAddr::new_from_sys(lsa);
+
+ connected = true;
+
+ return true;
+}
+
+unsigned DatagramSocket::sendto(const char *buf, unsigned size, const SockAddr &addr)
+{
+ if(size==0)
+ return 0;
+
+ SockAddr::SysAddr sa = addr.to_sys();
+
+ int ret = ::sendto(priv->handle, buf, size, 0, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ {
+#ifdef WIN32
+ throw system_error("sendto", WSAGetLastError());
+#else
+ throw system_error("sendto");
+#endif
+ }
+ }
+
+ return ret;
+}
+
+unsigned DatagramSocket::recvfrom(char *buf, unsigned size, SockAddr *&from_addr)
+{
+ if(size==0)
+ return 0;
+
+ SockAddr::SysAddr sa;
+ int ret = ::recvfrom(priv->handle, buf, size, 0, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ {
+#ifdef WIN32
+ throw system_error("recvfrom", WSAGetLastError());
+#else
+ throw system_error("recvfrom");
+#endif
+ }
+ }
+
+ from_addr = SockAddr::new_from_sys(sa);
+
+ return ret;
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_DATAGRAMSOCKET_H_
+#define MSP_NET_DATAGRAMSOCKET_H_
+
+#include "clientsocket.h"
+
+namespace Msp {
+namespace Net {
+
+class DatagramSocket: public ClientSocket
+{
+public:
+ DatagramSocket(Family, int = 0);
+
+ virtual bool connect(const SockAddr &);
+ virtual bool poll_connect(const Time::TimeDelta &) { return false; }
+
+ unsigned sendto(const char *, unsigned, const SockAddr &);
+ unsigned recvfrom(char *, unsigned, SockAddr *&);
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+#include <msp/strings/format.h>
+#include "inet.h"
+#include "sockaddr_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+InetAddr::InetAddr():
+ port(0)
+{
+ fill(addr, addr+4, 0);
+}
+
+InetAddr::InetAddr(const SysAddr &sa)
+{
+ const sockaddr_in &sai = reinterpret_cast<const sockaddr_in &>(sa.addr);
+ addr[0] = sai.sin_addr.s_addr>>24;
+ addr[1] = sai.sin_addr.s_addr>>16;
+ addr[2] = sai.sin_addr.s_addr>>8;
+ addr[3] = sai.sin_addr.s_addr;
+ port = ntohs(sai.sin_port);
+}
+
+SockAddr::SysAddr InetAddr::to_sys() const
+{
+ SysAddr sa;
+ sa.size = sizeof(sockaddr_in);
+ sockaddr_in &sai = reinterpret_cast<sockaddr_in &>(sa.addr);
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = (addr[0]<<24) | (addr[1]<<16) | (addr[2]<<8) | (addr[3]);
+ sai.sin_port = htons(port);
+
+ return sa;
+}
+
+string InetAddr::str() const
+{
+ string result = format("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
+ if(port)
+ result += format(":%d", port);
+ return result;
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_INET_H_
+#define MSP_NET_INET_H_
+
+#include "sockaddr.h"
+
+namespace Msp {
+namespace Net {
+
+/**
+Address class for IPv4 sockets.
+*/
+class InetAddr: public SockAddr
+{
+private:
+ unsigned char addr[4];
+ unsigned port;
+
+public:
+ InetAddr();
+ InetAddr(const SysAddr &);
+
+ virtual InetAddr *copy() const { return new InetAddr(*this); }
+
+ virtual SysAddr to_sys() const;
+
+ virtual Family get_family() const { return INET; }
+ unsigned get_port() const { return port; }
+ virtual std::string str() const;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netinet/in.h>
+#endif
+#include <msp/strings/format.h>
+#include "inet6.h"
+#include "sockaddr_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+Inet6Addr::Inet6Addr():
+ port(0)
+{
+ fill(addr, addr+16, 0);
+}
+
+Inet6Addr::Inet6Addr(const SysAddr &sa)
+{
+ const sockaddr_in6 &sai6 = reinterpret_cast<const sockaddr_in6 &>(sa.addr);
+ std::copy(sai6.sin6_addr.s6_addr, sai6.sin6_addr.s6_addr+16, addr);
+ port = htons(sai6.sin6_port);
+}
+
+SockAddr::SysAddr Inet6Addr::to_sys() const
+{
+ SysAddr sa;
+ sa.size = sizeof(sockaddr_in6);
+ sockaddr_in6 &sai6 = reinterpret_cast<sockaddr_in6 &>(sa.addr);
+ sai6.sin6_family = AF_INET6;
+ std::copy(addr, addr+16, sai6.sin6_addr.s6_addr);
+ sai6.sin6_port = htons(port);
+ sai6.sin6_flowinfo = 0;
+ sai6.sin6_scope_id = 0;
+
+ return sa;
+}
+
+string Inet6Addr::str() const
+{
+ string result = "[";
+ for(unsigned i=0; i<16; i+=2)
+ {
+ unsigned short part = (addr[i]<<8) | addr[i+1];
+ if(i>0)
+ result += ':';
+ result += format("%x", part);
+ }
+ result += ']';
+ if(port)
+ result += format(":%d", port);
+
+ return result;
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_INET6_H_
+#define NSP_NET_INET6_H_
+
+#include "sockaddr.h"
+
+namespace Msp {
+namespace Net {
+
+class Inet6Addr: public SockAddr
+{
+private:
+ unsigned char addr[16];
+ unsigned port;
+
+public:
+ Inet6Addr();
+ Inet6Addr(const SysAddr &);
+
+ virtual Inet6Addr *copy() const { return new Inet6Addr(*this); }
+
+ virtual SysAddr to_sys() const;
+
+ virtual Family get_family() const { return INET6; }
+ unsigned get_port() const { return port; }
+ virtual std::string str() const;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <cstring>
+#include <string>
+#include <msp/core/maputils.h>
+#include <msp/strings/lexicalcast.h>
+#include "protocol.h"
+
+using namespace std;
+
+namespace {
+
+using Msp::Net::buffer_error;
+
+template<typename T>
+class Assembler
+{
+public:
+ static char *assemble(const T &v, char *, char *);
+ static const char *disassemble(T &, const char *, const char *);
+};
+
+template<typename T>
+class Assembler<vector<T> >
+{
+public:
+ static char *assemble(const vector<T> &v, char *, char *);
+ static const char *disassemble(vector<T> &, const char *, const char *);
+};
+
+template<typename T>
+char *Assembler<T>::assemble(const T &v, char *data, char *end)
+{
+ // XXX Assumes little-endian
+ const char *ptr = reinterpret_cast<const char *>(&v)+sizeof(T);
+ for(unsigned i=0; i<sizeof(T); ++i)
+ {
+ if(data==end)
+ throw buffer_error("overflow");
+ *data++ = *--ptr;
+ }
+ return data;
+}
+
+template<>
+char *Assembler<string>::assemble(const string &v, char *data, char *end)
+{
+ data = Assembler<unsigned short>::assemble(v.size(), data, end);
+ if(end-data<static_cast<int>(v.size()))
+ throw buffer_error("overflow");
+ memcpy(data, v.data(), v.size());
+ return data+v.size();
+}
+
+template<typename T>
+char *Assembler<vector<T> >::assemble(const vector<T> &v, char *data, char *end)
+{
+ data = Assembler<unsigned short>::assemble(v.size(), data, end);
+ for(typename vector<T>::const_iterator i=v.begin(); i!=v.end(); ++i)
+ data = Assembler<T>::assemble(*i, data, end);
+ return data;
+}
+
+template<typename T>
+const char *Assembler<T>::disassemble(T &v, const char *data, const char *end)
+{
+ char *ptr = reinterpret_cast<char *>(&v)+sizeof(T);
+ for(unsigned i=0; i<sizeof(T); ++i)
+ {
+ if(data==end)
+ throw buffer_error("underflow");
+ *--ptr = *data++;
+ }
+ return data;
+}
+
+template<>
+const char *Assembler<string>::disassemble(string &v, const char *data, const char *end)
+{
+ unsigned short size;
+ data = Assembler<unsigned short>::disassemble(size, data, end);
+ if(end-data<size)
+ throw buffer_error("underflow");
+ v.assign(data, data+size);
+ return data+size;
+}
+
+template<typename T>
+const char *Assembler<vector<T> >::disassemble(vector<T> &v, const char *data, const char *end)
+{
+ /* We assume that the vector is in pristine state - this holds because the
+ only code path leading here is from PacketDef<P>::disassemble, which creates
+ a new packet. */
+ unsigned short size;
+ data = Assembler<unsigned short>::disassemble(size, data, end);
+ for(unsigned i=0; i<size; ++i)
+ {
+ T u;
+ data = Assembler<T>::disassemble(u, data, end);
+ v.push_back(u);
+ }
+ return data;
+}
+
+}
+
+namespace Msp {
+namespace Net {
+
+Protocol::Protocol(unsigned npi):
+ next_packet_id(npi)
+{ }
+
+Protocol::~Protocol()
+{
+ for(map<unsigned, PacketDefBase *>::iterator i=packet_class_defs.begin(); i!=packet_class_defs.end(); ++i)
+ delete i->second;
+}
+
+void Protocol::add_packet(PacketDefBase &pdef)
+{
+ PacketDefBase *&ptr = packet_class_defs[pdef.get_class_id()];
+ if(ptr)
+ delete ptr;
+ ptr = &pdef;
+ packet_id_defs[pdef.get_id()] = &pdef;
+}
+
+const Protocol::PacketDefBase &Protocol::get_packet_by_class(unsigned id) const
+{
+ return *get_item(packet_class_defs, id);
+}
+
+const Protocol::PacketDefBase &Protocol::get_packet_by_id(unsigned id) const
+{
+ return *get_item(packet_id_defs, id);
+}
+
+unsigned Protocol::disassemble(ReceiverBase &rcv, const char *data, unsigned size) const
+{
+ const unsigned char *udata = reinterpret_cast<const unsigned char *>(data);
+ unsigned id = (udata[0]<<8)+udata[1];
+ unsigned psz = (udata[2]<<8)+udata[3];
+ if(psz>size)
+ throw bad_packet("truncated");
+ const PacketDefBase &pdef = get_packet_by_id(id);
+ const char *ptr = pdef.disassemble(rcv, data+4, data+psz);
+ return ptr-data;
+}
+
+unsigned Protocol::get_packet_size(const char *data, unsigned size) const
+{
+ if(size<4)
+ return 0;
+ const unsigned char *udata = reinterpret_cast<const unsigned char *>(data);
+ return (udata[2]<<8)+udata[3];
+}
+
+unsigned Protocol::get_hash() const
+{
+ // TODO
+ return 123;
+}
+
+void Protocol::assemble_header(char *buf, unsigned id, unsigned size)
+{
+ buf[0] = (id>>8)&0xFF;
+ buf[1] = id&0xFF;
+ buf[2] = (size>>8)&0xFF;
+ buf[3] = size&0xFF;
+}
+
+template<typename T>
+char *Protocol::assemble_field(const T &v, char *d, char *e)
+{ return Assembler<T>::assemble(v, d, e); }
+
+template char *Protocol::assemble_field<>(const char &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const signed char &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const unsigned char &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const short &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const unsigned short &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const int &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const unsigned &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const long &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const unsigned long &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const float &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const double &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const string &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<char> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<signed char> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<unsigned char> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<short> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<unsigned short> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<int> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<unsigned> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<long> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<unsigned long> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<float> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<double> &v, char *d, char *e);
+template char *Protocol::assemble_field<>(const vector<string> &v, char *d, char *e);
+
+template<typename T>
+const char *Protocol::disassemble_field(T &v, const char *d, const char *e)
+{ return Assembler<T>::disassemble(v, d, e); }
+
+template const char *Protocol::disassemble_field<>(char &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(signed char &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(unsigned char &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(short &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(unsigned short &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(int &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(unsigned &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(long &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(unsigned long &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(float &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(double &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(string &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<char> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<signed char> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<unsigned char> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<short> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<unsigned short> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<int> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<unsigned> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<long> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<unsigned long> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<float> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<double> &v, const char *d, const char *e);
+template const char *Protocol::disassemble_field<>(vector<string> &v, const char *d, const char *e);
+
+unsigned Protocol::PacketDefBase::next_class_id = 1;
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_PROTOCOL_H_
+#define MSP_NET_PROTOCOL_H_
+
+#include <map>
+#include <stdexcept>
+#include <vector>
+#include "receiver.h"
+
+namespace Msp {
+namespace Net {
+
+class bad_packet: public std::runtime_error
+{
+public:
+ bad_packet(const std::string &w): std::runtime_error(w) { }
+ virtual ~bad_packet() throw() { }
+};
+
+
+class buffer_error: public std::runtime_error
+{
+public:
+ buffer_error(const std::string &w): std::runtime_error(w) { }
+ virtual ~buffer_error() throw() { }
+};
+
+
+class Protocol
+{
+private:
+ class PacketDefBase
+ {
+ protected:
+ unsigned id;
+
+ PacketDefBase(unsigned i): id(i) { }
+ public:
+ virtual ~PacketDefBase() { }
+ virtual unsigned get_class_id() const = 0;
+ unsigned get_id() const { return id; }
+ virtual const char *disassemble(ReceiverBase &, const char *, const char *) const = 0;
+
+ static unsigned next_class_id;
+ };
+
+ template<typename P>
+ class FieldBase
+ {
+ protected:
+ FieldBase() { }
+ public:
+ virtual ~FieldBase() { }
+ virtual char *assemble(const P &, char *, char *) const = 0;
+ virtual const char *disassemble(P &, const char *, const char *) const = 0;
+ };
+
+ template<typename P, typename T>
+ class Field: public FieldBase<P>
+ {
+ private:
+ T P::*ptr;
+
+ public:
+ Field(T P::*p): ptr(p) { }
+
+ virtual char *assemble(const P &p, char *d, char *e) const
+ { return assemble_field(p.*ptr, d, e); }
+
+ virtual const char *disassemble(P &p, const char *d, const char *e) const
+ { return disassemble_field(p.*ptr, d, e); }
+ };
+
+protected:
+ template<typename P>
+ class PacketDef: public PacketDefBase
+ {
+ private:
+ std::vector<FieldBase<P> *> fields;
+
+ public:
+ PacketDef(unsigned i): PacketDefBase(i)
+ { if(!class_id) class_id = next_class_id++; }
+
+ ~PacketDef()
+ {
+ for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
+ delete *i;
+ }
+
+ virtual unsigned get_class_id() const { return class_id; }
+
+ template<typename T>
+ PacketDef &operator()(T P::*p)
+ { fields.push_back(new Field<P, T>(p)); return *this; }
+
+ char *assemble(const P &p, char *d, char *e) const
+ {
+ for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
+ d = (*i)->assemble(p, d, e);
+ return d;
+ }
+
+ const char *disassemble(ReceiverBase &r, const char *d, const char *e) const
+ {
+ PacketReceiver<P> *prcv = dynamic_cast<PacketReceiver<P> *>(&r);
+ if(!prcv)
+ throw bad_packet("unsupported");
+ P pkt;
+ for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
+ d = (*i)->disassemble(pkt, d, e);
+ prcv->receive(pkt);
+ return d;
+ }
+
+ static unsigned class_id;
+ };
+
+ typedef std::map<unsigned, PacketDefBase *> PacketMap;
+
+ unsigned next_packet_id;
+ PacketMap packet_class_defs;
+ PacketMap packet_id_defs;
+
+ Protocol(unsigned = 1);
+public:
+ ~Protocol();
+
+private:
+ void add_packet(PacketDefBase &);
+
+protected:
+ template<typename P>
+ PacketDef<P> &add()
+ {
+ PacketDef<P> *pdef = new PacketDef<P>(next_packet_id++);
+ add_packet(*pdef);
+ return *pdef;
+ }
+
+ const PacketDefBase &get_packet_by_class(unsigned) const;
+ const PacketDefBase &get_packet_by_id(unsigned) const;
+
+public:
+ template<typename P>
+ unsigned assemble(const P &pkt, char *buf, unsigned size) const
+ {
+ unsigned id = PacketDef<P>::class_id;
+ const PacketDef<P> &pdef = static_cast<const PacketDef<P> &>(get_packet_by_class(id));
+ char *ptr = pdef.assemble(pkt, buf+4, buf+size);
+ assemble_header(buf, pdef.get_id(), (size = ptr-buf));
+ return size;
+ }
+
+ unsigned disassemble(ReceiverBase &, const char *, unsigned) const;
+
+ unsigned get_packet_size(const char *, unsigned) const;
+
+ unsigned get_hash() const;
+
+private:
+ static void assemble_header(char *, unsigned, unsigned);
+
+ template<typename T>
+ static char *assemble_field(const T &, char *, char *);
+
+ template<typename T>
+ static const char *disassemble_field(T &, const char *, const char *);
+};
+
+template<typename P>
+unsigned Protocol::PacketDef<P>::class_id = 0;
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_NET_RECEIVER_H_
+#define MSP_NET_RECEIVER_H_
+
+namespace Msp {
+namespace Net {
+
+class ReceiverBase
+{
+protected:
+ ReceiverBase() { }
+public:
+ virtual ~ReceiverBase() { }
+};
+
+template<typename P>
+class PacketReceiver: public virtual ReceiverBase
+{
+protected:
+ PacketReceiver() { }
+public:
+ virtual void receive(const P &) = 0;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
+#endif
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include "sockaddr_private.h"
+#include "socket.h"
+#include "resolve.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+SockAddr *resolve(const string &host, const string &serv, Family family)
+{
+ const char *chost = (host.empty() ? 0 : host.c_str());
+ const char *cserv = (serv.empty() ? 0 : serv.c_str());
+ unsigned flags = 0;
+ if(host=="*")
+ {
+ flags = AI_PASSIVE;
+ chost = 0;
+ }
+
+ addrinfo hints = { flags, family_to_sys(family), 0, 0, 0, 0, 0, 0 };
+ addrinfo *res;
+
+ int err = getaddrinfo(chost, cserv, &hints, &res);
+ if(err==0)
+ {
+ SockAddr::SysAddr sa;
+ sa.size = res->ai_addrlen;
+ const char *sptr = reinterpret_cast<const char *>(res->ai_addr);
+ char *dptr = reinterpret_cast<char *>(&sa.addr);
+ copy(sptr, sptr+res->ai_addrlen, dptr);
+ SockAddr *addr = SockAddr::new_from_sys(sa);
+ freeaddrinfo(res);
+ return addr;
+ }
+ else
+#ifdef WIN32
+ throw system_error("getaddrinfo", WSAGetLastError());
+#else
+ throw system_error("getaddrinfo", gai_strerror(err));
+#endif
+}
+
+SockAddr *resolve(const string &str, Family family)
+{
+ string host, serv;
+ if(str[0]=='[')
+ {
+ unsigned bracket = str.find(']');
+ host = str.substr(1, bracket-1);
+ unsigned colon = str.find(':', bracket);
+ if(colon!=string::npos)
+ serv = str.substr(colon+1);
+ }
+ else
+ {
+ unsigned colon = str.find(':');
+ if(colon!=string::npos)
+ {
+ host = str.substr(0, colon);
+ serv = str.substr(colon+1);
+ }
+ else
+ host = str;
+ }
+
+ return resolve(host, serv, family);
+}
+
+ /*sockaddr sa;
+ unsigned size = fill_sockaddr(sa);
+ char hst[128];
+ char srv[128];
+ int err = getnameinfo(&sa, size, hst, 128, srv, 128, 0);
+ if(err==0)
+ {
+ host = hst;
+ serv = srv;
+ }*/
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_RESOLVE_H_
+#define MSP_NET_RESOLVE_H_
+
+#include <string>
+#include "constants.h"
+
+namespace Msp {
+namespace Net {
+
+class SockAddr;
+
+/** Resolves host and service names into a socket address. If host is empty,
+the loopback address will be used. If host is "*", the wildcard address will
+be used. If service is empty, a socket address with a null service will be
+returned. With the IP families, these are not very useful. */
+SockAddr *resolve(const std::string &, const std::string &, Family = UNSPEC);
+
+/** And overload of resolve() that takes host and service as a single string,
+separated by a colon. If the host part contains colons, such as is the case
+with a numeric IPv6 address, it must be enclosed in brackets. */
+SockAddr *resolve(const std::string &, Family = UNSPEC);
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#include "serversocket.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+ServerSocket::ServerSocket(Family af, int type, int proto):
+ Socket(af, type, proto)
+{ }
+
+unsigned ServerSocket::do_write(const char *, unsigned)
+{
+ throw logic_error("can't write to ServerSocket");
+}
+
+unsigned ServerSocket::do_read(char *, unsigned)
+{
+ throw logic_error("can't read from ServerSocket");
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_SERVERSOCKET_H_
+#define MSP_NET_SERVERSOCKET_H_
+
+#include "socket.h"
+
+namespace Msp {
+namespace Net {
+
+class ClientSocket;
+
+/**
+ServerSockets are used to receive incoming connections. They cannot be used
+for sending and receiving data.
+*/
+class ServerSocket: public Socket
+{
+protected:
+ ServerSocket(Family, int, int);
+
+public:
+ virtual void listen(const SockAddr &, unsigned = 4) = 0;
+
+ virtual ClientSocket *accept() = 0;
+protected:
+ virtual unsigned do_write(const char *, unsigned);
+ virtual unsigned do_read(char *, unsigned);
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <stdexcept>
+#include "inet.h"
+#include "inet6.h"
+#include "sockaddr_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+SockAddr *SockAddr::new_from_sys(const SysAddr &sa)
+{
+ switch(sa.addr.ss_family)
+ {
+ case AF_INET:
+ return new InetAddr(sa);
+ case AF_INET6:
+ return new Inet6Addr(sa);
+ default:
+ throw invalid_argument("SockAddr::create");
+ }
+}
+
+SockAddr::SysAddr::SysAddr():
+ size(sizeof(sockaddr_storage))
+{
+ addr.ss_family = AF_UNSPEC;
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_SOCKADDR_H_
+#define MSP_NET_SOCKADDR_H_
+
+#include <string>
+#include "constants.h"
+
+namespace Msp {
+namespace Net {
+
+class SockAddr
+{
+public:
+ struct SysAddr;
+
+protected:
+ SockAddr() { }
+public:
+ virtual ~SockAddr() { }
+
+ virtual SockAddr *copy() const = 0;
+
+ static SockAddr *new_from_sys(const SysAddr &);
+ virtual SysAddr to_sys() const = 0;
+
+ virtual Family get_family() const = 0;
+ virtual std::string str() const = 0;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_NET_SOCKADDR_PRIVATE_H_
+#define MSP_NET_SOCKADDR_PRIVATE_H_
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+#include "sockaddr.h"
+
+namespace Msp {
+namespace Net {
+
+struct SockAddr::SysAddr
+{
+ struct sockaddr_storage addr;
+#ifdef WIN32
+ int size;
+#else
+ socklen_t size;
+#endif
+
+ SysAddr();
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef WIN32
+#include <cerrno>
+#include <fcntl.h>
+#include <sys/socket.h>
+#endif
+#include <iostream>
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#include <msp/strings/format.h>
+#include <msp/time/rawtime_private.h>
+#include <msp/time/units.h>
+#include "sockaddr_private.h"
+#include "socket.h"
+#include "socket_private.h"
+
+namespace {
+
+#ifdef WIN32
+class WinSockHelper
+{
+public:
+ WinSockHelper()
+ {
+ WSADATA wsa_data;
+ int err = WSAStartup(0x0002, &wsa_data);
+ if(err)
+ std::cerr<<"Failed to initialize WinSock: "<<err<<'\n';
+ }
+
+ ~WinSockHelper()
+ {
+ WSACleanup();
+ }
+};
+
+WinSockHelper wsh;
+#endif
+
+}
+
+namespace Msp {
+namespace Net {
+
+Socket::Socket(const Private &p):
+ priv(new Private),
+ local_addr(0)
+{
+ priv->handle = p.handle;
+
+ SockAddr::SysAddr sa;
+ getsockname(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
+ local_addr = SockAddr::new_from_sys(sa);
+
+#ifdef WIN32
+ *priv->event = CreateEvent(0, false, false, 0);
+#else
+ *priv->event = priv->handle;
+#endif
+}
+
+Socket::Socket(Family af, int type, int proto):
+ priv(new Private),
+ local_addr(0)
+{
+ priv->handle = socket(family_to_sys(af), type, proto);
+
+#ifdef WIN32
+ *priv->event = CreateEvent(0, false, false, 0);
+#else
+ *priv->event = priv->handle;
+#endif
+}
+
+Socket::~Socket()
+{
+#ifdef WIN32
+ closesocket(priv->handle);
+ CloseHandle(*priv->event);
+#else
+ ::close(priv->handle);
+#endif
+
+ delete local_addr;
+ delete priv;
+}
+
+void Socket::set_block(bool b)
+{
+ mode = (mode&~IO::M_NONBLOCK);
+ if(b)
+ mode = (mode|IO::M_NONBLOCK);
+
+#ifdef WIN32
+ u_long flag = !b;
+ ioctlsocket(priv->handle, FIONBIO, &flag);
+#else
+ int flags = fcntl(priv->handle, F_GETFL);
+ fcntl(priv->handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
+#endif
+}
+
+const IO::Handle &Socket::get_event_handle()
+{
+ return priv->event;
+}
+
+
+void Socket::bind(const SockAddr &addr)
+{
+ SockAddr::SysAddr sa = addr.to_sys();
+
+ int err = ::bind(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
+ if(err==-1)
+ throw system_error("bind");
+
+ delete local_addr;
+ local_addr = addr.copy();
+}
+
+const SockAddr &Socket::get_local_address() const
+{
+ if(local_addr==0)
+ throw bad_socket_state("not bound");
+ return *local_addr;
+}
+
+void Socket::set_timeout(const Time::TimeDelta &timeout)
+{
+#ifndef WIN32
+ timeval tv = Time::rawtime_to_timeval(timeout.raw());
+ set_option(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
+ set_option(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
+#else
+ DWORD msecs = static_cast<DWORD>(timeout/Time::msec);
+ set_option(SOL_SOCKET, SO_RCVTIMEO, &msecs, sizeof(DWORD));
+ set_option(SOL_SOCKET, SO_SNDTIMEO, &msecs, sizeof(DWORD));
+#endif
+}
+
+int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen)
+{
+#ifdef WIN32
+ return setsockopt(priv->handle, level, optname, reinterpret_cast<const char *>(optval), optlen);
+#else
+ return setsockopt(priv->handle, level, optname, optval, optlen);
+#endif
+}
+
+int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) const
+{
+#ifdef WIN32
+ return getsockopt(priv->handle, level, optname, reinterpret_cast<char *>(optval), optlen);
+#else
+ return getsockopt(priv->handle, level, optname, optval, optlen);
+#endif
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_SOCKET_H_
+#define MSP_NET_SOCKET_H_
+
+#include <msp/io/eventobject.h>
+#include <msp/io/handle.h>
+#include "constants.h"
+#include "sockaddr.h"
+
+namespace Msp {
+namespace Net {
+
+#ifdef WIN32
+typedef int socklen_t;
+#endif
+
+
+class bad_socket_state: public std::logic_error
+{
+public:
+ bad_socket_state(const std::string &w): std::logic_error(w) { }
+ virtual ~bad_socket_state() throw() { }
+};
+
+
+class Socket: public IO::EventObject
+{
+protected:
+ struct Private;
+
+ Private *priv;
+ SockAddr *local_addr;
+
+ Socket(const Private &);
+ Socket(Family, int, int);
+public:
+ ~Socket();
+
+ virtual void set_block(bool);
+ virtual const IO::Handle &get_event_handle();
+
+ /** Associates the socket with a local address. There must be no existing
+ users of the address. */
+ void bind(const SockAddr &);
+
+ const SockAddr &get_local_address() const;
+
+ void set_timeout(const Time::TimeDelta &);
+protected:
+ int set_option(int, int, const void *, socklen_t);
+ int get_option(int, int, void *, socklen_t *) const;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_NET_SOCKET_PRIVATE_H_
+#define MSP_NET_SOCKET_PRIVATE_H_
+
+#include <msp/io/handle.h>
+#include "socket.h"
+
+namespace Msp {
+namespace Net {
+
+struct Socket::Private
+{
+#ifdef WIN32
+ SOCKET handle;
+#else
+ int handle;
+#endif
+
+ /* On POSIX platforms this is the same as the handle. This might seem
+ strange but it allows the same syntax on both POSIX and Windows. */
+ IO::Handle event;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <cerrno>
+#include <msp/core/refptr.h>
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#include <msp/strings/format.h>
+#include "sockaddr_private.h"
+#include "socket_private.h"
+#include "streamserversocket.h"
+#include "streamsocket.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+StreamServerSocket::StreamServerSocket(Family af, int proto):
+ ServerSocket(af, SOCK_STREAM, proto),
+ listening(false)
+{ }
+
+void StreamServerSocket::listen(const SockAddr &addr, unsigned backlog)
+{
+ bind(addr);
+
+ int err = ::listen(priv->handle, backlog);
+ if(err==-1)
+ throw system_error("listen");
+
+#ifdef WIN32
+ WSAEventSelect(priv->handle, *priv->event, FD_ACCEPT);
+#endif
+ set_events(IO::P_INPUT);
+
+ listening = true;
+}
+
+StreamSocket *StreamServerSocket::accept()
+{
+ if(!listening)
+ throw bad_socket_state("not listening");
+
+ SockAddr::SysAddr sa;
+ Private new_p;
+ new_p.handle = ::accept(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
+
+ RefPtr<SockAddr> paddr = SockAddr::new_from_sys(sa);
+ return new StreamSocket(new_p, *paddr);
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_STREAMSERVERSOCKET_H_
+#define MSP_NET_STREAMSERVERSOCKET_H_
+
+#include "serversocket.h"
+#include "streamsocket.h"
+
+namespace Msp {
+namespace Net {
+
+class StreamServerSocket: public ServerSocket
+{
+private:
+ bool listening;
+
+public:
+ StreamServerSocket(Family, int = 0);
+
+ virtual void listen(const SockAddr &, unsigned = 4);
+ virtual StreamSocket *accept();
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef WIN32
+#include <sys/socket.h>
+#endif
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#include <msp/io/poll.h>
+#include <msp/strings/format.h>
+#include "sockaddr_private.h"
+#include "socket_private.h"
+#include "streamsocket.h"
+
+namespace Msp {
+namespace Net {
+
+StreamSocket::StreamSocket(const Private &p, const SockAddr &paddr):
+ ClientSocket(p, paddr)
+{
+#ifdef WIN32
+ WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
+#endif
+ set_events(IO::P_INPUT);
+}
+
+StreamSocket::StreamSocket(Family af, int proto):
+ ClientSocket(af, SOCK_STREAM, proto)
+{ }
+
+bool StreamSocket::connect(const SockAddr &addr)
+{
+ if(connected)
+ throw bad_socket_state("already connected");
+
+ SockAddr::SysAddr sa = addr.to_sys();
+
+ int err = ::connect(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
+#ifdef WIN32
+ if(err==SOCKET_ERROR)
+ {
+ int err_code = WSAGetLastError();
+ if(err_code==WSAEWOULDBLOCK)
+ {
+ connecting = true;
+ WSAEventSelect(priv->handle, *priv->event, FD_CONNECT);
+ set_events(IO::P_OUTPUT);
+ }
+ else
+ throw system_error("connect", err_code);
+ }
+#else
+ if(err==-1)
+ {
+ if(errno==EINPROGRESS)
+ {
+ connecting = true;
+ set_events(IO::P_OUTPUT);
+ }
+ else
+ throw system_error("connect");
+ }
+#endif
+
+ delete peer_addr;
+ peer_addr = addr.copy();
+
+ delete local_addr;
+ SockAddr::SysAddr lsa;
+ getsockname(priv->handle, reinterpret_cast<sockaddr *>(&lsa.addr), &lsa.size);
+ local_addr = SockAddr::new_from_sys(lsa);
+
+ if(err==0)
+ {
+ connected = true;
+ set_events(IO::P_INPUT);
+ signal_connect_finished.emit(0);
+ }
+
+ return connected;
+}
+
+bool StreamSocket::poll_connect(const Time::TimeDelta &timeout)
+{
+ if(!connecting)
+ return false;
+
+ IO::PollEvent res = poll(*this, IO::P_OUTPUT, timeout);
+ if(res&IO::P_OUTPUT)
+ {
+ connecting = false;
+
+ int err;
+ socklen_t len = sizeof(int);
+ get_option(SOL_SOCKET, SO_ERROR, &err, &len);
+
+ if(err!=0)
+ {
+ set_events(IO::P_NONE);
+#ifdef WIN32
+ throw system_error("connect", WSAGetLastError());
+#else
+ throw system_error("connect");
+#endif
+ }
+
+#ifdef WIN32
+ WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
+#endif
+ set_events(IO::P_INPUT);
+
+ connected = true;
+ }
+
+ return connected;
+}
+
+void StreamSocket::on_event(IO::PollEvent ev)
+{
+ if((ev&(IO::P_OUTPUT|IO::P_ERROR)) && connecting)
+ {
+ int err;
+ socklen_t len = sizeof(err);
+ get_option(SOL_SOCKET, SO_ERROR, &err, &len);
+
+ connecting = false;
+ connected = (err==0);
+ if(err)
+ {
+ system_error exc("connect", err);
+ signal_connect_finished.emit(&exc);
+ }
+ else
+ signal_connect_finished.emit(0);
+
+ if(err!=0)
+ {
+ delete peer_addr;
+ peer_addr = 0;
+ }
+
+#ifdef WIN32
+ WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
+#endif
+ set_events((err==0) ? IO::P_INPUT : IO::P_NONE);
+ }
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+#ifndef MSP_NET_STREAMSOCKET_H_
+#define MSP_NET_STREAMSOCKET_H_
+
+#include "clientsocket.h"
+
+namespace Msp {
+namespace Net {
+
+class StreamSocket: public ClientSocket
+{
+ friend class StreamServerSocket;
+
+private:
+ /// Used by StreamListenSocket to construct a new socket from accept.
+ StreamSocket(const Private &, const SockAddr &);
+public:
+ StreamSocket(Family, int = 0);
+
+ /** Connects to a remote address. StreamSockets must be connected before
+ data can be sent and received. Returns 0 if the connection was successfully
+ established, 1 if it's in progress.
+
+ If the socket is non-blocking, this function may return before the
+ connection is fully established. The caller must then use either the
+ poll_connect function or an EventDispatcher to finish the process. */
+ virtual bool connect(const SockAddr &);
+
+ virtual bool poll_connect(const Time::TimeDelta &);
+
+private:
+ void on_event(IO::PollEvent);
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
+++ /dev/null
-#include <cstring>
-#include <string>
-#include <msp/core/maputils.h>
-#include <msp/strings/lexicalcast.h>
-#include "protocol.h"
-
-using namespace std;
-
-namespace {
-
-using Msp::Net::buffer_error;
-
-template<typename T>
-class Assembler
-{
-public:
- static char *assemble(const T &v, char *, char *);
- static const char *disassemble(T &, const char *, const char *);
-};
-
-template<typename T>
-class Assembler<vector<T> >
-{
-public:
- static char *assemble(const vector<T> &v, char *, char *);
- static const char *disassemble(vector<T> &, const char *, const char *);
-};
-
-template<typename T>
-char *Assembler<T>::assemble(const T &v, char *data, char *end)
-{
- // XXX Assumes little-endian
- const char *ptr = reinterpret_cast<const char *>(&v)+sizeof(T);
- for(unsigned i=0; i<sizeof(T); ++i)
- {
- if(data==end)
- throw buffer_error("overflow");
- *data++ = *--ptr;
- }
- return data;
-}
-
-template<>
-char *Assembler<string>::assemble(const string &v, char *data, char *end)
-{
- data = Assembler<unsigned short>::assemble(v.size(), data, end);
- if(end-data<static_cast<int>(v.size()))
- throw buffer_error("overflow");
- memcpy(data, v.data(), v.size());
- return data+v.size();
-}
-
-template<typename T>
-char *Assembler<vector<T> >::assemble(const vector<T> &v, char *data, char *end)
-{
- data = Assembler<unsigned short>::assemble(v.size(), data, end);
- for(typename vector<T>::const_iterator i=v.begin(); i!=v.end(); ++i)
- data = Assembler<T>::assemble(*i, data, end);
- return data;
-}
-
-template<typename T>
-const char *Assembler<T>::disassemble(T &v, const char *data, const char *end)
-{
- char *ptr = reinterpret_cast<char *>(&v)+sizeof(T);
- for(unsigned i=0; i<sizeof(T); ++i)
- {
- if(data==end)
- throw buffer_error("underflow");
- *--ptr = *data++;
- }
- return data;
-}
-
-template<>
-const char *Assembler<string>::disassemble(string &v, const char *data, const char *end)
-{
- unsigned short size;
- data = Assembler<unsigned short>::disassemble(size, data, end);
- if(end-data<size)
- throw buffer_error("underflow");
- v.assign(data, data+size);
- return data+size;
-}
-
-template<typename T>
-const char *Assembler<vector<T> >::disassemble(vector<T> &v, const char *data, const char *end)
-{
- /* We assume that the vector is in pristine state - this holds because the
- only code path leading here is from PacketDef<P>::disassemble, which creates
- a new packet. */
- unsigned short size;
- data = Assembler<unsigned short>::disassemble(size, data, end);
- for(unsigned i=0; i<size; ++i)
- {
- T u;
- data = Assembler<T>::disassemble(u, data, end);
- v.push_back(u);
- }
- return data;
-}
-
-}
-
-namespace Msp {
-namespace Net {
-
-Protocol::Protocol(unsigned npi):
- next_packet_id(npi)
-{ }
-
-Protocol::~Protocol()
-{
- for(map<unsigned, PacketDefBase *>::iterator i=packet_class_defs.begin(); i!=packet_class_defs.end(); ++i)
- delete i->second;
-}
-
-void Protocol::add_packet(PacketDefBase &pdef)
-{
- PacketDefBase *&ptr = packet_class_defs[pdef.get_class_id()];
- if(ptr)
- delete ptr;
- ptr = &pdef;
- packet_id_defs[pdef.get_id()] = &pdef;
-}
-
-const Protocol::PacketDefBase &Protocol::get_packet_by_class(unsigned id) const
-{
- return *get_item(packet_class_defs, id);
-}
-
-const Protocol::PacketDefBase &Protocol::get_packet_by_id(unsigned id) const
-{
- return *get_item(packet_id_defs, id);
-}
-
-unsigned Protocol::disassemble(ReceiverBase &rcv, const char *data, unsigned size) const
-{
- const unsigned char *udata = reinterpret_cast<const unsigned char *>(data);
- unsigned id = (udata[0]<<8)+udata[1];
- unsigned psz = (udata[2]<<8)+udata[3];
- if(psz>size)
- throw bad_packet("truncated");
- const PacketDefBase &pdef = get_packet_by_id(id);
- const char *ptr = pdef.disassemble(rcv, data+4, data+psz);
- return ptr-data;
-}
-
-unsigned Protocol::get_packet_size(const char *data, unsigned size) const
-{
- if(size<4)
- return 0;
- const unsigned char *udata = reinterpret_cast<const unsigned char *>(data);
- return (udata[2]<<8)+udata[3];
-}
-
-unsigned Protocol::get_hash() const
-{
- // TODO
- return 123;
-}
-
-void Protocol::assemble_header(char *buf, unsigned id, unsigned size)
-{
- buf[0] = (id>>8)&0xFF;
- buf[1] = id&0xFF;
- buf[2] = (size>>8)&0xFF;
- buf[3] = size&0xFF;
-}
-
-template<typename T>
-char *Protocol::assemble_field(const T &v, char *d, char *e)
-{ return Assembler<T>::assemble(v, d, e); }
-
-template char *Protocol::assemble_field<>(const char &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const signed char &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const unsigned char &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const short &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const unsigned short &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const int &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const unsigned &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const long &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const unsigned long &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const float &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const double &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const string &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<char> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<signed char> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<unsigned char> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<short> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<unsigned short> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<int> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<unsigned> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<long> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<unsigned long> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<float> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<double> &v, char *d, char *e);
-template char *Protocol::assemble_field<>(const vector<string> &v, char *d, char *e);
-
-template<typename T>
-const char *Protocol::disassemble_field(T &v, const char *d, const char *e)
-{ return Assembler<T>::disassemble(v, d, e); }
-
-template const char *Protocol::disassemble_field<>(char &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(signed char &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(unsigned char &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(short &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(unsigned short &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(int &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(unsigned &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(long &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(unsigned long &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(float &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(double &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(string &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<char> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<signed char> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<unsigned char> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<short> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<unsigned short> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<int> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<unsigned> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<long> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<unsigned long> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<float> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<double> &v, const char *d, const char *e);
-template const char *Protocol::disassemble_field<>(vector<string> &v, const char *d, const char *e);
-
-unsigned Protocol::PacketDefBase::next_class_id = 1;
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_PROTOCOL_H_
-#define MSP_NET_PROTOCOL_H_
-
-#include <map>
-#include <stdexcept>
-#include <vector>
-#include "receiver.h"
-
-namespace Msp {
-namespace Net {
-
-class bad_packet: public std::runtime_error
-{
-public:
- bad_packet(const std::string &w): std::runtime_error(w) { }
- virtual ~bad_packet() throw() { }
-};
-
-
-class buffer_error: public std::runtime_error
-{
-public:
- buffer_error(const std::string &w): std::runtime_error(w) { }
- virtual ~buffer_error() throw() { }
-};
-
-
-class Protocol
-{
-private:
- class PacketDefBase
- {
- protected:
- unsigned id;
-
- PacketDefBase(unsigned i): id(i) { }
- public:
- virtual ~PacketDefBase() { }
- virtual unsigned get_class_id() const = 0;
- unsigned get_id() const { return id; }
- virtual const char *disassemble(ReceiverBase &, const char *, const char *) const = 0;
-
- static unsigned next_class_id;
- };
-
- template<typename P>
- class FieldBase
- {
- protected:
- FieldBase() { }
- public:
- virtual ~FieldBase() { }
- virtual char *assemble(const P &, char *, char *) const = 0;
- virtual const char *disassemble(P &, const char *, const char *) const = 0;
- };
-
- template<typename P, typename T>
- class Field: public FieldBase<P>
- {
- private:
- T P::*ptr;
-
- public:
- Field(T P::*p): ptr(p) { }
-
- virtual char *assemble(const P &p, char *d, char *e) const
- { return assemble_field(p.*ptr, d, e); }
-
- virtual const char *disassemble(P &p, const char *d, const char *e) const
- { return disassemble_field(p.*ptr, d, e); }
- };
-
-protected:
- template<typename P>
- class PacketDef: public PacketDefBase
- {
- private:
- std::vector<FieldBase<P> *> fields;
-
- public:
- PacketDef(unsigned i): PacketDefBase(i)
- { if(!class_id) class_id = next_class_id++; }
-
- ~PacketDef()
- {
- for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
- delete *i;
- }
-
- virtual unsigned get_class_id() const { return class_id; }
-
- template<typename T>
- PacketDef &operator()(T P::*p)
- { fields.push_back(new Field<P, T>(p)); return *this; }
-
- char *assemble(const P &p, char *d, char *e) const
- {
- for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
- d = (*i)->assemble(p, d, e);
- return d;
- }
-
- const char *disassemble(ReceiverBase &r, const char *d, const char *e) const
- {
- PacketReceiver<P> *prcv = dynamic_cast<PacketReceiver<P> *>(&r);
- if(!prcv)
- throw bad_packet("unsupported");
- P pkt;
- for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
- d = (*i)->disassemble(pkt, d, e);
- prcv->receive(pkt);
- return d;
- }
-
- static unsigned class_id;
- };
-
- typedef std::map<unsigned, PacketDefBase *> PacketMap;
-
- unsigned next_packet_id;
- PacketMap packet_class_defs;
- PacketMap packet_id_defs;
-
- Protocol(unsigned = 1);
-public:
- ~Protocol();
-
-private:
- void add_packet(PacketDefBase &);
-
-protected:
- template<typename P>
- PacketDef<P> &add()
- {
- PacketDef<P> *pdef = new PacketDef<P>(next_packet_id++);
- add_packet(*pdef);
- return *pdef;
- }
-
- const PacketDefBase &get_packet_by_class(unsigned) const;
- const PacketDefBase &get_packet_by_id(unsigned) const;
-
-public:
- template<typename P>
- unsigned assemble(const P &pkt, char *buf, unsigned size) const
- {
- unsigned id = PacketDef<P>::class_id;
- const PacketDef<P> &pdef = static_cast<const PacketDef<P> &>(get_packet_by_class(id));
- char *ptr = pdef.assemble(pkt, buf+4, buf+size);
- assemble_header(buf, pdef.get_id(), (size = ptr-buf));
- return size;
- }
-
- unsigned disassemble(ReceiverBase &, const char *, unsigned) const;
-
- unsigned get_packet_size(const char *, unsigned) const;
-
- unsigned get_hash() const;
-
-private:
- static void assemble_header(char *, unsigned, unsigned);
-
- template<typename T>
- static char *assemble_field(const T &, char *, char *);
-
- template<typename T>
- static const char *disassemble_field(T &, const char *, const char *);
-};
-
-template<typename P>
-unsigned Protocol::PacketDef<P>::class_id = 0;
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef MSP_NET_RECEIVER_H_
-#define MSP_NET_RECEIVER_H_
-
-namespace Msp {
-namespace Net {
-
-class ReceiverBase
-{
-protected:
- ReceiverBase() { }
-public:
- virtual ~ReceiverBase() { }
-};
-
-template<typename P>
-class PacketReceiver: public virtual ReceiverBase
-{
-protected:
- PacketReceiver() { }
-public:
- virtual void receive(const P &) = 0;
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifdef WIN32
-#define _WIN32_WINNT 0x0501
-#include <ws2tcpip.h>
-#else
-#include <netdb.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
-#include "sockaddr_private.h"
-#include "socket.h"
-#include "resolve.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-SockAddr *resolve(const string &host, const string &serv, Family family)
-{
- const char *chost = (host.empty() ? 0 : host.c_str());
- const char *cserv = (serv.empty() ? 0 : serv.c_str());
- unsigned flags = 0;
- if(host=="*")
- {
- flags = AI_PASSIVE;
- chost = 0;
- }
-
- addrinfo hints = { flags, family_to_sys(family), 0, 0, 0, 0, 0, 0 };
- addrinfo *res;
-
- int err = getaddrinfo(chost, cserv, &hints, &res);
- if(err==0)
- {
- SockAddr::SysAddr sa;
- sa.size = res->ai_addrlen;
- const char *sptr = reinterpret_cast<const char *>(res->ai_addr);
- char *dptr = reinterpret_cast<char *>(&sa.addr);
- copy(sptr, sptr+res->ai_addrlen, dptr);
- SockAddr *addr = SockAddr::new_from_sys(sa);
- freeaddrinfo(res);
- return addr;
- }
- else
-#ifdef WIN32
- throw system_error("getaddrinfo", WSAGetLastError());
-#else
- throw system_error("getaddrinfo", gai_strerror(err));
-#endif
-}
-
-SockAddr *resolve(const string &str, Family family)
-{
- string host, serv;
- if(str[0]=='[')
- {
- unsigned bracket = str.find(']');
- host = str.substr(1, bracket-1);
- unsigned colon = str.find(':', bracket);
- if(colon!=string::npos)
- serv = str.substr(colon+1);
- }
- else
- {
- unsigned colon = str.find(':');
- if(colon!=string::npos)
- {
- host = str.substr(0, colon);
- serv = str.substr(colon+1);
- }
- else
- host = str;
- }
-
- return resolve(host, serv, family);
-}
-
- /*sockaddr sa;
- unsigned size = fill_sockaddr(sa);
- char hst[128];
- char srv[128];
- int err = getnameinfo(&sa, size, hst, 128, srv, 128, 0);
- if(err==0)
- {
- host = hst;
- serv = srv;
- }*/
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_RESOLVE_H_
-#define MSP_NET_RESOLVE_H_
-
-#include <string>
-#include "constants.h"
-
-namespace Msp {
-namespace Net {
-
-class SockAddr;
-
-/** Resolves host and service names into a socket address. If host is empty,
-the loopback address will be used. If host is "*", the wildcard address will
-be used. If service is empty, a socket address with a null service will be
-returned. With the IP families, these are not very useful. */
-SockAddr *resolve(const std::string &, const std::string &, Family = UNSPEC);
-
-/** And overload of resolve() that takes host and service as a single string,
-separated by a colon. If the host part contains colons, such as is the case
-with a numeric IPv6 address, it must be enclosed in brackets. */
-SockAddr *resolve(const std::string &, Family = UNSPEC);
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include "serversocket.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-ServerSocket::ServerSocket(Family af, int type, int proto):
- Socket(af, type, proto)
-{ }
-
-unsigned ServerSocket::do_write(const char *, unsigned)
-{
- throw logic_error("can't write to ServerSocket");
-}
-
-unsigned ServerSocket::do_read(char *, unsigned)
-{
- throw logic_error("can't read from ServerSocket");
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_SERVERSOCKET_H_
-#define MSP_NET_SERVERSOCKET_H_
-
-#include "socket.h"
-
-namespace Msp {
-namespace Net {
-
-class ClientSocket;
-
-/**
-ServerSockets are used to receive incoming connections. They cannot be used
-for sending and receiving data.
-*/
-class ServerSocket: public Socket
-{
-protected:
- ServerSocket(Family, int, int);
-
-public:
- virtual void listen(const SockAddr &, unsigned = 4) = 0;
-
- virtual ClientSocket *accept() = 0;
-protected:
- virtual unsigned do_write(const char *, unsigned);
- virtual unsigned do_read(char *, unsigned);
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <stdexcept>
-#include "inet.h"
-#include "inet6.h"
-#include "sockaddr_private.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-SockAddr *SockAddr::new_from_sys(const SysAddr &sa)
-{
- switch(sa.addr.ss_family)
- {
- case AF_INET:
- return new InetAddr(sa);
- case AF_INET6:
- return new Inet6Addr(sa);
- default:
- throw invalid_argument("SockAddr::create");
- }
-}
-
-SockAddr::SysAddr::SysAddr():
- size(sizeof(sockaddr_storage))
-{
- addr.ss_family = AF_UNSPEC;
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_SOCKADDR_H_
-#define MSP_NET_SOCKADDR_H_
-
-#include <string>
-#include "constants.h"
-
-namespace Msp {
-namespace Net {
-
-class SockAddr
-{
-public:
- struct SysAddr;
-
-protected:
- SockAddr() { }
-public:
- virtual ~SockAddr() { }
-
- virtual SockAddr *copy() const = 0;
-
- static SockAddr *new_from_sys(const SysAddr &);
- virtual SysAddr to_sys() const = 0;
-
- virtual Family get_family() const = 0;
- virtual std::string str() const = 0;
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef MSP_NET_SOCKADDR_PRIVATE_H_
-#define MSP_NET_SOCKADDR_PRIVATE_H_
-
-#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#endif
-#include "sockaddr.h"
-
-namespace Msp {
-namespace Net {
-
-struct SockAddr::SysAddr
-{
- struct sockaddr_storage addr;
-#ifdef WIN32
- int size;
-#else
- socklen_t size;
-#endif
-
- SysAddr();
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef WIN32
-#include <cerrno>
-#include <fcntl.h>
-#include <sys/socket.h>
-#endif
-#include <iostream>
-#include <msp/core/systemerror.h>
-#include <msp/io/handle_private.h>
-#include <msp/strings/format.h>
-#include <msp/time/rawtime_private.h>
-#include <msp/time/units.h>
-#include "sockaddr_private.h"
-#include "socket.h"
-#include "socket_private.h"
-
-namespace {
-
-#ifdef WIN32
-class WinSockHelper
-{
-public:
- WinSockHelper()
- {
- WSADATA wsa_data;
- int err = WSAStartup(0x0002, &wsa_data);
- if(err)
- std::cerr<<"Failed to initialize WinSock: "<<err<<'\n';
- }
-
- ~WinSockHelper()
- {
- WSACleanup();
- }
-};
-
-WinSockHelper wsh;
-#endif
-
-}
-
-namespace Msp {
-namespace Net {
-
-Socket::Socket(const Private &p):
- priv(new Private),
- local_addr(0)
-{
- priv->handle = p.handle;
-
- SockAddr::SysAddr sa;
- getsockname(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
- local_addr = SockAddr::new_from_sys(sa);
-
-#ifdef WIN32
- *priv->event = CreateEvent(0, false, false, 0);
-#else
- *priv->event = priv->handle;
-#endif
-}
-
-Socket::Socket(Family af, int type, int proto):
- priv(new Private),
- local_addr(0)
-{
- priv->handle = socket(family_to_sys(af), type, proto);
-
-#ifdef WIN32
- *priv->event = CreateEvent(0, false, false, 0);
-#else
- *priv->event = priv->handle;
-#endif
-}
-
-Socket::~Socket()
-{
-#ifdef WIN32
- closesocket(priv->handle);
- CloseHandle(*priv->event);
-#else
- ::close(priv->handle);
-#endif
-
- delete local_addr;
- delete priv;
-}
-
-void Socket::set_block(bool b)
-{
- mode = (mode&~IO::M_NONBLOCK);
- if(b)
- mode = (mode|IO::M_NONBLOCK);
-
-#ifdef WIN32
- u_long flag = !b;
- ioctlsocket(priv->handle, FIONBIO, &flag);
-#else
- int flags = fcntl(priv->handle, F_GETFL);
- fcntl(priv->handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
-#endif
-}
-
-const IO::Handle &Socket::get_event_handle()
-{
- return priv->event;
-}
-
-
-void Socket::bind(const SockAddr &addr)
-{
- SockAddr::SysAddr sa = addr.to_sys();
-
- int err = ::bind(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
- if(err==-1)
- throw system_error("bind");
-
- delete local_addr;
- local_addr = addr.copy();
-}
-
-const SockAddr &Socket::get_local_address() const
-{
- if(local_addr==0)
- throw bad_socket_state("not bound");
- return *local_addr;
-}
-
-void Socket::set_timeout(const Time::TimeDelta &timeout)
-{
-#ifndef WIN32
- timeval tv = Time::rawtime_to_timeval(timeout.raw());
- set_option(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
- set_option(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
-#else
- DWORD msecs = static_cast<DWORD>(timeout/Time::msec);
- set_option(SOL_SOCKET, SO_RCVTIMEO, &msecs, sizeof(DWORD));
- set_option(SOL_SOCKET, SO_SNDTIMEO, &msecs, sizeof(DWORD));
-#endif
-}
-
-int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen)
-{
-#ifdef WIN32
- return setsockopt(priv->handle, level, optname, reinterpret_cast<const char *>(optval), optlen);
-#else
- return setsockopt(priv->handle, level, optname, optval, optlen);
-#endif
-}
-
-int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) const
-{
-#ifdef WIN32
- return getsockopt(priv->handle, level, optname, reinterpret_cast<char *>(optval), optlen);
-#else
- return getsockopt(priv->handle, level, optname, optval, optlen);
-#endif
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_SOCKET_H_
-#define MSP_NET_SOCKET_H_
-
-#include <msp/io/eventobject.h>
-#include <msp/io/handle.h>
-#include "constants.h"
-#include "sockaddr.h"
-
-namespace Msp {
-namespace Net {
-
-#ifdef WIN32
-typedef int socklen_t;
-#endif
-
-
-class bad_socket_state: public std::logic_error
-{
-public:
- bad_socket_state(const std::string &w): std::logic_error(w) { }
- virtual ~bad_socket_state() throw() { }
-};
-
-
-class Socket: public IO::EventObject
-{
-protected:
- struct Private;
-
- Private *priv;
- SockAddr *local_addr;
-
- Socket(const Private &);
- Socket(Family, int, int);
-public:
- ~Socket();
-
- virtual void set_block(bool);
- virtual const IO::Handle &get_event_handle();
-
- /** Associates the socket with a local address. There must be no existing
- users of the address. */
- void bind(const SockAddr &);
-
- const SockAddr &get_local_address() const;
-
- void set_timeout(const Time::TimeDelta &);
-protected:
- int set_option(int, int, const void *, socklen_t);
- int get_option(int, int, void *, socklen_t *) const;
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef MSP_NET_SOCKET_PRIVATE_H_
-#define MSP_NET_SOCKET_PRIVATE_H_
-
-#include <msp/io/handle.h>
-#include "socket.h"
-
-namespace Msp {
-namespace Net {
-
-struct Socket::Private
-{
-#ifdef WIN32
- SOCKET handle;
-#else
- int handle;
-#endif
-
- /* On POSIX platforms this is the same as the handle. This might seem
- strange but it allows the same syntax on both POSIX and Windows. */
- IO::Handle event;
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <cerrno>
-#include <msp/core/refptr.h>
-#include <msp/core/systemerror.h>
-#include <msp/io/handle_private.h>
-#include <msp/strings/format.h>
-#include "sockaddr_private.h"
-#include "socket_private.h"
-#include "streamserversocket.h"
-#include "streamsocket.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-StreamServerSocket::StreamServerSocket(Family af, int proto):
- ServerSocket(af, SOCK_STREAM, proto),
- listening(false)
-{ }
-
-void StreamServerSocket::listen(const SockAddr &addr, unsigned backlog)
-{
- bind(addr);
-
- int err = ::listen(priv->handle, backlog);
- if(err==-1)
- throw system_error("listen");
-
-#ifdef WIN32
- WSAEventSelect(priv->handle, *priv->event, FD_ACCEPT);
-#endif
- set_events(IO::P_INPUT);
-
- listening = true;
-}
-
-StreamSocket *StreamServerSocket::accept()
-{
- if(!listening)
- throw bad_socket_state("not listening");
-
- SockAddr::SysAddr sa;
- Private new_p;
- new_p.handle = ::accept(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
-
- RefPtr<SockAddr> paddr = SockAddr::new_from_sys(sa);
- return new StreamSocket(new_p, *paddr);
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_STREAMSERVERSOCKET_H_
-#define MSP_NET_STREAMSERVERSOCKET_H_
-
-#include "serversocket.h"
-#include "streamsocket.h"
-
-namespace Msp {
-namespace Net {
-
-class StreamServerSocket: public ServerSocket
-{
-private:
- bool listening;
-
-public:
- StreamServerSocket(Family, int = 0);
-
- virtual void listen(const SockAddr &, unsigned = 4);
- virtual StreamSocket *accept();
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef WIN32
-#include <sys/socket.h>
-#endif
-#include <cerrno>
-#include <msp/core/systemerror.h>
-#include <msp/io/handle_private.h>
-#include <msp/io/poll.h>
-#include <msp/strings/format.h>
-#include "sockaddr_private.h"
-#include "socket_private.h"
-#include "streamsocket.h"
-
-namespace Msp {
-namespace Net {
-
-StreamSocket::StreamSocket(const Private &p, const SockAddr &paddr):
- ClientSocket(p, paddr)
-{
-#ifdef WIN32
- WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
- set_events(IO::P_INPUT);
-}
-
-StreamSocket::StreamSocket(Family af, int proto):
- ClientSocket(af, SOCK_STREAM, proto)
-{ }
-
-bool StreamSocket::connect(const SockAddr &addr)
-{
- if(connected)
- throw bad_socket_state("already connected");
-
- SockAddr::SysAddr sa = addr.to_sys();
-
- int err = ::connect(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
-#ifdef WIN32
- if(err==SOCKET_ERROR)
- {
- int err_code = WSAGetLastError();
- if(err_code==WSAEWOULDBLOCK)
- {
- connecting = true;
- WSAEventSelect(priv->handle, *priv->event, FD_CONNECT);
- set_events(IO::P_OUTPUT);
- }
- else
- throw system_error("connect", err_code);
- }
-#else
- if(err==-1)
- {
- if(errno==EINPROGRESS)
- {
- connecting = true;
- set_events(IO::P_OUTPUT);
- }
- else
- throw system_error("connect");
- }
-#endif
-
- delete peer_addr;
- peer_addr = addr.copy();
-
- delete local_addr;
- SockAddr::SysAddr lsa;
- getsockname(priv->handle, reinterpret_cast<sockaddr *>(&lsa.addr), &lsa.size);
- local_addr = SockAddr::new_from_sys(lsa);
-
- if(err==0)
- {
- connected = true;
- set_events(IO::P_INPUT);
- signal_connect_finished.emit(0);
- }
-
- return connected;
-}
-
-bool StreamSocket::poll_connect(const Time::TimeDelta &timeout)
-{
- if(!connecting)
- return false;
-
- IO::PollEvent res = poll(*this, IO::P_OUTPUT, timeout);
- if(res&IO::P_OUTPUT)
- {
- connecting = false;
-
- int err;
- socklen_t len = sizeof(int);
- get_option(SOL_SOCKET, SO_ERROR, &err, &len);
-
- if(err!=0)
- {
- set_events(IO::P_NONE);
-#ifdef WIN32
- throw system_error("connect", WSAGetLastError());
-#else
- throw system_error("connect");
-#endif
- }
-
-#ifdef WIN32
- WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
- set_events(IO::P_INPUT);
-
- connected = true;
- }
-
- return connected;
-}
-
-void StreamSocket::on_event(IO::PollEvent ev)
-{
- if((ev&(IO::P_OUTPUT|IO::P_ERROR)) && connecting)
- {
- int err;
- socklen_t len = sizeof(err);
- get_option(SOL_SOCKET, SO_ERROR, &err, &len);
-
- connecting = false;
- connected = (err==0);
- if(err)
- {
- system_error exc("connect", err);
- signal_connect_finished.emit(&exc);
- }
- else
- signal_connect_finished.emit(0);
-
- if(err!=0)
- {
- delete peer_addr;
- peer_addr = 0;
- }
-
-#ifdef WIN32
- WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
- set_events((err==0) ? IO::P_INPUT : IO::P_NONE);
- }
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_STREAMSOCKET_H_
-#define MSP_NET_STREAMSOCKET_H_
-
-#include "clientsocket.h"
-
-namespace Msp {
-namespace Net {
-
-class StreamSocket: public ClientSocket
-{
- friend class StreamServerSocket;
-
-private:
- /// Used by StreamListenSocket to construct a new socket from accept.
- StreamSocket(const Private &, const SockAddr &);
-public:
- StreamSocket(Family, int = 0);
-
- /** Connects to a remote address. StreamSockets must be connected before
- data can be sent and received. Returns 0 if the connection was successfully
- established, 1 if it's in progress.
-
- If the socket is non-blocking, this function may return before the
- connection is fully established. The caller must then use either the
- poll_connect function or an EventDispatcher to finish the process. */
- virtual bool connect(const SockAddr &);
-
- virtual bool poll_connect(const Time::TimeDelta &);
-
-private:
- void on_event(IO::PollEvent);
-};
-
-} // namespace Net
-} // namespace Msp
-
-#endif