# HG changeset patch # User terom # Date 1229385402 0 # Node ID 5589abf5e61b8886c5fdd36477dca72f336ea57d # Parent 01d3c340b372269c5b8dea3af593a74490dd43b9 break the network code. Too late to set up a branch for this now diff -r 01d3c340b372 -r 5589abf5e61b src/Engine.cc --- a/src/Engine.cc Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Engine.cc Mon Dec 15 23:56:42 2008 +0000 @@ -22,7 +22,7 @@ void Engine::setupNetworkClient (const std::string &connect_host, const std::string &connect_port) { // connect_to - CL_IPAddress connect_addr(connect_host, connect_port); + NetworkAddress connect_addr(connect_host, connect_port); // create the client net_client = new NetworkClient(*this, game_state, connect_addr); diff -r 01d3c340b372 -r 5589abf5e61b src/Network/Address.cc --- a/src/Network/Address.cc Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/Address.cc Mon Dec 15 23:56:42 2008 +0000 @@ -3,10 +3,104 @@ #include +NetworkAddress::NetworkAddress (void) : + hostname(), service(), address_length(0) +{ + +} + +NetworkAddress::NetworkAddress (std::string service) : + hostname(), service(service), address_length(0) +{ + +} + +NetworkAddress::NetworkAddress (std::string hostname, std::string service) : + hostname(hostname), service(service), address_length(0) +{ + +} + +NetworkAddress::NetworkAddress (const sockaddr *addr, socklen_t len) : + hostname(hostname), service(service), address_length(0) +{ + // proxy to set_sockaddr + set_sockaddr(addr, len); +} + +addrinfo* NetworkAddress::get_addrinfo (int family, int socktype, int protocol, int flags) const { + addrinfo hints, *results; + int err; + + // initialize flags + hints.ai_flags = flags; + hints.ai_family = family; + hints.ai_socktype = socktype; + hints.ai_protocol = protocol; + hints.ai_addrlen = 0; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + // hostname + service may be NULL + const char *hostname = this->hostname.empty() ? NULL : this->hostname.c_str(); + const char *service = this->service.empty() ? NULL : this->service.c_str(); + + // do getaddrinfo() + if ((err = getaddrinfo(hostname, service, &hints, &results))) + throw NetworkAddressError(*this, "getaddrinfo", gai_strerror(err)); + + // done + return results; +} + +const sockaddr* NetworkAddress::get_sockaddr (socklen_t &len_ref) const { + // we can't figure this out ourselves... + if (address_length == 0) + throw Error("NetworkAddress::get_sockaddr called without a valid sockaddr set"); + + // update len + len_ref = address_length; + + // and return a pointer to our internal address + return (const sockaddr*) &address; +} + +void NetworkAddress::set_sockaddr (const sockaddr *addr, socklen_t len) { + char host_buf[NI_MAXHOST], serv_buf[NI_MAXSERV]; + int err; + + // invalid length? + if (len > sizeof(this->address)) + throw NetworkAddressError(*this, "set_sockaddr", "invalid sockaddr length"); + + // do getnameinfo() + if ((err = getnameinfo(addr, len, host_buf, NI_MAXHOST, serv_buf, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV))) + throw NetworkAddressError(*this, "getnameinfo", gai_strerror(err)); + + // copy over to address + memcpy(&this->address, addr, len); +} + std::ostream& operator<< (std::ostream &s, const NetworkAddress &addr) { - s << "[" << addr.get_address() << ":" << addr.get_port() << "]"; + s << "[" << addr.get_hostname() << ":" << addr.get_service() << "]"; return s; } +std::string NetworkAddressError::build_str (const NetworkAddress &addr, const char *op, const char *msg) { + std::stringstream ss; + + ss << op << ": " << addr << ": " << msg; + + return ss.str(); +} + +NetworkAddressError::NetworkAddressError (const NetworkAddress &addr, const char *op, const char *msg) : + Error(build_str(addr, op, msg)) +{ + +} + + + diff -r 01d3c340b372 -r 5589abf5e61b src/Network/Address.hh --- a/src/Network/Address.hh Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/Address.hh Mon Dec 15 23:56:42 2008 +0000 @@ -1,16 +1,159 @@ #ifndef NETWORK_ADDRESS_HH #define NETWORK_ADDRESS_HH -#include +#include "../Error.hh" + +/* + * Platform-specific includes + */ +#ifndef WIN32 + // linux + #include + #include + #include +#else + #error "This network code won't compile on win32 :)" +#endif + +#include + +// assume... +#if INET6_ADDRSTRLEN < INET_ADDRSTRLEN + #error INET6_ADDRSTRLEN is smaller than INET_ADDRSTRLEN +#endif + +/** + * Length of a network address + */ +const socklen_t NETWORK_ADDRESS_LENGTH = INET6_ADDRSTRLEN; /** * We use ClanLib's IPAddress API, but with our own name */ -typedef CL_IPAddress NetworkAddress; +class NetworkAddress { + private: + /** + * Our human-readable hostname + */ + std::string hostname; + + /** + * Our human-readable service + */ + std::string service; + + /** + * Our machine-readable address and its length + */ + sockaddr_storage address; + socklen_t address_length; + + public: + /** + * Construct an empty NetworkAddress + */ + NetworkAddress (void); + + /** + * Construct a NetworkAddress with a NULL hostname, and a specific service + */ + NetworkAddress (std::string service); + + /** + * Construct a NetworkAddress on a specific hostname and service + */ + NetworkAddress (std::string hostname, std::string service); + + /** + * Construct a NetworkAddress from a machine-readable address of the given length + */ + NetworkAddress (const sockaddr *addr, socklen_t len); + + public: + /** + * Get a addrinfo* for this address using the given family/type/protocol/flags. + * + * Remember to free the returned pointer using freeaddrinfo() after use. + * + * @param family the socket family for hints.ai_family + * @param socktype the socket type for hints.ai_socktype + * @param protoocl the socket protocol for hints.ai_protocol + * @param flags the flags for hints.ai_flags + * @return linked list of addrinfo's + * @throw NetworkAddressError if resolving this address fails + */ + addrinfo* get_addrinfo (int family, int socktype, int protocol = 0, int flags = 0) const; + + /** + * Get a sockaddr* for this address. This is only valid for NetworkAddress's which have had set_sockaddr called + * on them. + * + * @param len_ref updated to the sockaddr length + * @return borrowed sockaddr pointer + */ + const sockaddr* get_sockaddr (socklen_t &len_ref) const; + + /** + * Set a sockaddr for this address + * + * @param addr the address to copy, of len bytes + * @param len the size of the sockaddr + */ + void set_sockaddr (const sockaddr *addr, socklen_t len); + + /** + * Get the human-readable hostname + */ + std::string get_hostname (void) const { return hostname; } + + /** + * Get the human-readable service name + */ + std::string get_service (void) const { return service; } + + /** + * Equal-to comparison operator. This requires that the machine-readable address be available. + */ + bool operator== (const NetworkAddress &other) const { + return (address_length == other.address_length) && memcmp(&address, &other.address, address_length) == 0; + } + + /** + * Not-qqual-to comparison operator. This requires that the machine-readable address be available. + */ + bool operator!= (const NetworkAddress &other) const { + return (address_length != other.address_length) || memcmp(&address, &other.address, address_length) != 0; + } + + /** + * Less-than comparison operator. Smaller addresses are always lesser. + */ + bool operator< (const NetworkAddress &other) const { + return (address_length < other.address_length) || memcmp(&address, &other.address, other.address_length) < 0; + } + + /** + * Greater-than comparison operator. Bigger addresses are always greater. + */ + bool operator> (const NetworkAddress &other) const { + return (address_length > other.address_length) || memcmp(&address, &other.address, address_length) > 0; + } +}; /** * Formatted as [:] */ std::ostream& operator<< (std::ostream &s, const NetworkAddress &addr); +/** + * + */ +class NetworkAddressError : public Error { + protected: + static std::string build_str (const NetworkAddress &addr, const char *op, const char *msg); + + public: + NetworkAddressError (const NetworkAddress &addr, const char *op, const char *msg); +}; + #endif /* NETWORK_ADDRESS_HH */ diff -r 01d3c340b372 -r 5589abf5e61b src/Network/Buffer.cc --- a/src/Network/Buffer.cc Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/Buffer.cc Mon Dec 15 23:56:42 2008 +0000 @@ -8,7 +8,7 @@ /* * NetworkBufferBase */ -NetworkBufferBase::NetworkBufferBase (NetworkSocket &socket, size_t size_hint) : +NetworkBufferBase::NetworkBufferBase (NetworkSocket *socket, size_t size_hint) : socket(socket), buf(0), size(0), offset(0) { // allocate initial buffer @@ -59,15 +59,14 @@ /* * NetworkBufferInput */ -NetworkBufferInput::NetworkBufferInput (NetworkSocket &socket, size_t size_hint) : +NetworkBufferInput::NetworkBufferInput (NetworkSocket *socket, size_t size_hint) : NetworkBufferBase(socket, size_hint) { } bool NetworkBufferInput::try_read (size_t item_size) { - int ret; - size_t to_read = item_size; + size_t ret, to_read = item_size; // keept reads at at least NETWORK_BUFFER_CHUNK_SIZE bytes if (to_read < NETWORK_BUFFER_CHUNK_SIZE) @@ -77,22 +76,11 @@ resize(to_read); // read once - try { - ret = socket.recv(buf + offset, to_read); - - } catch (CL_Error &e) { - if (errno == EAGAIN) - return false; + ret = socket->recv(buf + offset, to_read); - else - throw NetworkSocketOSError(socket, "recv"); - } - - // handle EOF + // nothing left? if (ret == 0) - throw NetworkSocketEOFError(socket, "recv"); - - assert(ret >= 0); + return false; // update offset offset += ret; @@ -129,7 +117,7 @@ /* * NetworkBufferOutput */ -NetworkBufferOutput::NetworkBufferOutput (NetworkSocket &socket, size_t size_hint) : +NetworkBufferOutput::NetworkBufferOutput (NetworkSocket *socket, size_t size_hint) : NetworkBufferBase(socket, size_hint) { @@ -137,22 +125,13 @@ void NetworkBufferOutput::push_write (char *buf_ptr, size_t buf_size) { - int ret; + size_t ret; // try and short-circuit writes unless we have already buffered data if (offset == 0) { - try { - // attempt to send something - ret = socket.send(buf_ptr, buf_size); + // attempt to send something + ret = socket->send(buf_ptr, buf_size); - } catch (CL_Error &e) { - // ignore EAGAIN, detect this by setting ret to -1 - if (errno != EAGAIN) - throw NetworkSocketOSError(socket, "send"); - - ret = -1; - } - // if we managed to send something, adjust buf/size and buffer if (ret > 0) { // sanity-check @@ -175,24 +154,18 @@ } void NetworkBufferOutput::flush_write (void) { - int ret; + size_t ret; // ignore if we don't have any data buffered if (offset == 0) return; // attempt to write as much as possible - try { - ret = socket.send(buf, offset); + ret = socket->send(buf, offset); - } catch (CL_Error &e) { - // ignore EAGAIN and just return - if (errno == EAGAIN) - return; - - else - throw NetworkSocketOSError(socket, "send"); - } + // busy? + if (ret == 0) + return; // trim the buffer trim(ret); diff -r 01d3c340b372 -r 5589abf5e61b src/Network/Buffer.hh --- a/src/Network/Buffer.hh Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/Buffer.hh Mon Dec 15 23:56:42 2008 +0000 @@ -25,7 +25,7 @@ class NetworkBufferBase { protected: /** The socket that we use */ - NetworkSocket socket; + NetworkSocket *socket; /** The buffer itself */ char *buf; @@ -37,7 +37,7 @@ /** * Allocate buf using the given initial size, and set offset to zero */ - NetworkBufferBase (NetworkSocket &socket, size_t size_hint); + NetworkBufferBase (NetworkSocket *socket, size_t size_hint); /** * Free()'s the buf @@ -76,7 +76,7 @@ /** * @see NetworkBufferBase */ - NetworkBufferInput (NetworkSocket &socket, size_t size_hint); + NetworkBufferInput (NetworkSocket *socket, size_t size_hint); private: /** @@ -187,7 +187,7 @@ /** * @see NetworkBufferBase */ - NetworkBufferOutput (NetworkSocket &socket, size_t size_hint); + NetworkBufferOutput (NetworkSocket *socket, size_t size_hint); private: /** diff -r 01d3c340b372 -r 5589abf5e61b src/Network/Socket.cc --- a/src/Network/Socket.cc Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/Socket.cc Mon Dec 15 23:56:42 2008 +0000 @@ -1,8 +1,275 @@ #include "Socket.hh" +#include "../Engine.hh" #include +NetworkSocket::NetworkSocket (int family, int socktype, int protocol) : + fd(-1), family(family), socktype(socktype), protocol(protocol), bound(false) +{ + +} + +NetworkSocket::NetworkSocket (int fd) : + fd(fd), family(0), socktype(0), protocol(0), bound(false) +{ + +} + +NetworkSocket::~NetworkSocket (void) { + // close any remaining socket + if (fd >= 0) + force_close(); +} + +void NetworkSocket::lazy_socket (int family, int socktype, int protocol) { + // if we already have a socket, exit + if (fd >= 0) + return; + + // check that we don't have conflicting family/type/protocol + if ( + (this->family && family != this->family) || + (this->socktype && socktype != this->socktype) || + (this->protocol && protocol != this->protocol) + ) + throw NetworkSocketError(*this, "socket.create", "family/socktype/protocol mismatch"); + + // create the socket or fail + if ((fd = ::socket(family, socktype, protocol)) < 0) + throw NetworkSocketOSError(*this, "socket"); + + // update our family/type/protocol + this->family = family; + this->socktype = socktype; + this->protocol = protocol; +} + +void NetworkSocket::force_close (void) { + // use closesocket + if (::closesocket(fd)) + Engine::log(WARN, "socket.force_close") << "error closing socket: " /* XXX: errno */; + + // invalidate fd + fd = -1; +} + +void NetworkSocket::bind (const NetworkAddress &addr) { + // get our addrinfo + addrinfo *r, *results = addr.get_addrinfo(family, socktype, protocol, AI_PASSIVE); + + // find the right address to bind to + for (r = results; r; r = r->ai_next) { + // create socket if needed, warn on errors + try { + lazy_socket(r->ai_family, r->ai_socktype, r->ai_protocol); + + } catch (NetworkSocketError &e) { + Engine::log(WARN, "socket.bind") << "unable to create socket for " << r << ": " << e.what(); + continue; + } + + // bind it, warn on errors + if (::bind(fd, r->ai_addr, r->ai_addrlen)) { + Engine::log(WARN, "socket.bind") << "unable to bind on " << r /* XXX: errno */ ; + + // close the bad socket + force_close(); + + continue; + + } else { + // we have a bound socket, break + break; + } + } + + // release our addrinfo + freeaddrinfo(results); + + // if we failed to bind, r is a NULL pointer + if (r == NULL) + throw NetworkSocketError(*this, "bind", "unable to bind on any addresses"); + + // mark ourselves as bound + bound = true; +} + +void NetworkSocket::listen (int backlog) { + // just call listen + if (::listen(fd, backlog)) + throw NetworkSocketOSError(*this, "listen"); +} + +NetworkAddress NetworkSocket::get_local_address (void) { + sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + + // do getsockname() + if (::getsockname(fd, (sockaddr *) &addr, &addrlen)) + throw NetworkSocketOSError(*this, "getsockname"); + + // return addr + return NetworkAddress((sockaddr *) &addr, addrlen); +} + +NetworkAddress NetworkSocket::get_remote_address (void) { + sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + + // do getpeername() + if (::getpeername(fd, (sockaddr *) &addr, &addrlen)) + throw NetworkSocketOSError(*this, "getpeername"); + + // return addr + return NetworkAddress((sockaddr *) &addr, addrlen); +} + +void NetworkSocket::set_nonblocking (bool nonblocking) { + // XXX: linux-specific + if (fcntl(fd, F_SETFL, O_NONBLOCK, nonblocking ? 1 : 0) == -1) + throw NetworkSocketOSError(*this, "fcntl(F_SETFL, O_NONBLOCK)"); +} + +NetworkSocket* NetworkSocket::accept (NetworkAddress *src) { + int new_fd; + sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + + // try and get the FD + if ((new_fd = ::accept(fd, (sockaddr *) &addr, &addrlen))) + throw NetworkSocketOSError(*this, "accept"); + + // allocate new NetworkSocket for new_fd + NetworkSocket *socket = new NetworkSocket(new_fd); + + // update src + if (src) + src->set_sockaddr((sockaddr *) &addr, addrlen); + + // done + return socket; +} + +void NetworkSocket::connect (const NetworkAddress &addr) { + // get our addrinfo + addrinfo *r, *results = addr.get_addrinfo(family, socktype, protocol); + + // find the right address to bind to + for (r = results; r; r = r->ai_next) { + // create socket if needed, warn on errors + try { + lazy_socket(r->ai_family, r->ai_socktype, r->ai_protocol); + + } catch (NetworkSocketError &e) { + Engine::log(WARN, "socket.connect") << "unable to create socket for " << r << ": " << e.what(); + continue; + } + + // connect it, warn on errors + if (::connect(fd, r->ai_addr, r->ai_addrlen)) { + Engine::log(WARN, "socket.connect") << "unable to connect to " << r /* XXX: errno */ ; + + // close unless bound, to not keep invalid sockets hanging around + if (!bound) + force_close(); + + continue; + + } else { + // we have a connected socket, break + break; + } + } + + // release our addrinfo + freeaddrinfo(results); + + // if we failed to connect, r is a NULL pointer + if (r == NULL) + throw NetworkSocketError(*this, "connect", "unable to connect to any addresses"); +} + +size_t NetworkSocket::send (const char *buf, size_t size, const NetworkAddress *dest) { + ssize_t ret; + + // use send or sendto? + if (dest) { + const sockaddr *addr; + socklen_t addr_len; + + // get destination address + addr = dest->get_sockaddr(addr_len); + + // sendto() + if ((ret = ::sendto(fd, buf, size, 0, addr, addr_len)) < 0 && errno != EAGAIN) + throw NetworkSocketOSError(*this, "sendto"); + + } else { + // send() + if ((ret = ::send(fd, buf, size, 0)) < 0 && errno != EAGAIN) + throw NetworkSocketOSError(*this, "send"); + + } + + // sanity-check + if (ret == 0) { + // XXX: not sure what this means... + Engine::log(ERROR, "socket.send") << "send[to] returned zero, trying again..."; + return 0; + } + + // EAGAIN? + if (ret < 0) + return 0; + + // return number of bytes sent + return ret; +} + +size_t NetworkSocket::recv (char *buf, size_t size, NetworkAddress *src) { + ssize_t ret; + + // use recv or recvfrom? + if (src) { + sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + + // recvfrom() + if ((ret = ::recvfrom(fd, buf, size, 0, (sockaddr *) &addr, &addr_len)) < 0 && errno != EAGAIN) + throw NetworkSocketOSError(*this, "recvfrom"); + + // modify src... + src->set_sockaddr((sockaddr *) &addr, addr_len); + + } else { + // recv + if ((ret = ::recv(fd, buf, size, 0)) < 0 && errno != EAGAIN) + throw NetworkSocketOSError(*this, "recv"); + + } + + // EOF? + if (ret == 0) + throw NetworkSocketEOFError(*this, "recv"); + + // EAGAIN? + if (ret < 0) + return 0; + + // return number of bytes received + return ret; +} + +void NetworkSocket::close (void) { + // use closesocket + if (::closesocket(fd)) + throw NetworkSocketOSError(*this, "close"); + + // invalidate fd + fd = -1; +} + std::string NetworkSocketError::build_str (const NetworkSocket &socket, const char *op, const char *err) { std::stringstream ss; diff -r 01d3c340b372 -r 5589abf5e61b src/Network/Socket.hh --- a/src/Network/Socket.hh Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/Socket.hh Mon Dec 15 23:56:42 2008 +0000 @@ -2,23 +2,165 @@ #define NETWORK_SOCKET_HH #include "../Error.hh" +#include "Address.hh" -#include +/* + * Platform-specific includes + */ +#ifndef WIN32 + // linux + #include + #include + #include + #include + + #define closesocket close +#else + #error "This network code won't compile on win32 :)" +#endif + #include #include /** - * We use ClanLib's Socket API, but with our own name + * We use ClanLib's Socket API, but with our own extensions... */ -typedef CL_Socket NetworkSocket; +class NetworkSocket { + private: + /** The file descriptor */ + int fd; + + /** Socket domain */ + int family; + + /** Socket type */ + int socktype; + + /** Socket protocol */ + int protocol; + + /** + * Has the socket been explicitly bind()'d? If so, force ourselves to use this socket in connect(). + */ + bool bound; + + /** + * Read/write signals + */ + CL_Signal_v0 _sig_read, _sig_write; + + public: + /** + * Construct a socket of the specific type. Family and protocol can be left as NULL, but type should usually + * be specified. + */ + NetworkSocket (int family, int socktype, int protocol = 0); + + /** + * Create a socket from the given pre-existing fd + */ + NetworkSocket (int fd); + + /** + * Force-close the socket if it's still open + */ + ~NetworkSocket (void); + + private: + // XXX: nocopy + + /** + * Create a new socket of the given type, unless we already have one + */ + void lazy_socket (int family, int type, int protocol); + + /** + * Close, ignoring errors + */ + void force_close (void); + + public: + /** + * Get the socket fd... promise not to break it + */ + int get_socket (void) const { return fd; } + + /** + * Bind to a specific local address + */ + void bind (const NetworkAddress &addr); + + /** + * Put socket into listen mode + */ + void listen (int backlog); + + /** + * Get local address + */ + NetworkAddress get_local_address (void); + + /** + * Get remote address + */ + NetworkAddress get_remote_address (void); + + /** + * Make send/recv/connect non-blocking + */ + void set_nonblocking (bool nonblocking); + + /** + * Accept a new connection, optionally giving the connection's source address + */ + NetworkSocket* accept (NetworkAddress *src); + + /** + * Establish a new connection + */ + void connect (const NetworkAddress &addr); + + /** + * Send, optionally using the specific destination + * + * @return number of bytes sent, zero if busy + * @throw NetworkSocketError on error + */ + size_t send (const char *buf, size_t size, const NetworkAddress *dest = NULL); + + /** + * Recv, optionally storing the source in src + * + * @return number of bytes received, zero if none available + * @throw NetworkSocketEOFError if the connection was closed + * @throw NetworkSocketError on error + */ + size_t recv (char *buf, size_t size, NetworkAddress *src = NULL); + + /** + * Close the socket + */ + void close (void); + + /** + * Triggered when socket becomes readable + */ + CL_Signal_v0& sig_read (void) { return _sig_read; } + + /** + * Triggered when socket becomes writeable after a send that returned zero + */ + CL_Signal_v0& sig_write (void) { return _sig_write; } +}; /** * Base class for expcetions thrown by socket methods */ class NetworkSocketError : public Error { protected: - std::string build_str (const NetworkSocket &socket, const char *op, const char *err); - + static std::string build_str (const NetworkSocket &socket, const char *op, const char *err); + + public: NetworkSocketError (const NetworkSocket &socket, const char *op, const char *err); }; diff -r 01d3c340b372 -r 5589abf5e61b src/Network/TCP.cc --- a/src/Network/TCP.cc Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/TCP.cc Mon Dec 15 23:56:42 2008 +0000 @@ -5,15 +5,18 @@ /* * NetworkTCPTransport */ -NetworkTCPTransport::NetworkTCPTransport (NetworkSocket socket) : +NetworkTCPTransport::NetworkTCPTransport (NetworkSocket *socket) : socket(socket), in(socket, NETWORK_TCP_INITIAL_IN_BUF), out(socket, NETWORK_TCP_INITIAL_OUT_BUF) { // connect signals - slots.connect(socket.sig_read_triggered(), this, &NetworkTCPTransport::on_read); - slots.connect(socket.sig_write_triggered(), this, &NetworkTCPTransport::on_write); - slots.connect(socket.sig_disconnected(), this, &NetworkTCPTransport::on_disconnected); + slots.connect(socket->sig_read(), this, &NetworkTCPTransport::on_read); + slots.connect(socket->sig_write(), this, &NetworkTCPTransport::on_write); } - + +NetworkTCPTransport::~NetworkTCPTransport (void) { + // release socket + delete socket; +} void NetworkTCPTransport::on_read (void) { uint32_t length; @@ -56,11 +59,6 @@ _sig_disconnect(); } } - -void NetworkTCPTransport::on_disconnected (void) { - // pass right through - _sig_disconnect(); -} void NetworkTCPTransport::write_packet (const NetworkPacketBuffer &packet) { uint32_t prefix = packet.get_data_size(); @@ -82,17 +80,17 @@ } } +/* + * NetworkTCPServer + */ NetworkTCPServer::NetworkTCPServer (const NetworkAddress &listen_addr) : - socket(CL_Socket::tcp, CL_Socket::ipv4) { - - // wow... I didn't know ClanLib was *this* crap - socket.proto = CL_Socket::tcp; + socket(AF_UNSPEC, SOCK_STREAM) { // bind socket.bind(listen_addr); // assign slots - slots.connect(socket.sig_read_triggered(), this, &NetworkTCPServer::on_accept); + slots.connect(socket.sig_read(), this, &NetworkTCPServer::on_accept); // listen socket.listen(NETWORK_LISTEN_BACKLOG); @@ -104,7 +102,7 @@ void NetworkTCPServer::on_accept (void) { // accept a new socket - NetworkSocket client_sock = socket.accept(); + NetworkSocket *client_sock = socket.accept(NULL); // create a new NetworkTCPTransport NetworkTCPTransport *client = buildTransport(client_sock); @@ -113,19 +111,19 @@ _sig_client(client); } -NetworkTCPTransport* NetworkTCPServer::buildTransport (CL_Socket &socket) { +NetworkTCPTransport* NetworkTCPServer::buildTransport (NetworkSocket *socket) { return new NetworkTCPTransport(socket); } +/* + * NetworkTCPClient + */ NetworkTCPClient::NetworkTCPClient (const NetworkAddress &connect_addr) : - NetworkTCPTransport(NetworkSocket(CL_Socket::tcp, CL_Socket::ipv4)) { + NetworkTCPTransport(new NetworkSocket(AF_UNSPEC, SOCK_STREAM)) { - // wow... I didn't know ClanLib was *this* crap - socket.proto = CL_Socket::tcp; - // connect - socket.connect(connect_addr); + socket->connect(connect_addr); // use nonblocking sockets - socket.set_nonblocking(true); + socket->set_nonblocking(true); } diff -r 01d3c340b372 -r 5589abf5e61b src/Network/TCP.hh --- a/src/Network/TCP.hh Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/TCP.hh Mon Dec 15 23:56:42 2008 +0000 @@ -26,7 +26,7 @@ /** * The SOCK_STREAM socket */ - NetworkSocket socket; + NetworkSocket *socket; /** * Our input buffer associated with socket @@ -44,7 +44,12 @@ /** * Construct this using the given socket */ - NetworkTCPTransport (NetworkSocket socket); + NetworkTCPTransport (NetworkSocket *socket); + + /** + * Deletes the socket + */ + ~NetworkTCPTransport (void); private: /** @@ -56,11 +61,6 @@ * Triggered when the socket is read for send */ void on_write (void); - - /** - * Triggered when the socket is disconnected (?) - */ - void on_disconnected (void); /** * The packet-read signal @@ -74,14 +74,14 @@ public: /** - * Get this TCP socket's local ddress + * Get this TCP socket's local address */ - NetworkAddress getLocalAddress (void) { return socket.get_source_address(); } + NetworkAddress getLocalAddress (void) { return socket->get_local_address(); } /** * Get this TCP socket's remote address */ - NetworkAddress getRemoteAddress (void) { return socket.get_dest_address(); } + NetworkAddress getRemoteAddress (void) { return socket->get_remote_address(); } /** * Write the given packet to this socket output, buffering the data if need be @@ -138,7 +138,7 @@ * * @param socket the socket returned by accept() */ - virtual NetworkTCPTransport* buildTransport (CL_Socket &socket); + virtual NetworkTCPTransport* buildTransport (NetworkSocket *socket); public: /** diff -r 01d3c340b372 -r 5589abf5e61b src/Network/UDP.cc --- a/src/Network/UDP.cc Mon Dec 15 16:41:00 2008 +0000 +++ b/src/Network/UDP.cc Mon Dec 15 23:56:42 2008 +0000 @@ -1,52 +1,49 @@ #include "UDP.hh" +#include "../Engine.hh" #include #include NetworkUDP::NetworkUDP (void) : - socket(CL_Socket::udp, CL_Socket::ipv4) { - + socket(AF_UNSPEC, SOCK_DGRAM) +{ // do not bind // connect signal - slots.connect(socket.sig_read_triggered(), this, &NetworkUDP::on_recv); + slots.connect(socket.sig_read(), this, &NetworkUDP::on_recv); // nonblocking socket.set_nonblocking(true); } NetworkUDP::NetworkUDP (const NetworkAddress &bind_addr) : - socket(CL_Socket::udp, CL_Socket::ipv4) { + socket(AF_UNSPEC, SOCK_DGRAM) { // bind socket socket.bind(bind_addr); // connect signal - slots.connect(socket.sig_read_triggered(), this, &NetworkUDP::on_recv); + slots.connect(socket.sig_read(), this, &NetworkUDP::on_recv); // nonblocking socket.set_nonblocking(true); } void NetworkUDP::on_recv (void) { - int ret; + size_t ret; NetworkPacket pkt; NetworkAddress src; // receieve as many packets as possible do { // attempt to recv a packet - try { - ret = socket.recv(pkt.get_buf(), pkt.get_buf_size(), src); + ret = socket.recv(pkt.get_buf(), pkt.get_buf_size(), &src); + + // no more packets? + if (ret == 0) + return; - } catch (CL_Error &e) { - if (errno == EAGAIN) - return; - else - throw; - } - // set packet data size pkt.set_data_size(ret); @@ -57,23 +54,26 @@ } bool NetworkUDP::sendto (const NetworkPacketBuffer &packet, const NetworkAddress &dst) { - int ret; + size_t ret; - // XXX: shouldn't get trimmed try { - ret = socket.send(packet.get_buf(), packet.get_data_size(), dst); + // try and send + ret = socket.send(packet.get_buf(), packet.get_data_size(), &dst); - } catch (CL_Error &e) { - // XXX: catch some errors, but not others? + } catch (NetworkSocketError &e) { + // catch and log errors + Engine::log(WARN, "udp.sendto") << "socket->send raised error: " << e.what(); return false; } - - assert(ret > 0); - // UDP shouldn't trim packets - assert((unsigned int) ret == packet.get_data_size()); - - // good - return true; + // weird packet size? + if (ret != packet.get_data_size()) { + Engine::log(ERROR, "udp.sendto") << "socket->send returned weird length: " << ret << ", packet was " << packet.get_data_size(); + return false; + + } else { + // sent + return true; + } }