about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-10-24 08:40:46 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-10-24 08:41:55 -0700
commit5eb5a8dea64cad10634930a49e82148a6265e472 (patch)
tree85ce03ae6e8d8f016969605559968bd989beba5a
parenta65a32aed450add3f81ecbdf9e07c44c97c5a14e (diff)
downloadmu-5eb5a8dea64cad10634930a49e82148a6265e472.tar.gz
3581
Fix CI. 3 different memory leaks in the socket internals.

The hard one was recognizing the need for
`receive-from-client-socket-and-close`.
-rw-r--r--091socket.cc23
-rw-r--r--092socket.mu17
2 files changed, 37 insertions, 3 deletions
diff --git a/091socket.cc b/091socket.cc
index ee76d3c6..180f2b27 100644
--- a/091socket.cc
+++ b/091socket.cc
@@ -50,6 +50,7 @@ case _OPEN_CLIENT_SOCKET: {
     break;
   }
   long long int result = reinterpret_cast<long long int>(client);
+//?   cerr << "$open-client-socket: " << client->fd << " -> " << result << '\n';
   products.at(0).push_back(static_cast<double>(result));
   break;
 }
@@ -108,6 +109,7 @@ case _OPEN_SERVER_SOCKET: {
     break;
   }
   long long int result = reinterpret_cast<long long int>(server);
+//?   cerr << "$open-server-socket: " << server->fd << " -> " << result << '\n';
   products.at(0).push_back(static_cast<double>(result));
   break;
 }
@@ -168,9 +170,11 @@ case _ACCEPT: {
   if (server) {
     socket_t* session = accept_session(server);
     long long int result = reinterpret_cast<long long int>(session);
+//?     cerr << "$accept from " << server->fd << ": " << session->fd << " -> " << result << '\n';
     products.at(0).push_back(static_cast<double>(result));
   }
   else {
+//?     cerr << "error in $accept from " << server->fd << '\n';
     products.at(0).push_back(0);
   }
   break;
@@ -230,6 +234,7 @@ case _READ_FROM_SOCKET: {
   products.resize(4);
   long long int x = static_cast<long long int>(ingredients.at(0).at(0));
   socket_t* socket = reinterpret_cast<socket_t*>(x);
+//?   cerr << "$read-from-socket: polling " << socket->fd << '\n';
   // 1. we'd like to simply read() from the socket
   // however read() on a socket never returns EOF, so we wouldn't know when to stop
   // 2. recv() can signal EOF, but it also signals "no data yet" in the beginning
@@ -243,6 +248,7 @@ case _READ_FROM_SOCKET: {
     p.events = POLLIN | POLLHUP;
     int status = poll(&p, /*num pollfds*/1, /*timeout*/100/*ms*/);
     if (status == 0) {
+//?       cerr << "$read-from-socket: poll() timeout\n";
       products.at(0).push_back(/*no data*/0);
       products.at(1).push_back(/*found*/false);
       products.at(2).push_back(/*eof*/false);
@@ -260,15 +266,24 @@ case _READ_FROM_SOCKET: {
     }
     socket->polled = true;
   }
+//?   cerr << "reading from socket " << socket->fd << '\n';
   int bytes = static_cast<int>(ingredients.at(1).at(0));
   char* contents = new char[bytes];
   bzero(contents, bytes);
+  int error_code = 0;
   int bytes_read = recv(socket->fd, contents, bytes-/*terminal null*/1, MSG_DONTWAIT);
+  if (bytes_read < 0) error_code = errno;
+//?   cerr << "bytes read: " << bytes_read << '\n';
+//?   if (error_code) {
+//?     ostringstream out;
+//?     out << "error in $read-from-socket " << socket->fd;
+//?     perror(out.str().c_str());
+//?   }
   products.at(0).push_back(new_mu_text(contents));
   products.at(1).push_back(/*found*/true);
   products.at(2).push_back(/*eof*/bytes_read <= 0);
-  products.at(3).push_back(/*error*/0);
-  delete contents;
+  products.at(3).push_back(error_code);
+  delete[] contents;
   break;
 }
 
@@ -288,9 +303,11 @@ case _WRITE_TO_SOCKET: {
 case _WRITE_TO_SOCKET: {
   long long int x = static_cast<long long int>(ingredients.at(0).at(0));
   socket_t* session = reinterpret_cast<socket_t*>(x);
+//?   cerr << "writing to socket " << session->fd << '\n';
   // write just one character at a time to the session socket
   long long int y = static_cast<long long int>(ingredients.at(1).at(0));
   char c = static_cast<char>(y);
+//?   cerr << "  " << c << '\n';
   if (write(session->fd, &c, 1) != 1) {
     raise << maybe(current_recipe_name()) << "failed to write to socket\n" << end();
     exit(0);
@@ -321,7 +338,9 @@ case _CLOSE_SOCKET: {
 case _CLOSE_SOCKET: {
   long long int x = static_cast<long long int>(ingredients.at(0).at(0));
   socket_t* socket = reinterpret_cast<socket_t*>(x);
+//?   cerr << "closing " << socket->fd << '\n';
   close(socket->fd);
+  delete socket;
   break;
 }
 
diff --git a/092socket.mu b/092socket.mu
index 9fa4e415..eacc501f 100644
--- a/092socket.mu
+++ b/092socket.mu
@@ -16,10 +16,13 @@ F - example-server-test: $open-server-socket failed]
   ]
   source:&:source:char <- start-reading-from-network 0/real-resources, [localhost/], port
   response:text <- drain source
+#?   $print [app: done draining], 10/newline
   10:@:char/raw <- copy *response
   memory-should-contain [
     10:array:character <- [abc]
   ]
+#?   $print [app: closing server socket], 10/newline
+  $close-socket socket
 ]
 # helper just for this scenario
 def example-handler query:text -> response:text [
@@ -62,6 +65,7 @@ F - example-server-test: $accept failed]
   query:text <- drain contents
   response:text <- call request-handler, query
   write-to-socket session, response
+#?   $print [app: closing session socket], 10/newline
   $close-socket session
 ]
 
@@ -86,7 +90,7 @@ def start-reading-from-network resources:&:resources, uri:text -> contents:&:sou
   req:text <- interpolate [GET _ HTTP/1.1], path
   request-socket socket, req
   contents:&:source:char, sink:&:sink:char <- new-channel 10000
-  start-running receive-from-socket socket, sink
+  start-running receive-from-client-socket-and-close socket, sink
 ]
 
 def request-socket socket:num, s:text -> socket:num [
@@ -118,6 +122,7 @@ def receive-from-socket socket:num, sink:&:sink:char -> sink:&:sink:char [
       done?:bool <- greater-or-equal i, bytes-read
       break-if done?
       c:char <- index *req, i  # todo: unicode
+#?       $print [read ], c, 10/newline
       sink <- write sink, c
       i <- add i, 1
       loop
@@ -125,6 +130,15 @@ def receive-from-socket socket:num, sink:&:sink:char -> sink:&:sink:char [
     loop-unless eof?
   }
   sink <- close sink
+#?   $print [read status: ] found? [ ] eof? [ ] error 10/newline
+]
+
+def receive-from-client-socket-and-close socket:num, sink:&:sink:char -> sink:&:sink:char [
+  local-scope
+  load-ingredients
+  sink <- receive-from-socket socket, sink
+#?   $print [app: closing socket after reading], 10/newline
+  $close-socket socket
 ]
 
 def write-to-socket socket:num, s:text [
@@ -135,6 +149,7 @@ def write-to-socket socket:num, s:text [
   {
     done?:bool <- greater-or-equal i, len
     break-if done?
+#?     $print i, 10/newline
     c:char <- index *s, i
     $write-to-socket socket, c
     i <- add i, 1