--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkTCP.cc Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,177 @@
+
+#include "NetworkTCP.hh"
+
+#include <cstdlib>
+#include <cassert>
+
+NetworkBuffer::NetworkBuffer (NetworkSocket &socket, size_t size_hint) :
+ socket(socket), buf(0), size(0), offset(0) {
+
+ // allocate initial buffer
+ if ((buf = (char *) malloc(size_hint)) == NULL)
+ throw CL_Error("malloc failed");
+
+ // remember size
+ size = size_hint;
+}
+
+void NetworkBuffer::resize (size_t new_size) {
+ // realloc buffer
+ if ((buf = (char *) realloc((void *) buf, new_size)) == NULL)
+ throw CL_Error("realloc failed");
+
+ // update size
+ size = new_size;
+}
+
+void NetworkBuffer::write (const char *buf_ptr, size_t buf_size) {
+ int 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);
+
+ } catch (CL_Error &e) {
+ // ignore EAGAIN, detect this by setting ret to -1
+ if (errno != EAGAIN)
+ throw;
+
+ ret = -1;
+ }
+
+ // if we managed to send something, adjust buf/size and buffer
+ if (ret > 0) {
+ buf_ptr += ret;
+ buf_size -= ret;
+
+ // sanity-check
+ assert(buf_size >= 0);
+
+ // if that was all, we're done
+ if (buf_size == 0)
+ return;
+ }
+ }
+
+ size_t new_size = size;
+
+ // calcluate new buffer size
+ while (offset + buf_size > new_size)
+ new_size *= 2;
+
+ // grow internal buffer if needed
+ if (new_size != size)
+ resize(new_size);
+
+ // copy into our internal buffer
+ memcpy(buf + offset, buf_ptr, buf_size);
+}
+
+void NetworkBuffer::flush_write (void) {
+ int 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)
+
+ } catch (CL_Error &e) {
+ // ignore EAGAIN and just return
+ if (errno == EAGAIN)
+ return;
+
+ else
+ throw;
+ }
+
+ // update offset
+ offset -= ret;
+
+ // shift the buffer forwards from (buf + ret) -> (buf), copying (old_offset - ret) bytes
+ memmove(buf, buf + ret, offset);
+}
+
+NetworkTCPTransport::NetworkTCPTransport (CL_Socket socket) :
+ socket(socket), in(NETWORK_TCP_INITIAL_IN_BUF), out(NETWORK_TCP_INITIAL_OUT_BUF) {
+
+ // use nonblocking sockets
+ socket.set_nonblocking(true);
+
+ // 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_triggered(), this, &NetworkTCPTransport::on_disconnected);
+}
+
+
+void NetworkTCPTransport::on_read (void) {
+ NetworkPacket packet;
+
+ do {
+ size_t to_read = 0;
+
+ // guess how much data to receive based on either the given length prefix or our minimim chunk size
+ if (in.read_prefix<uint16_t>(to_read) == false || to_read < NETWORK_TCP_CHUNK_SIZE)
+ to_read = NETWORK_TCP_CHUNK_SIZE
+
+ // do the recv
+ if (in.recv(socket, to_read) == -1)
+
+ // read out any packets
+ while (in.read_prefix_packet<uint16_t>(packet)) {
+ handle_packet(packet);
+ }
+ } while (...);
+}
+
+void NetworkTCPTransport::on_write (void) {
+ // just flush the output buffer
+ out.flush_write();
+}
+
+void NetworkTCPTransport::on_disconnected (void) {
+
+}
+
+void NetworkTCPTransport::write_packet (const NetworkPacket &packet) {
+ // just write to the output buffer
+ out.write(packet.get_buf(), packet.get_size());
+}
+
+NetworkTCPServer::NetworkTCPServer (const NetworkAddress &listen_addr) :
+ socket(tcp, ipv4) {
+
+ // bind
+ socket.bind(listen_addr);
+
+ // assign slots
+ slots.connect(socket.sig_read_triggered(), this, &NetworkTCPServer::on_accept);
+
+ // listen
+ socket.listen(NETWORK_LISTEN_BACKLOG);
+}
+
+
+void NetworkTCPServer::on_accept (void) {
+ // accept a new socket
+ NetworkSocket client_sock = socket.accept();
+
+ // create a new NetworkTCPTransport
+ NetworkTCPTransport *client = new NetworkTCPTransport(client_sock);
+
+ // let our user handle it
+ handle_client(client);
+}
+
+NetworkTCPClient::NetworkTCPClient (const NetworkAddress &connect_addr) :
+ NetworkTCPTransport(NetworkSocket(tcp, ipv4)) {
+
+ // connect
+ socket.connect(connect_addr);
+
+}