diff options
Diffstat (limited to 'src/core/netconnection.cc')
-rw-r--r-- | src/core/netconnection.cc | 167 |
1 files changed, 135 insertions, 32 deletions
diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc index 9790655..379df14 100644 --- a/src/core/netconnection.cc +++ b/src/core/netconnection.cc @@ -7,7 +7,6 @@ #include <sstream> #include "sys/sys.h" -#include "net/net.h" #include "core/application.h" #include "core/gameconnection.h" #include "core/netconnection.h" @@ -22,27 +21,86 @@ NetConnection::NetConnection() NetConnection::~NetConnection() { + disconnect(); +} + +void NetConnection::abort() +{ + connection_error= true; } void NetConnection::connect(std::string const &to_host, int to_port) { - TCPConnection::connect(to_host, to_port); - if(connected()) { - FD_ZERO(&clientset); - FD_SET(fd(), &clientset); + connection_error = false; + connection_fd = -1; + + if (valid()) + return; + + // resolve serverhostname + struct hostent *serverhostent; + serverhostent = gethostbyname(to_host.c_str()); + if (!serverhostent) { + con_warn << "Could not resolve '" << to_host.c_str() << "'" << std::endl; + abort(); + return; } + + con_print << "Connecting to " << inet_ntoa(*((struct in_addr *)serverhostent->h_addr)) << ":" << to_port << "..." << std::endl; + + // Get a socket file descriptor + connection_fd = socket(PF_INET, SOCK_DGRAM, 0); + if (connection_fd == -1) { + //con_error << "Network socket() failed!" << std::endl; + abort(); + return; + } + + // make the connection + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(to_port); + // FIXME inet_addr can still fail + server_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)serverhostent->h_addr))); + if (server_addr.sin_addr.s_addr == INADDR_NONE) { + con_error << "Network invalid address " << to_host << "!" << std::endl; + abort(); + return; + } + memset(server_addr.sin_zero, '\0', sizeof server_addr.sin_zero); + + /* + if (::connect(connection_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != 0) { + //con_error << "Network connect() failed!" << std::endl; + abort(); + return; + } + */ + + connection_host = to_host; + connection_port = to_port; + connection_error = false; - std::ostringstream osstream; - osstream << "pif "; - game()->localplayer()->serialize_client_update(osstream); - osstream << '\n'; - send(osstream.str()); + FD_ZERO(&clientset); + FD_SET(fd(), &clientset); + + game()->localplayer()->player_dirty = true; } void NetConnection::disconnect() { - TCPConnection::disconnect(); - FD_ZERO(&clientset); + if (connection_fd != -1) { + sendq.clear(); + sendq.assign("disconnect\n"); + transmit(); + + FD_ZERO(&clientset); + close(connection_fd); + } + + connection_fd = -1; + connection_error = false; + connection_host.clear(); + connection_port = 0; } bool NetConnection::has_messages() const @@ -64,25 +122,41 @@ void NetConnection::retreive(std::string & message) void NetConnection::receive() { // TODO: binary mode data transfer - std::string datablock; - TCPConnection::receive(datablock); + if (error() || invalid()) + return; + + ssize_t bytes_received; + + memset(recvbuf, '\0', BLOCKSIZE); + bytes_received = ::recv(connection_fd, recvbuf, BLOCKSIZE-1, 0); - if (error()) + if (bytes_received == 0) { + con_print << "Disconnected."; + abort(); + return; + } else if (bytes_received < 0) { + con_error << "Network receive() error!" << std::endl; + //perror("recv"); + abort(); return; - while (datablock.size() > 0) { + } + + std::string datablock; + datablock.assign(recvbuf); + + while (datablock.size()) { // scan the datablock for enters if (datablock[0] == '\n' || datablock[0] == '\r') { - if (messageblock.size() > 0) { + if (messageblock.size() >= FRAMESIZE) { + con_warn << "Incoming message exceeds " << FRAMESIZE << " bytes!\n"; + messageblock.clear(); + } else if (messageblock.size()) { recvq.push_back(messageblock); + //con_debug << "Incoming message '" << messageblock << "'" << std::endl; messageblock.clear(); } } else { - if (messageblock.size() < net::FRAMESIZE) { - messageblock.append(datablock.substr(0,1)); - } else { - con_warn << "Network message exceeds " << net::FRAMESIZE << " bytes!" << std::endl; - messageblock.clear(); - } + messageblock.append(datablock.substr(0,1)); } datablock.erase(0,1); } @@ -97,22 +171,33 @@ void NetConnection::frame(float seconds) fd_set readset = clientset; int nb = select(fd()+1, &readset, NULL, NULL, &timeout); - if (nb == 0) + if (nb == 0) { return; - + } if (nb == -1) { con_error << "Network error on select()" << std::endl; //perror("select"); abort(); } - if (FD_ISSET(this->fd(), &readset) && !error()) { + while (FD_ISSET(this->fd(), &readset) && !error()) { receive(); + while (has_messages()) { std::string message; retreive(message); parse_incoming_message(message); } + + nb = select(fd()+1, &readset, NULL, NULL, &timeout); + if (nb == 0) { + return; + } + if (nb == -1) { + con_error << "Network error on select()" << std::endl; + //perror("select"); + abort(); + } } } @@ -123,14 +208,32 @@ void NetConnection::send(std::string const &msg) void NetConnection::transmit() { - while (sendq.size() && valid() && !error()) { - TCPConnection::send(sendq.substr(0, net::FRAMESIZE-1)); - if (sendq.size() < net::FRAMESIZE) { - sendq.clear(); - } else { - sendq.erase(0, net::FRAMESIZE-1); + + if (error() || invalid()) + return; + + if (sendq.size() > FRAMESIZE) { + con_warn << "Outgoing message exceeds " << FRAMESIZE << " bytes!\n"; + //sendq.clear(); + //return; + } + + ssize_t bytes_sent = 0; + + while (sendq.size()) { + bytes_sent = ::sendto(connection_fd, sendq.c_str(), sendq.size(), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); + if (bytes_sent <= 0) { + con_error << "Network send() error!" << std::endl; + //perror("send"); + abort(); + return; } + + // assert (bytes_sent <= sendbuf.size()); + sendq.erase(0, bytes_sent); } + + sendq.clear(); } // parse incoming client messages |