From: Mikko Rasa Date: Sat, 6 Aug 2011 20:17:41 +0000 (+0300) Subject: Add ClientSocket and ServerSocket abstractions X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=e6f09239fae7ff675e1068365a06803dcc8f8d1f;p=libs%2Fnet.git Add ClientSocket and ServerSocket abstractions --- diff --git a/examples/netcat.cpp b/examples/netcat.cpp index 2532959..9bbad87 100644 --- a/examples/netcat.cpp +++ b/examples/netcat.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -15,7 +15,7 @@ class NetCat: public RegisteredApplication private: bool ipv6; bool listen; - Net::StreamListenSocket *server_sock; + Net::StreamServerSocket *server_sock; Net::StreamSocket *sock; IO::EventDispatcher event_disp; @@ -53,7 +53,7 @@ NetCat::NetCat(int argc, char **argv): } 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)); diff --git a/source/clientsocket.cpp b/source/clientsocket.cpp new file mode 100644 index 0000000..10ba0b0 --- /dev/null +++ b/source/clientsocket.cpp @@ -0,0 +1,87 @@ +#ifndef WIN32 +#include +#include +#endif +#include +#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 diff --git a/source/clientsocket.h b/source/clientsocket.h new file mode 100644 index 0000000..e222a5f --- /dev/null +++ b/source/clientsocket.h @@ -0,0 +1,46 @@ +#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 diff --git a/source/datagramsocket.cpp b/source/datagramsocket.cpp index 3f20ba5..32ecc23 100644 --- a/source/datagramsocket.cpp +++ b/source/datagramsocket.cpp @@ -10,7 +10,7 @@ namespace Msp { 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); @@ -18,7 +18,7 @@ DatagramSocket::DatagramSocket(Family f, int p): set_events(IO::P_INPUT); } -int DatagramSocket::connect(const SockAddr &addr) +bool DatagramSocket::connect(const SockAddr &addr) { SockAddr::SysAddr sa = addr.to_sys(); @@ -42,7 +42,7 @@ int DatagramSocket::connect(const SockAddr &addr) connected = true; - return (err==0)?0:1; + return true; } unsigned DatagramSocket::sendto(const char *buf, unsigned size, const SockAddr &addr) diff --git a/source/datagramsocket.h b/source/datagramsocket.h index 3903a6a..23ca296 100644 --- a/source/datagramsocket.h +++ b/source/datagramsocket.h @@ -1,17 +1,19 @@ #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 *&); }; diff --git a/source/serversocket.cpp b/source/serversocket.cpp new file mode 100644 index 0000000..6028483 --- /dev/null +++ b/source/serversocket.cpp @@ -0,0 +1,23 @@ +#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 diff --git a/source/serversocket.h b/source/serversocket.h new file mode 100644 index 0000000..10375f0 --- /dev/null +++ b/source/serversocket.h @@ -0,0 +1,32 @@ +#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 diff --git a/source/socket.cpp b/source/socket.cpp index 0e29509..b5a6ec8 100644 --- a/source/socket.cpp +++ b/source/socket.cpp @@ -41,11 +41,9 @@ WinSockHelper wsh; 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; @@ -62,9 +60,7 @@ Socket::Socket(const Private &p, const SockAddr &paddr): 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); @@ -77,7 +73,6 @@ Socket::Socket(Family af, int type, int proto): Socket::~Socket() { - signal_flush_required.emit(); #ifdef WIN32 closesocket(priv->handle); CloseHandle(*priv->event); @@ -86,7 +81,6 @@ Socket::~Socket() #endif delete local_addr; - delete peer_addr; delete priv; } @@ -143,13 +137,6 @@ const SockAddr &Socket::get_local_address() const 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 @@ -168,52 +155,5 @@ int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) #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 diff --git a/source/socket.h b/source/socket.h index 861012b..38d65da 100644 --- a/source/socket.h +++ b/source/socket.h @@ -28,11 +28,9 @@ protected: 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(); @@ -40,24 +38,15 @@ public: 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 diff --git a/source/streamlistensocket.cpp b/source/streamlistensocket.cpp deleted file mode 100644 index 681aded..0000000 --- a/source/streamlistensocket.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include -#include -#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(&sa.addr), &sa.size); - - RefPtr paddr = SockAddr::from_sys(sa); - return new StreamSocket(new_p, *paddr); -} - -} // namespace Net -} // namespace Msp diff --git a/source/streamlistensocket.h b/source/streamlistensocket.h deleted file mode 100644 index a24e731..0000000 --- a/source/streamlistensocket.h +++ /dev/null @@ -1,27 +0,0 @@ -#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 diff --git a/source/streamserversocket.cpp b/source/streamserversocket.cpp new file mode 100644 index 0000000..2809742 --- /dev/null +++ b/source/streamserversocket.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#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(&sa.addr), &sa.size); + + RefPtr paddr = SockAddr::from_sys(sa); + return new StreamSocket(new_p, *paddr); +} + +} // namespace Net +} // namespace Msp diff --git a/source/streamserversocket.h b/source/streamserversocket.h new file mode 100644 index 0000000..aa4868c --- /dev/null +++ b/source/streamserversocket.h @@ -0,0 +1,25 @@ +#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 diff --git a/source/streamsocket.cpp b/source/streamsocket.cpp index 5794ecd..3fa6b9a 100644 --- a/source/streamsocket.cpp +++ b/source/streamsocket.cpp @@ -14,8 +14,7 @@ namespace Msp { 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); @@ -24,11 +23,10 @@ StreamSocket::StreamSocket(const Private &p, const SockAddr &paddr): } 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"); @@ -64,14 +62,12 @@ int StreamSocket::poll_connect(const Time::TimeDelta &timeout) 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"); @@ -121,7 +117,7 @@ int StreamSocket::connect(const SockAddr &addr) signal_connect_finished.emit(0); } - return (err==0)?0:1; + return connected; } void StreamSocket::on_event(IO::PollEvent ev) diff --git a/source/streamsocket.h b/source/streamsocket.h index 3ffe72a..3fc6d04 100644 --- a/source/streamsocket.h +++ b/source/streamsocket.h @@ -1,16 +1,14 @@ #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 @@ -30,14 +28,9 @@ public: 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);