#include <msp/core/refptr.h>
#include <msp/io/console.h>
#include <msp/io/eventdispatcher.h>
-#include <msp/net/streamlistensocket.h>
+#include <msp/net/streamserversocket.h>
#include <msp/net/streamsocket.h>
#include <msp/net/resolve.h>
private:
bool ipv6;
bool listen;
- Net::StreamListenSocket *server_sock;
+ Net::StreamServerSocket *server_sock;
Net::StreamSocket *sock;
IO::EventDispatcher event_disp;
}
else
{
- server_sock = new Net::StreamListenSocket(addr->get_family());
+ server_sock = new Net::StreamServerSocket(addr->get_family());
server_sock->listen(*addr);
event_disp.add(*server_sock);
server_sock->signal_data_available.connect(sigc::mem_fun(this, &NetCat::net_data_available));
--- /dev/null
+#ifndef WIN32
+#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
+{
+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
namespace Net {
DatagramSocket::DatagramSocket(Family f, int p):
- Socket(f, SOCK_DGRAM, p)
+ ClientSocket(f, SOCK_DGRAM, p)
{
#ifdef WIN32
WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
set_events(IO::P_INPUT);
}
-int DatagramSocket::connect(const SockAddr &addr)
+bool DatagramSocket::connect(const SockAddr &addr)
{
SockAddr::SysAddr sa = addr.to_sys();
connected = true;
- return (err==0)?0:1;
+ return true;
}
unsigned DatagramSocket::sendto(const char *buf, unsigned size, const SockAddr &addr)
#ifndef MSP_NET_DATAGRAMSOCKET_H_
#define MSP_NET_DATAGRAMSOCKET_H_
-#include "socket.h"
+#include "clientsocket.h"
namespace Msp {
namespace Net {
-class DatagramSocket: public Socket
+class DatagramSocket: public ClientSocket
{
public:
DatagramSocket(Family, int = 0);
- int connect(const SockAddr &);
+ 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 *&);
};
--- /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
namespace Msp {
namespace Net {
-Socket::Socket(const Private &p, const SockAddr &paddr):
+Socket::Socket(const Private &p):
priv(new Private),
- connected(true),
- local_addr(0),
- peer_addr(paddr.copy())
+ local_addr(0)
{
priv->handle = p.handle;
Socket::Socket(Family af, int type, int proto):
priv(new Private),
- connected(false),
- local_addr(0),
- peer_addr(0)
+ local_addr(0)
{
priv->handle = socket(family_to_sys(af), type, proto);
Socket::~Socket()
{
- signal_flush_required.emit();
#ifdef WIN32
closesocket(priv->handle);
CloseHandle(*priv->event);
#endif
delete local_addr;
- delete peer_addr;
delete priv;
}
return *local_addr;
}
-const SockAddr &Socket::get_peer_address() const
-{
- if(peer_addr==0)
- throw bad_socket_state("not connected");
- return *peer_addr;
-}
-
int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen)
{
#ifdef WIN32
#endif
}
-unsigned Socket::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 Socket::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
struct Private;
Private *priv;
- bool connected;
SockAddr *local_addr;
- SockAddr *peer_addr;
- Socket(const Private &, const SockAddr &);
+ Socket(const Private &);
Socket(Family, int, int);
public:
~Socket();
void set_block(bool);
const IO::Handle &get_event_handle();
- bool is_connected() const { return connected; }
-
/** Associates the socket with a local address. There must be no existing
users of the address. */
void bind(const SockAddr &);
- /** Connects to a remote address. Exact semantics depend on the socket
- type. */
- virtual int connect(const SockAddr &) = 0;
-
void set_timeout(const Time::TimeDelta &);
const SockAddr &get_local_address() const;
- const SockAddr &get_peer_address() const;
protected:
int set_option(int, int, const void *, socklen_t);
int get_option(int, int, void *, socklen_t *) const;
- unsigned do_write(const char *, unsigned);
- unsigned do_read(char *, unsigned);
};
} // namespace Net
+++ /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 "streamlistensocket.h"
-#include "streamsocket.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Net {
-
-StreamListenSocket::StreamListenSocket(Family af, int proto):
- Socket(af, SOCK_STREAM, proto),
- listening(false)
-{ }
-
-int StreamListenSocket::connect(const SockAddr &)
-{
- // XXX This function needs to go away
- throw logic_error("Can't connect a listen socket");
-}
-
-void StreamListenSocket::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 *StreamListenSocket::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::from_sys(sa);
- return new StreamSocket(new_p, *paddr);
-}
-
-} // namespace Net
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_NET_STREAMLISTENSOCKET_H_
-#define MSP_NET_STREAMLISTENSOCKET_H_
-
-#include "socket.h"
-
-namespace Msp {
-namespace Net {
-
-class StreamSocket;
-
-class StreamListenSocket: public Socket
-{
-private:
- bool listening;
-
-public:
- StreamListenSocket(Family, int = 0);
-
- int connect(const SockAddr &);
- void listen(const SockAddr &, unsigned = 4);
- StreamSocket *accept();
-};
-
-} // 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::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
namespace Net {
StreamSocket::StreamSocket(const Private &p, const SockAddr &paddr):
- Socket(p, paddr),
- connecting(false)
+ ClientSocket(p, paddr)
{
#ifdef WIN32
WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
}
StreamSocket::StreamSocket(Family af, int proto):
- Socket(af, SOCK_STREAM, proto),
- connecting(false)
+ ClientSocket(af, SOCK_STREAM, proto)
{ }
-int StreamSocket::poll_connect(const Time::TimeDelta &timeout)
+bool StreamSocket::poll_connect(const Time::TimeDelta &timeout)
{
if(!connecting)
throw bad_socket_state("not connecting");
set_events(IO::P_INPUT);
connected = true;
-
- return 0;
}
- return 1;
+ return connected;
}
-int StreamSocket::connect(const SockAddr &addr)
+bool StreamSocket::connect(const SockAddr &addr)
{
if(connected)
throw bad_socket_state("already connected");
signal_connect_finished.emit(0);
}
- return (err==0)?0:1;
+ return connected;
}
void StreamSocket::on_event(IO::PollEvent ev)
#ifndef MSP_NET_STREAMSOCKET_H_
#define MSP_NET_STREAMSOCKET_H_
-#include "socket.h"
+#include "clientsocket.h"
namespace Msp {
namespace Net {
-class StreamSocket: public Socket
+class StreamSocket: public ClientSocket
{
- friend class StreamListenSocket;
-private:
- bool connecting;
+ friend class StreamServerSocket;
public:
/** Emitted when the socket finishes connecting. The argument is a
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 int connect(const SockAddr &);
-
- bool is_connecting() const { return connecting; }
+ virtual bool connect(const SockAddr &);
- /** Checks the status of a connection being established. Returns 0 if the
- connection was established successfully, 1 if it's still in progress. If
- the attempt finished due to an error, an exception is thrown. */
- int poll_connect(const Time::TimeDelta &);
+ virtual bool poll_connect(const Time::TimeDelta &);
private:
void on_event(IO::PollEvent);