--- /dev/null
+package "mspnet"
+{
+ require "mspio";
+ if "arch=win32"
+ {
+ build_info
+ {
+ library "ws2_32";
+ };
+ };
+
+ library "mspnet"
+ {
+ source "source";
+ install true;
+ install_headers "msp/net";
+ };
+};
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_CONSTANTS_H_
+#define MSP_NET_CONSTANTS_H_
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+
+namespace Msp {
+namespace Net {
+
+enum Family
+{
+ UNSPEC=AF_UNSPEC,
+ INET=AF_INET,
+ INET6=AF_INET6,
+ UNIF=AF_UNIX
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#include <errno.h>
+#include <msp/strings/formatter.h>
+#include "datagramsocket.h"
+
+namespace Msp {
+namespace Net {
+
+DatagramSocket::DatagramSocket(Family f, int p):
+ Socket(f, SOCK_DGRAM, p)
+{ }
+
+int DatagramSocket::connect(const SockAddr &addr)
+{
+ check_state(false);
+
+ sockaddr sa;
+ socklen_t size=addr.fill_sockaddr(sa);
+
+ int err=::connect(handle, &sa, size);
+ if(err==-1)
+ throw Exception(format("Unable to connect: %s", strerror(errno)));
+
+ delete peer_addr;
+ peer_addr=addr.copy();
+
+ delete local_addr;
+ size=sizeof(sockaddr);
+ getsockname(handle, &sa, &size);
+ local_addr=SockAddr::create(sa);
+
+ connected=true;
+
+ return (err==0)?0:1;
+}
+
+unsigned DatagramSocket::sendto(const char *buf, unsigned size, const SockAddr &addr_)
+{
+ check_state(false);
+
+ if(size==0)
+ return 0;
+
+ sockaddr addr;
+ socklen_t addr_len=addr_.fill_sockaddr(addr);
+
+ int ret=::sendto(handle, buf, size, 0, &addr, addr_len);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw Exception(format("Sendto failed: %s", strerror(errno)));
+ }
+
+ return ret;
+}
+
+unsigned DatagramSocket::recvfrom(char *buf, unsigned size, SockAddr *&addr_)
+{
+ check_state(false);
+
+ if(size==0)
+ return 0;
+
+ sockaddr addr;
+ socklen_t addr_len=sizeof(sockaddr);
+
+ int ret=::recvfrom(handle, buf, size, 0, &addr, &addr_len);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw Exception(format("Recvfrom failed: %s", strerror(errno)));
+ }
+
+ addr_=SockAddr::create(addr);
+
+ return ret;
+}
+
+IO::PollEvent DatagramSocket::get_initial_events() const
+{
+ return IO::P_INPUT;
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_DATAGRAMSOCKET_H_
+#define MSP_NET_DATAGRAMSOCKET_H_
+
+#include "socket.h"
+
+namespace Msp {
+namespace Net {
+
+class DatagramSocket: public Socket
+{
+public:
+ DatagramSocket(Family, int =0);
+ int connect(const SockAddr &);
+ unsigned sendto(const char *, unsigned, const SockAddr &);
+ unsigned recvfrom(char *, unsigned, SockAddr *&);
+private:
+ IO::PollEvent get_initial_events() const;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#include <msp/strings/formatter.h>
+#include "inet.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+InetAddr::InetAddr():
+ addr(0),
+ port(0)
+{ }
+
+InetAddr::InetAddr(sockaddr_in &sa):
+ addr(sa.sin_addr.s_addr),
+ port(sa.sin_port)
+{ }
+
+InetAddr::InetAddr(in_addr_t a, in_port_t p):
+ addr(htonl(a)),
+ port(htons(p))
+{ }
+
+string InetAddr::str() const
+{
+ const unsigned char *ptr=reinterpret_cast<const unsigned char *>(&addr);
+ return format("%d.%d.%d.%d:%d", static_cast<int>(ptr[0]), static_cast<int>(ptr[1]), static_cast<int>(ptr[2]), static_cast<int>(ptr[3]), ntohs(port));
+}
+
+unsigned InetAddr::fill_sockaddr(sockaddr &sa) const
+{
+ sockaddr_in &sai=reinterpret_cast<sockaddr_in &>(sa);
+ sai.sin_family=AF_INET;
+ sai.sin_addr.s_addr=addr;
+ sai.sin_port=port;
+
+ return sizeof(sockaddr_in);
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_INET_H_
+#define MSP_NET_INET_H_
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+#include <string>
+#include "sockaddr.h"
+
+namespace Msp {
+namespace Net {
+
+#ifdef WIN32
+typedef u_long in_addr_t;
+typedef u_short in_port_t;
+#endif
+
+/**
+Address class for IPv4 sockets.
+*/
+class InetAddr: public SockAddr
+{
+public:
+ InetAddr();
+ InetAddr(sockaddr_in &);
+ InetAddr(in_addr_t, in_port_t);
+ Family get_family() const { return INET; }
+ in_addr_t get_addr() const { return ntohl(addr); }
+ in_port_t get_port() const { return ntohs(port); }
+ std::string str() const;
+ unsigned fill_sockaddr(sockaddr &) const;
+ InetAddr *copy() const { return new InetAddr(*this); }
+private:
+ in_addr_t addr;
+ in_port_t port;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
+#endif
+#include <msp/strings/formatter.h>
+#include "socket.h"
+#include "resolve.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+SockAddr *resolve(const string &s, Family family)
+{
+ string host, serv;
+ unsigned colon=s.find(':');
+ if(colon!=string::npos)
+ {
+ host=s.substr(0, colon);
+ serv=s.substr(colon+1);
+ }
+ else
+ host=s;
+
+ addrinfo hints={0, family, 0, 0, 0, 0, 0, 0};
+ addrinfo *res;
+ const char *chost=(host.empty() ? 0 : host.c_str());
+ const char *cserv=(serv.empty() ? 0 : serv.c_str());
+ int err=getaddrinfo(chost, cserv, &hints, &res);
+ if(err==0)
+ {
+ SockAddr *addr=SockAddr::create(*res->ai_addr);
+ freeaddrinfo(res);
+ return addr;
+ }
+ else
+#ifdef WIN32
+ throw Exception(format("Can't resolve '%s': %d", host, err));
+#else
+ throw Exception(format("Can't resolve '%s': %s", host, gai_strerror(err)));
+#endif
+}
+
+ /*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
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_RESOLVE_H_
+#define MSP_NET_RESOLVE_H_
+
+#include <string>
+#include "constants.h"
+
+namespace Msp {
+namespace Net {
+
+class SockAddr;
+
+SockAddr *resolve(const std::string &, Family =UNSPEC);
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#include <msp/core/except.h>
+#include "inet.h"
+
+namespace Msp {
+namespace Net {
+
+SockAddr *SockAddr::create(sockaddr &sa)
+{
+ switch(sa.sa_family)
+ {
+ case AF_INET:
+ return new InetAddr(reinterpret_cast<sockaddr_in &>(sa));
+ default:
+ throw InvalidParameterValue("Unknown address family");
+ }
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_SOCKADDR_H_
+#define MSP_NET_SOCKADDR_H_
+
+#ifndef WIN32
+#include <sys/socket.h>
+#endif
+#include "constants.h"
+
+namespace Msp {
+namespace Net {
+
+class SockAddr
+{
+public:
+ virtual Family get_family() const =0;
+ virtual std::string str() const =0;
+
+ /**
+ Fills the given struct sockaddr with information from this SockAddr.
+
+ @return Number of bytes used
+ */
+ virtual unsigned fill_sockaddr(sockaddr &) const =0;
+
+ virtual SockAddr *copy() const =0;
+
+ virtual ~SockAddr() { }
+
+ static SockAddr *create(sockaddr &);
+protected:
+ SockAddr() { }
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef WIN32
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#endif
+#include <iostream>
+#include <msp/strings/formatter.h>
+#include <msp/time/units.h>
+#include "socket.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 {
+
+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(handle, FIONBIO, &flag);
+#else
+ int flags=fcntl(handle, F_GETFL);
+ fcntl(handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
+#endif
+}
+
+IO::Handle Socket::get_event_handle()
+{
+#ifdef WIN32
+ return event;
+#else
+ return handle;
+#endif
+}
+
+
+void Socket::bind(const SockAddr &addr)
+{
+ check_state(false);
+
+ sockaddr sa;
+ unsigned size=addr.fill_sockaddr(sa);
+
+ int err=::bind(handle, &sa, size);
+ if(err==-1)
+ throw Exception(format("Unable to bind: %s", strerror(errno)));
+
+ delete local_addr;
+ local_addr=addr.copy();
+}
+
+/**
+Closes the socket. Most operations on the socket will return an error after
+this.
+*/
+void Socket::close()
+{
+ if(handle==MSP_NET_INVALID_SOCKET_HANDLE)
+ return;
+
+ set_events(IO::P_NONE);
+
+ signal_flush_required.emit();
+#ifdef WIN32
+ closesocket(handle);
+ CloseHandle(event);
+#else
+ ::close(handle);
+#endif
+ handle=MSP_NET_INVALID_SOCKET_HANDLE;
+ signal_closed.emit();
+
+ delete local_addr;
+ local_addr=0;
+ delete peer_addr;
+ peer_addr=0;
+}
+
+const SockAddr &Socket::get_local_address() const
+{
+ if(local_addr==0)
+ throw InvalidState("Local address not set");
+ return *local_addr;
+}
+
+const SockAddr &Socket::get_peer_address() const
+{
+ if(peer_addr==0)
+ throw InvalidState("Peer address not set");
+ return *peer_addr;
+}
+
+Socket::~Socket()
+{
+ close();
+}
+
+Socket::Socket(SocketHandle h, const SockAddr &paddr):
+ handle(h),
+ connected(true),
+ local_addr(0),
+ peer_addr(paddr.copy())
+{
+ sockaddr sa;
+ socklen_t size=sizeof(sockaddr);
+ getsockname(handle, &sa, &size);
+ local_addr=SockAddr::create(sa);
+
+#ifdef WIN32
+ event=CreateEvent(0, false, false, 0);
+#endif
+}
+
+Socket::Socket(Family af, int type, int proto):
+ connected(false),
+ local_addr(0),
+ peer_addr(0)
+{
+ handle=socket(af, type, proto);
+
+#ifdef WIN32
+ event=CreateEvent(0, false, false, 0);
+#endif
+}
+
+void Socket::check_state(bool conn) const
+{
+ if(handle==MSP_NET_INVALID_SOCKET_HANDLE)
+ throw Exception("Socket is closed");
+ if(conn && !connected)
+ throw Exception("Socket is not connected");
+}
+
+int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen)
+{
+#ifdef WIN32
+ return getsockopt(handle, level, optname, reinterpret_cast<char *>(optval), optlen);
+#else
+ return getsockopt(handle, level, optname, optval, optlen);
+#endif
+}
+
+unsigned Socket::do_write(const char *buf, unsigned size)
+{
+ check_state(true);
+
+ if(size==0)
+ return 0;
+
+ int ret=::send(handle, buf, size, 0);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw Exception(format("Writing to socket failed: %s", strerror(errno)));
+ }
+
+ return ret;
+}
+
+unsigned Socket::do_read(char *buf, unsigned size)
+{
+ check_state(true);
+
+ if(size==0)
+ return 0;
+
+ int ret=::recv(handle, buf, size, 0);
+ if(ret<0)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw Exception(format("Reading from socket failed: %s", strerror(errno)));
+ }
+ 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
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_SOCKET_H_
+#define MSP_NET_SOCKET_H_
+
+#include <msp/io/base.h>
+#include "constants.h"
+#include "sockaddr.h"
+#include "types.h"
+
+namespace Msp {
+namespace Net {
+
+class Socket: public IO::Base
+{
+public:
+ void set_block(bool);
+ IO::Handle get_event_handle();
+
+ bool get_connected() const { return connected; }
+ void bind(const SockAddr &);
+ virtual int connect(const SockAddr &) =0;
+ void close();
+ const SockAddr &get_local_address() const;
+ const SockAddr &get_peer_address() const;
+ ~Socket();
+protected:
+ SocketHandle handle;
+#ifdef WIN32
+ IO::Handle event;
+#endif
+ bool connected;
+ SockAddr *local_addr;
+ SockAddr *peer_addr;
+
+ Socket(SocketHandle, const SockAddr &);
+ Socket(Family, int, int);
+ void check_state(bool) const;
+ int get_option(int, int, void *, socklen_t *);
+ unsigned do_write(const char *, unsigned);
+ unsigned do_read(char *, unsigned);
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#include <errno.h>
+#include <msp/core/refptr.h>
+#include <msp/strings/formatter.h>
+#include "streamlistensocket.h"
+#include "streamsocket.h"
+
+namespace Msp {
+namespace Net {
+
+StreamListenSocket::StreamListenSocket(Family af, int proto):
+ Socket(af, SOCK_STREAM, proto),
+ listening(false)
+{ }
+
+int StreamListenSocket::connect(const SockAddr &)
+{
+ throw Exception("Can't connect a listen socket");
+}
+
+void StreamListenSocket::listen(const SockAddr &addr, unsigned backlog)
+{
+ bind(addr);
+
+ int err=::listen(handle, backlog);
+ if(err==-1)
+ throw Exception(format("Unable to listen: %s", strerror(errno)));
+
+#ifdef WIN32
+ WSAEventSelect(handle, event, FD_ACCEPT);
+#endif
+ set_events(IO::P_INPUT);
+
+ listening=true;
+}
+
+StreamSocket *StreamListenSocket::accept()
+{
+ if(!listening)
+ throw InvalidState("Socket is not listening");
+
+ sockaddr sa;
+ socklen_t size=sizeof(sockaddr);
+ SocketHandle new_h=::accept(handle, &sa, &size);
+
+ RefPtr<SockAddr> paddr=SockAddr::create(sa);
+ return new StreamSocket(new_h, *paddr);
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_STREAMLISTENSOCKET_H_
+#define MSP_NET_STREAMLISTENSOCKET_H_
+
+#include "socket.h"
+
+namespace Msp {
+namespace Net {
+
+class StreamSocket;
+
+class StreamListenSocket: public Socket
+{
+public:
+ StreamListenSocket(Family, int =0);
+ int connect(const SockAddr &);
+ void listen(const SockAddr &, unsigned =4);
+ StreamSocket *accept();
+private:
+ bool listening;
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef WIN32
+#include <sys/socket.h>
+#endif
+#include <errno.h>
+#include <msp/io/poll.h>
+#include <msp/strings/formatter.h>
+#include "streamsocket.h"
+
+namespace Msp {
+namespace Net {
+
+/**
+Constructs a new StreamSocket.
+*/
+StreamSocket::StreamSocket(Family af, int proto):
+ Socket(af, SOCK_STREAM, proto),
+ connecting(false)
+{ }
+
+/**
+Checks the status of an ongoing connection attempt. If the connection fails
+with an error, an exception is thrown.
+
+@return 0 if the connection finished, 1 if not
+*/
+int StreamSocket::poll_connect(const Time::TimeDelta &timeout)
+{
+ check_state(false);
+ if(!connecting)
+ throw InvalidState("No connection attempt going on");
+
+ int res=poll(*this, IO::P_OUTPUT, timeout);
+ if(res==-1)
+#ifdef WIN32
+ throw Exception(format("Connection polling failed: %d", WSAGetLastError()));
+#else
+ throw Exception(format("Connection polling failed: %s", strerror(errno)));
+#endif
+ else if(res>0)
+ {
+ 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 Exception(format("Connection failed: %d", err));
+#else
+ throw Exception(format("Connection failed: %s", strerror(err)));
+#endif
+ }
+
+#ifdef WIN32
+ WSAEventSelect(handle, event, FD_READ|FD_CLOSE);
+#endif
+ set_events(IO::P_INPUT);
+
+ connected=true;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+Connects the socket to a remote address. In non-blocking mode, this function
+may return before the connection is finished. The caller must then use either
+the poll_connect function or an EventDispatcher to determine when the
+connection is finished.
+
+@return 0 if the connection finished, 1 if it is in progress
+*/
+int StreamSocket::connect(const SockAddr &addr)
+{
+ check_state(false);
+
+ if(connected)
+ throw InvalidState("Socket is already connected");
+
+ sockaddr sa;
+ socklen_t size=addr.fill_sockaddr(sa);
+
+#ifdef WIN32
+ int err=WSAConnect(handle, &sa, size, 0, 0, 0, 0);
+ if(err=SOCKET_ERROR)
+ {
+ int err_code=WSAGetLastError();
+ if(err_code==WSAEWOULDBLOCK)
+ {
+ connecting=true;
+ WSAEventSelect(handle, event, FD_CONNECT);
+ set_events(IO::P_OUTPUT);
+ }
+ else
+ throw Exception(format("Unable to connect: %d", err_code));
+ }
+#else
+ int err=::connect(handle, &sa, size);
+ if(err==-1)
+ {
+ if(errno==EINPROGRESS)
+ {
+ connecting=true;
+ set_events(IO::P_OUTPUT);
+ }
+ else
+ throw Exception(format("Unable to connect: %s", strerror(errno)));
+ }
+#endif
+
+ delete peer_addr;
+ peer_addr=addr.copy();
+
+ delete local_addr;
+ size=sizeof(sockaddr);
+ getsockname(handle, &sa, &size);
+ local_addr=SockAddr::create(sa);
+
+ if(err==0)
+ {
+ connected=true;
+ signal_connect_finished.emit(0);
+ }
+
+ return (err==0)?0:1;
+}
+
+/**
+Used by StreamListenSocket to construct a new socket from accept.
+*/
+StreamSocket::StreamSocket(SocketHandle h, const SockAddr &paddr):
+ Socket(h, paddr),
+ connecting(false)
+{
+#ifdef WIN32
+ WSAEventSelect(handle, event, FD_READ|FD_CLOSE);
+#endif
+ set_events(IO::P_INPUT);
+}
+
+void StreamSocket::on_event(IO::PollEvent ev)
+{
+ //cout<<"StreamSocket::on_event "<<ev<<'\n';
+ 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);
+ signal_connect_finished.emit(err);
+
+ if(err!=0)
+ {
+ delete peer_addr;
+ peer_addr=0;
+ }
+
+#ifdef WIN32
+ WSAEventSelect(handle, event, FD_READ|FD_CLOSE);
+#endif
+ set_events((err==0) ? IO::P_INPUT : IO::P_NONE);
+ }
+}
+
+} // namespace Net
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_STREAMSOCKET_H_
+#define MSP_NET_STREAMSOCKET_H_
+
+#include "socket.h"
+
+namespace Msp {
+namespace Net {
+
+class StreamSocket: public Socket
+{
+ friend class StreamListenSocket;
+public:
+ /**
+ Emitted when the socket finishes connecting. The argument is a standard
+ error code, 0 indicating success.
+ */
+ sigc::signal<void, int> signal_connect_finished;
+
+ StreamSocket(Family, int =0);
+ bool get_connecting() const { return connecting; }
+ int poll_connect(const Time::TimeDelta &);
+ int connect(const SockAddr &);
+private:
+ bool connecting;
+
+ StreamSocket(SocketHandle, const SockAddr &);
+ void on_event(IO::PollEvent);
+};
+
+} // namespace Net
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspnet
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_NET_TYPES_H_
+#define MSP_NET_TYPES_H_
+
+namespace Msp {
+namespace Net {
+
+#ifdef WIN32
+typedef SOCKET SocketHandle;
+typedef int socklen_t;
+
+#define MSP_NET_INVALID_SOCKET_HANDLE static_cast<SOCKET>(-1)
+#else
+typedef IO::Handle SocketHandle;
+
+#define MSP_NET_INVALID_SOCKET_HANDLE MSP_IO_INVALID_HANDLE
+#endif
+
+} // namespace Net
+} // namespace Msp
+
+#endif