Understanding the Network Connections in LambdaMOO(source: LambdaMOO Programmers Manual Online documentation about LambdaMOO)Accepting and Initiating Network ConnectionsWhen the server first accepts a new, incoming network connection, it is given the low-level network address of computer on the other end. It immediately attempts to convert this address into the human-readable host name that will be entered in the server log and returned by the connection_name() function. This conversion can, for the TCP/IP networking configurations, involve a certain amount of communication with remote name servers, which can take quite a long time and/or fail entirely. While the server is doing this conversion, it is not doing anything else at all; in particular, it it not responding to user commands or executing MOO tasks. By default, the server will wait no more than 5 seconds for such a name lookup to succeed; after that, it behaves as if the conversion had failed, using instead a printable representation of the low-level address. If the property name_lookup_timeout exists on $server_options and has an integer as its value, that integer is used instead as the timeout interval. When the open_network_connection() function is used, the server must again do a conversion, this time from the host name given as an argument into the low-level address necessary for actually opening the connection. This conversion is subject to the same timeout as in the in-bound case; if the conversion does not succeed before the timeout expires, the connection attempt is aborted and open_network_connection() raises E_QUOTA. After a successful conversion, though, the server must still wait for the actual connection to be accepted by the remote computer. As before, this can take a long time during which the server is again doing nothing else. Also as before, the server will by default wait no more than 5 seconds for the connection attempt to succeed; if the timeout expires, open_network_connection() again raises E_QUOTA. This default timeout interval can also be overridden from within the database, by defining the property outbound_connect_timeout on $server_options with an integer as its value. Associating Network Connections with PlayersWhen a network connection is first made to the MOO, it is identified by a unique, negative object number. Such a connection is said to be un-logged-in and is not yet associated with any MOO player object. Each line of input on an un-logged-in connection is first parsed into words in the usual way (see the chapter on command parsing for details) and then these words are passed as the arguments in a call to the verb $do_login_command(). For example, the input line connect Munchkin frebblebit would result in the following call being made: $do_login_command("connect", "Munchkin", "frebblebit") In that call, the variable player will have as its value the negative object number associated with the appropriate network connection. The functions notify() and boot_player() can be used with such object numbers to send output to and disconnect un-logged-in connections. Also, the variable argstr will have as its value the unparsed command line as received on the network connection. If $do_login_command() returns a valid player object and the connection is still open, then the connection is considered to have logged into that player. The server then makes one of the following verbs calls, depending on the player object that was returned:
$user_created(player) ;listeners() => {{#650, 7778, 0}, {#0, 7777, 1}} => #0 (The System Object) => #650 (HTTP Service) #0:do_login_command this none this 1: "...This code should only be run as a server task..."; 2: if (callers()) 3: return E_PERM; 4: endif 5: if (typeof(h = $network:incoming_connection(player)) == OBJ) 6: "connected to an object"; 7: return h; 8: elseif (h) 9: return 0; 10: endif 11: host = $string_utils:connection_hostname(connection_name(player)); 12: if ($login:redlisted(host)) 13: boot_player(player); 14: server_log(tostr("REDLISTED: ", player, " from ", host)); 15: return 0; 16: endif 17: "...checks to see if the login is spamming the server with too many commands..."; 18: if (!$login:maybe_limit_commands()) 19: args = $login:parse_command(@args); 20: return $login:(args[1])(@listdelete(args, 1)); 21: endif #650:do_login_command this none this 1: if (length(args) > 1) 2: try 3: if (args[1] == "get" || args[2] == "post") 4: this:(args[1])(@listdelete(args, 1)); 5: endif 6: except v (ANY) 7: endtry 8: "A hack to delay for output to reach the client."; 9: suspend(2); 10: boot_player(player); 11: return -1; 12: else 13: return -1; 14: endif The first of these is used if the returned object number is greater than the value returned by the max_object() function before $do_login_command() was invoked, that is, it is called if the returned object appears to have been freshly created. If this is not the case, then one of the other two verb calls is used. The $user_connected() call is used if there was no existing active connection for the returned player object. Otherwise, the $user_reconnected() call is used instead. If an in-bound network connection does not successfully log in within a certain period of time, the server will automatically shut down the connection, thereby freeing up the resources associated with maintaining it. When any network connection (even an un-logged-in or outbound one) is terminated, by either the server or the client, then one of the following two verb calls is made:
$user_disconnected(player) The first is used if the disconnection is due to actions taken by the server (e.g., a use of the boot_player() function or the un- logged-in timeout described above) and the second if the disconnection was initiated by the client side. It is not an error if any of these five verbs do not exist; the corresponding call is simply skipped. When the network connection is first established, the null command is automatically entered by the server, resulting in an initial call to $do_login_command() with no arguments. This signal can be used by the verb to print out a welcome message, for example.
#650:get this none this 1: {path, ?version = "HTTP/1.0", @excess} = args; 2: if (length(args) > 1 && args[2] == "HTTP/1.0") 3: revision = "1.0"; 4: else 5: revision = "0.9"; 6: endif 7: if (subs = match(path, "^/+/")) 8: path[1..subs[2] - 1] = ""; 9: endif 10: headers = {}; 11: Authorizations = {}; 12: referer = 0; 13: if (revision == "1.0") 14: while (line = read(player)) 15: if (index(line, "Authorization:")) 16: parts = $string_utils:explode(line, " "); 17: if (parts[2] == "Basic") 18: Authorizations = {@Authorizations, this.httpd:base_64_decode(parts[3])}; 19: endif 20: else 21: headers = {@headers, line}; 22: endif 23: endwhile 24: endif [...deleted debugging lines...] 55: "httpd actully handles the processing and we send it back to the client."; 56: ctype = ""; 57: try 58: {ctype, output} = this.httpd:get(path, headers, Authorizations); 59: notify(player, "HTTP/1.0 200 OK"); 60: except v (ANY) 61: notify(player, "HTTP/1.0 500 Oops"); 62: output = {"<html><title><head>Server Error</head></title><body>A server error has occurred.</body></html>"}; 63: ctype = "text/html"; 64: endtry 65: notify(player, tostr("Server: Strange/0.1 LambaMOO/", server_version())); 66: notify(player, "Content-Type: " + tostr(ctype)); 67: notify(player, "Last-modified: " + ctime()); 68: content_length = 0; 69: for line in (output) 70: content_length = content_length + length(line) + 2; 71: $command_utils:suspend_if_needed(1); 72: endfor 73: notify(player, "Date: " + ctime()); 74: notify(player, "Content-length: " + tostr(content_length)); 75: "appearantly no one expects Content-length: anymore"; 76: notify(player, ""); 77: counter = 1; 78: while (counter <= length(output)) 79: notify(player, output[counter]); 80: $command_utils:suspend_if_needed(1); 81: counter = counter + 1; 82: endwhile 83: endif 84: return; ;#650.httpd => #648 (Page Server) @list #648:get #648:get this none this 1: "HTTPD:get(path)"; 2: {path, ?headers = {}, ?Authorizations = {}} = args; 3: contents = this:find_page(path, headers, Authorizations); 4: if (ticks_left() < 600) 5: suspend(1); 6: endif 7: return contents; @list #648:find_page #648:find_page this none this 1: "HTTPD:find_page returns {} if nothing is found, or else returns the"; 2: "set of lines for the requested 'page'. Since I'm writing this, and"; 3: "the whole concept of path is meaningless since this is all potentially"; 4: "dynamic html, I'm not bothering with file extensions."; 5: {path, ?headers = {}, ?Authorizations = {}} = args; 6: page = {}; 7: path = strsub(path, "%20", " "); 8: chunks = $string_utils:explode(path, "/"); 9: if (length(chunks) > 0) 10: {Location, @rest} = chunks; 11: OtherLoc = Location + "/"; 12: for Thing in (this.contents) 13: if (Thing.name == Location || Thing.name == OtherLoc) 14: return Thing:get_content(rest, headers, Authorizations); 15: endif 16: endfor 17: return this.unknown_page:get_content(path, headers, Authorizations); 18: else 19: return this.root:get_content({"/"}, headers, Authorizations); 20: endif ;$string_utils:nn(#648.contents) => "Root (#397), objects/ (#1484), rooms/ (#1485), and map/ (#1486)" @list #397:get_content #397:get_content none none none 1: {path, headers, authorization} = args; 2: {?next = "/", @rest} = path; 3: if (next == "/" && length(rest) == 0) 4: DoSelf = 1; 5: else 6: DoSelf = 0; 7: endif 8: if (DoSelf == 0) 9: other_next = next + "/"; 10: for Thing in (this.contents) 11: if (next == Thing.name || other_next == Thing.name) 12: return Thing:get_content(rest, headers, authorization); 13: endif 14: endfor 15: endif 16: Content = {"<html>"}; 17: Content = {@Content, "<title>Blackwood WWW Interface</title>"}; 18: Content = {@Content, "<body bgcolor=ffffff><font size=+2>"}; 19: Content = {@Content, "<h1>Blackwood WWW Interface</h1>"}; 20: Content = {@Content, "Welcome to the Blackwood MOO server WWW Interface."}; 21: Content = {@Content, "<p>You are welcome to look around our town."}; 22: Content = {@Content, "<br>Start by looking at the "}; 23: Content = {@Content, "<a href=\"" + "rooms/" + tostr(tonum($player_start)) + "\">Town Square</a>"}; 24: Content = {@Content, "</font>"}; 25: Content = {@Content, "<p><img align=top src=\"http://www.cs.ndsu.nodak.edu/~slator/gifs/trans-under_co.gif\">"}; 26: Content = {@Content, "This page is under construction."}; 27: Content = {@Content, "<br>Comments?: email slator@cs.ndsu.edu"}; 28: return {"text/html", Content}; oit:Retailer~[90]> telnet lions.cs.ndsu.nodak.edu 7778 Trying 134.129.125.71... Connected to lions.cs.ndsu.nodak.edu. Escape character is '^]'. => get / HTTP/1.0 200 OK Server: Strange/0.1 LambaMOO/1.8.0r5 Content-Type: text/html Last-modified: Mon Apr 19 21:03:15 1999 CDT Date: Mon Apr 19 21:03:15 1999 CDT Content-length: 461
This page is under construction.
|