diff options
author | Stephen Malina <stephenmalina@gmail.com> | 2016-09-21 05:27:56 -0700 |
---|---|---|
committer | Stephen Malina <stephenmalina@gmail.com> | 2016-09-21 05:29:02 -0700 |
commit | 25cd8e9878b7b7325271773d4e4ec91b7462d0e6 (patch) | |
tree | 7c7a6952233abb3740171fd1803993535b73bc9d | |
parent | 6845c4d94a823f4de186b0cd1298f530ab6f7460 (diff) | |
download | mu-25cd8e9878b7b7325271773d4e4ec91b7462d0e6.tar.gz |
3403
Wrap $read-from-socket in a channel and fix the socket example so that browser's display the response properly.
-rw-r--r-- | 091socket.cc | 47 | ||||
-rw-r--r-- | server-socket.mu | 54 |
2 files changed, 64 insertions, 37 deletions
diff --git a/091socket.cc b/091socket.cc index 3ffca8f4..5caf9f79 100644 --- a/091socket.cc +++ b/091socket.cc @@ -16,7 +16,7 @@ struct socket_t { :(code) void server_socket(int portno, socket_t* server) { server->fd = socket(AF_INET, SOCK_STREAM, 0); - int dummy; + int dummy = 0; setsockopt(server->fd, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy)); server->addr.sin_family = AF_INET; server->addr.sin_addr.s_addr = INADDR_ANY; @@ -115,24 +115,20 @@ _READ_FROM_SOCKET, put(Recipe_ordinal, "$read-from-socket", _READ_FROM_SOCKET); :(before "End Primitive Recipe Checks") case _READ_FROM_SOCKET: { - if (SIZE(inst.ingredients) != 1) { - raise << maybe(get(Recipe, r).name) << "'$read-from-socket' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); + if (SIZE(inst.ingredients) != 2) { + raise << maybe(get(Recipe, r).name) << "'$read-from-socket' requires exactly two ingredients, but got '" << inst.original_string << "'\n" << end(); break; } if (!is_mu_number(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "first 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 one product, but got '" << inst.original_string << "'\n" << end(); + if (!is_mu_number(inst.ingredients.at(1))) { + 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 (!is_mu_character(inst.products.at(0))) { - raise << maybe(get(Recipe, r).name) << "first product of '$read-from-socket' should be a 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 but got '" << to_string(inst.products.at(1)) << "'\n" << end(); + if (SIZE(inst.products) != 2) { + raise << maybe(get(Recipe, r).name) << "'$read-from-socket' requires exactly two product, but got '" << inst.original_string << "'\n" << end(); break; } break; @@ -140,20 +136,16 @@ case _READ_FROM_SOCKET: { :(before "End Primitive Recipe Implementations") case _READ_FROM_SOCKET: { long long int x = static_cast<long long int>(ingredients.at(0).at(0)); + int bytes = static_cast<int>(ingredients.at(1).at(0)); //? Should this be something with more bytes? socket_t* socket = reinterpret_cast<socket_t*>(x); int socket_fd = socket->fd; - char single_char[2]; - bzero(single_char, 2); - int bytes_read = read(socket_fd, single_char, 1); + char contents[bytes]; + bzero(contents, bytes); + int bytes_read = read(socket_fd, contents, bytes - 1 /* null-terminated */); + //?: cerr << "Read:\n" << string(contents) << "\n"; products.resize(2); - if (single_char[0]== EOF || bytes_read == 0) { - products.at(1).push_back(1); // eof - } - else { - products.at(1).push_back(0); - } - products.at(0).push_back(single_char[0]); - break; + products.at(0).push_back(new_mu_text(string(contents))); + products.at(1).push_back(bytes_read); break; } @@ -190,11 +182,11 @@ _CLOSE_SOCKET, put(Recipe_ordinal, "$close-socket", _CLOSE_SOCKET); :(before "End Primitive Recipe Checks") case _CLOSE_SOCKET: { - if (SIZE(inst.ingredients) != 2) { + if (SIZE(inst.ingredients) != 1) { raise << maybe(get(Recipe, r).name) << "'$close-socket' requires exactly two ingredient, but got '" << inst.original_string << "'\n" << end(); break; } - if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(0))) { + if (!is_mu_number(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "first ingredient of '$close-socket' should be a character, but got '" << to_string(inst.ingredients.at(0)) << "t\n" << end(); break; } @@ -202,9 +194,8 @@ case _CLOSE_SOCKET: { } :(before "End Primitive Recipe Implementations") case _CLOSE_SOCKET: { - double socket_fd = ingredients.at(0).at(0); - double session_fd = ingredients.at(1).at(0); - close(socket_fd); - close(session_fd); + long long int x = static_cast<long long int>(ingredients.at(0).at(0)); + socket_t* socket = reinterpret_cast<socket_t*>(x); + close(socket->fd); break; } diff --git a/server-socket.mu b/server-socket.mu index dbdf1ef7..3da870ca 100644 --- a/server-socket.mu +++ b/server-socket.mu @@ -1,19 +1,33 @@ +# Example of reading from a socket using channels and writing back to it +# directly. Running this file and navigating to <address of server>:8081 +# should result in your browser displaying "SUCCESS!". +# +# Unfortunately, the reading implementation has some redundant, inelegant +# code to make up for my lack of insight into Linux's socket internal. def main [ local-scope - socket:num <- $socket 8080/port + socket:num <- $socket 8081/port $print [Mu socket creation returned ], socket, 10/newline session:num <- $accept socket - write-to-socket session, [HTTP/1.0 200 OK - -OK] + contents:&:source:char, sink:&:sink:char <- new-channel 5096 + sink <- start-running transmit-from-socket session, sink + buf:&:buffer <- new-buffer 30 { - c:char, eof?:boolean <- $read-from-socket session - $print c - break-if eof? + c:char, done?:bool, contents <- read contents + break-if done? + buf <- append buf, c loop } - $print 10/newline, [Hit end of socket, closing...], 10/newline - $close-socket socket, session + socket-text:text <- buffer-to-array buf + $print [Done reading from socket.], 10/newline + write-to-socket session, [HTTP/1.0 200 OK +Content-type: text/plain + +SUCCESS! +] + $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 [ @@ -25,8 +39,30 @@ def write-to-socket session-socket:number, s:address:array:character [ done?:boolean <- greater-or-equal i, len break-if done? c:character <- index *s, i + $print [writing to socket: ], i, [ ], c, 10/newline $write-to-socket session-socket, c i <- add i, 1 loop } ] + +def transmit-from-socket session:num, sink:&:sink:char -> sink:&:sink:char [ + local-scope + load-ingredients + { + req:text, bytes-read:number <- $read-from-socket session, 4096/bytes + $print [read ], bytes-read, [ bytes from socket], 10/newline + i:number <- copy 0 + { + done?:boolean <- greater-or-equal i, bytes-read + break-if done? + c:char <- index *req, i + end-of-request?:bool <- equal c, 10/newline + break-if end-of-request? # To be safe, for now. + sink <- write sink, c + i <- add i, 1 + loop + } + } + sink <- close sink +] |