about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStephen Malina <stephenmalina@gmail.com>2016-09-25 10:42:15 -0400
committerStephen Malina <stephenmalina@gmail.com>2016-10-07 08:09:42 -0400
commitd7e48920f7faf092d972ea02fc02551ba1c5bb23 (patch)
treeff2e3a01983ae2be287d0183909f2e2a7bb2289a
parent4a70fb39cc6a0f2ebe34e9b58b873e13d8221015 (diff)
downloadmu-d7e48920f7faf092d972ea02fc02551ba1c5bb23.tar.gz
3458
Testable network interface and write flow.
-rw-r--r--092socket.mu116
-rw-r--r--server-socket.mu4
2 files changed, 118 insertions, 2 deletions
diff --git a/092socket.mu b/092socket.mu
new file mode 100644
index 00000000..60515b06
--- /dev/null
+++ b/092socket.mu
@@ -0,0 +1,116 @@
+# Wrappers around socket primitives that take a 'network-interface' object and
+# are thus easier to test.
+# The current semantics of fake port-connections don't match UNIX socket ones, but we'll improve them as we learn more.
+container local-network [
+  data:&:@:port-connection
+]
+
+# Port connections represent connections to ports on localhost.
+# Before passing a local-network object to network functions
+# `start-reading` and `start-writing`, add port-connections to the
+# local-network.
+#
+# For reading, `transmit-from-socket` will check for a
+# port-connection on the port parameter that's been passed in. If there's
+# no port-connectin for that port, it will return nothing and log. If
+# there is a port-connection for that port, it will transmit the contents
+# to the passed in sink.
+#
+# For writing, `start-writing-socket` returns a sink connecting the
+# caller to the socket on the passed-in port.
+container port-connection [
+  port:num
+  contents:text
+]
+
+def new-port-connection port:num, contents:text -> p:&:port-connection [
+  local-scope
+  load-ingredients
+  p:&:port-connection <- new port-connection:type
+  *p <- put *p, port:offset, port
+  *p <- put *p, contents:offset, contents
+]
+
+def new-fake-network -> n:&:local-network [
+  local-scope
+  load-ingredients
+  n:&:local-network <- new local-network:type
+  local-network-ports:&:@:port-connection <- new port-connection:type, 0
+  *n <- put *n, data:offset, local-network-ports
+]
+
+scenario write-to-fake-socket [
+  local-scope
+  single-port-network:&:local-network <- new-fake-network
+  sink:&:sink:char, writer:num/routine <- start-writing-socket single-port-network, 8080
+  sink <- write sink, 120/x
+  close sink
+  wait-for-routine writer
+  tested-port-connections:&:@:port-connection <- get *single-port-network, data:offset
+  tested-port-connection:port-connection <- index *tested-port-connections, 0
+  contents:text <- get tested-port-connection, contents:offset
+  10:bool/raw <- equal contents, [x]
+  memory-should-contain [
+    10 <- 1
+  ]
+]
+
+def start-writing-socket network:&:local-network, port:num -> sink:&:sink:char, routine-id:num [
+  local-scope
+  load-ingredients
+  source:&:source:char, sink:&:sink:char <- new-channel 30
+  {
+    break-if network
+    socket:num <- $socket 8080/port
+    session:num <- $accept socket
+    # TODO Create channel implementation of write-to-socket.
+    routine-id <- copy 0
+    return
+  }
+  # fake network
+  routine-id <- start-running transmit-to-fake-socket network, port, source
+]
+
+def transmit-to-fake-socket network:&:local-network, port:num, source:&:source:char -> network:&:local-network, source:&:source:char [
+  local-scope
+  load-ingredients
+  # compute new port connection contents
+  buf:&:buffer <- new-buffer 30
+  {
+    c:char, done?:bool, source <- read source
+    break-unless c
+    buf <- append buf, c
+    break-if done?
+    loop
+  }
+  contents:text <- buffer-to-array buf
+  new-port-connection:&:port-connection <- new-port-connection port, contents
+  # Got the contents of the channel, time to write to fake port.
+  i:num <- copy 0
+  port-connections:&:@:port-connection <- get *network, data:offset
+  len:num <- length *port-connections
+  {
+    done?:bool <- greater-or-equal i, len
+    break-if done?
+    current:port-connection <- index *port-connections, i
+    current-port:num <- get current, port:offset
+    ports-match?:bool <- equal current-port, port
+    i <- add i, 1
+    loop-unless ports-match?
+    # Found an existing connection on this port, overwrite.
+    put-index *port-connections, i, *new-port-connection
+    reply
+  }
+  # Couldn't find an existing connection on this port, initialize a new one.
+  new-len:num <- add len, 1
+  new-port-connections:&:@:port-connection <- new port-connection:type, new-len
+  put *network, data:offset, new-port-connections
+  i:num <- copy 0
+  {
+    done?:bool <- greater-or-equal i, len
+    break-if done?
+    tmp:port-connection <- index *port-connections, i
+    put-index *new-port-connections, i, tmp
+  }
+  put-index *new-port-connections, len, *new-port-connection
+]
diff --git a/server-socket.mu b/server-socket.mu
index 3538b687..8a25da92 100644
--- a/server-socket.mu
+++ b/server-socket.mu
@@ -24,13 +24,13 @@ def main [
 Content-type: text/plain
 
 SUCCESS!
-]
+], contents
   $print 10/newline, [Wrote to and closing socket...], 10/newline
   $close-socket session
   $close-socket socket
 ]
 
-def write-to-socket session-socket:number, s:address:array:character [
+def write-to-socket session-socket:number, s:address:array:character, source:&:source:char [
   local-scope
   load-ingredients
   len:number <- length *s