about summary refs log tree commit diff stats
path: root/091socket.cc
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-10-23 20:06:09 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-10-23 20:07:30 -0700
commit28191d317a46a1aeb3ec2034de2da626c38b6d73 (patch)
treeaad08fe0e1133b7374e247efe29dac4dea47e04e /091socket.cc
parentccfee30398074e2b5276a0ba295464ded4945ec9 (diff)
downloadmu-28191d317a46a1aeb3ec2034de2da626c38b6d73.tar.gz
3571 - make 'read-from-socket' non-blocking
Its interface now mirrors that of 'read-event'.
Diffstat (limited to '091socket.cc')
-rw-r--r--091socket.cc43
1 files changed, 32 insertions, 11 deletions
diff --git a/091socket.cc b/091socket.cc
index 2f605ac3..150074f1 100644
--- a/091socket.cc
+++ b/091socket.cc
@@ -202,22 +202,32 @@ case _READ_FROM_SOCKET: {
     raise << maybe(get(Recipe, r).name) << "second ingredient of '$read-from-socket' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
     break;
   }
-  if (SIZE(inst.products) != 2) {
-    raise << maybe(get(Recipe, r).name) << "'$read-from-socket' requires exactly two products, but got '" << inst.original_string << "'\n" << end();
+  int nprod = SIZE(inst.products);
+  if (nprod == 0 || nprod > 4) {
+    raise << maybe(get(Recipe, r).name) << "'$read-from-socket' requires 1-4 products, but got '" << inst.original_string << "'\n" << end();
     break;
   }
   if (!is_mu_text(inst.products.at(0))) {
     raise << maybe(get(Recipe, r).name) << "first product of '$read-from-socket' should be a text (address array character), but got '" << to_string(inst.products.at(0)) << "'\n" << end();
     break;
   }
-  if (!is_mu_boolean(inst.products.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "second product of '$read-from-socket' should be a boolean (eof?), but got '" << to_string(inst.products.at(1)) << "'\n" << end();
+  if (nprod > 1 && !is_mu_boolean(inst.products.at(1))) {
+    raise << maybe(get(Recipe, r).name) << "second product of '$read-from-socket' should be a boolean (data received?), but got '" << to_string(inst.products.at(1)) << "'\n" << end();
+    break;
+  }
+  if (nprod > 2 && !is_mu_boolean(inst.products.at(2))) {
+    raise << maybe(get(Recipe, r).name) << "third product of '$read-from-socket' should be a boolean (eof?), but got '" << to_string(inst.products.at(2)) << "'\n" << end();
+    break;
+  }
+  if (nprod > 3 && !is_mu_number(inst.products.at(3))) {
+    raise << maybe(get(Recipe, r).name) << "fourth product of '$read-from-socket' should be a number (error code), but got '" << to_string(inst.products.at(3)) << "'\n" << end();
     break;
   }
   break;
 }
 :(before "End Primitive Recipe Implementations")
 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);
   // 1. we'd like to simply read() from the socket
@@ -227,26 +237,37 @@ case _READ_FROM_SOCKET: {
   // 3. but poll() will block on EOF, so only use poll() on the very first
   // $read-from-socket on a socket
   if (!socket->polled) {
-    socket->polled = true;
     pollfd p;
     bzero(&p, sizeof(p));
     p.fd = socket->fd;
     p.events = POLLIN | POLLHUP;
-    if (poll(&p, /*num pollfds*/1, /*no timeout*/-1) <= 0) {
+    int status = poll(&p, /*num pollfds*/1, /*timeout*/100/*ms*/);
+    if (status == 0) {
+      products.at(0).push_back(/*no data*/0);
+      products.at(1).push_back(/*found*/false);
+      products.at(2).push_back(/*eof*/false);
+      products.at(3).push_back(/*error*/0);
+      break;
+    }
+    else if (status < 0) {
+      int error_code = errno;
       raise << maybe(current_recipe_name()) << "error in $read-from-socket\n" << end();
-      products.resize(2);
-      products.at(0).push_back(0);
-      products.at(1).push_back(false);
+      products.at(0).push_back(/*no data*/0);
+      products.at(1).push_back(/*found*/false);
+      products.at(2).push_back(/*eof*/false);
+      products.at(3).push_back(error_code);
       break;
     }
+    socket->polled = true;
   }
   int bytes = static_cast<int>(ingredients.at(1).at(0));
   char* contents = new char[bytes];
   bzero(contents, bytes);
   int bytes_read = recv(socket->fd, contents, bytes-/*terminal null*/1, MSG_DONTWAIT);
-  products.resize(2);
   products.at(0).push_back(new_mu_text(contents));
-  products.at(1).push_back(bytes_read <= 0);
+  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;
   break;
 }