From: Doug Coleman Date: Tue, 28 Sep 2010 00:12:33 +0000 (-0500) Subject: Squashed commit of the following: X-Git-Tag: 0.97~4257^2~67 X-Git-Url: https://gitweb.factorcode.org/gitweb.cgi?p=factor.git;a=commitdiff_plain;h=0bbfa64b2478129a9e3e63bae34ed25f2375555f Squashed commit of the following: commit 54b3e19c7407707fabddd53872559c58cd5143d2 Author: Doug Coleman Date: Mon Sep 27 19:10:15 2010 -0500 Fix typo commit 3207516dc93e0e1edc9f119efcc79f4484eab244 Author: Doug Coleman Date: Mon Sep 27 19:08:30 2010 -0500 Rename io.servers.connection to io.servers --- diff --git a/basis/channels/remote/remote-docs.factor b/basis/channels/remote/remote-docs.factor index 266d774056..2215d959a3 100644 --- a/basis/channels/remote/remote-docs.factor +++ b/basis/channels/remote/remote-docs.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2007 Chris Double. ! See http://factorcode.org/license.txt for BSD license. USING: channels concurrency.distributed help.markup help.syntax -io.servers.connection ; +io.servers ; IN: channels.remote HELP: diff --git a/basis/concurrency/distributed/distributed-tests.factor b/basis/concurrency/distributed/distributed-tests.factor index 3a6693c440..ebe5bc5da2 100644 --- a/basis/concurrency/distributed/distributed-tests.factor +++ b/basis/concurrency/distributed/distributed-tests.factor @@ -1,7 +1,7 @@ USING: tools.test concurrency.distributed kernel io.files io.files.temp io.directories arrays io.sockets system calendar combinators threads math sequences concurrency.messaging -continuations accessors prettyprint io.servers.connection ; +continuations accessors prettyprint io.servers ; FROM: concurrency.messaging => receive send ; IN: concurrency.distributed.tests @@ -36,4 +36,4 @@ test-node-server [ test-node-client "thread-a" send 100 seconds receive-timeout ] unit-test -] with-threaded-server \ No newline at end of file +] with-threaded-server diff --git a/basis/concurrency/distributed/distributed.factor b/basis/concurrency/distributed/distributed.factor index f18f5279ea..153f0c9ad6 100644 --- a/basis/concurrency/distributed/distributed.factor +++ b/basis/concurrency/distributed/distributed.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2005 Chris Double. All Rights Reserved. ! See http://factorcode.org/license.txt for BSD license. USING: serialize sequences concurrency.messaging threads io -io.servers.connection io.encodings.binary assocs init +io.servers io.encodings.binary assocs init arrays namespaces kernel accessors ; FROM: io.sockets => host-name with-client ; IN: concurrency.distributed diff --git a/basis/ftp/server/server-tests.factor b/basis/ftp/server/server-tests.factor index 2954db0f8b..fa6afa30cc 100644 --- a/basis/ftp/server/server-tests.factor +++ b/basis/ftp/server/server-tests.factor @@ -1,6 +1,6 @@ USING: calendar ftp.server io.encodings.ascii io.files io.files.unique namespaces threads tools.test kernel -io.servers.connection ftp.client accessors urls +io.servers ftp.client accessors urls io.pathnames io.directories sequences fry io.backend continuations ; FROM: ftp.client => ftp-get ; diff --git a/basis/ftp/server/server.factor b/basis/ftp/server/server.factor index e6a47c3ffd..c1508f8ad5 100644 --- a/basis/ftp/server/server.factor +++ b/basis/ftp/server/server.factor @@ -5,7 +5,7 @@ combinators.short-circuit concurrency.promises continuations destructors ftp io io.directories io.encodings io.encodings.8-bit.latin1 io.encodings.binary io.encodings.utf8 io.files io.files.info io.files.types io.pathnames -io.servers.connection io.sockets io.streams.string io.timeouts +io.servers io.sockets io.streams.string io.timeouts kernel logging math math.bitwise math.parser namespaces sequences simple-tokenizer splitting strings threads tools.files unicode.case ; diff --git a/basis/furnace/sessions/sessions-tests.factor b/basis/furnace/sessions/sessions-tests.factor index 49311ee891..1ac3dbd51a 100644 --- a/basis/furnace/sessions/sessions-tests.factor +++ b/basis/furnace/sessions/sessions-tests.factor @@ -1,6 +1,6 @@ USING: tools.test http furnace.sessions furnace.actions http.server http.server.responses math namespaces make kernel -accessors io.sockets io.servers.connection prettyprint +accessors io.sockets io.servers prettyprint io.streams.string io.files io.files.temp io.directories splitting destructors sequences db db.tuples db.sqlite continuations urls math.parser furnace furnace.utilities ; diff --git a/basis/http/http-tests.factor b/basis/http/http-tests.factor index 7be7c43399..1a74e3fc6d 100644 --- a/basis/http/http-tests.factor +++ b/basis/http/http-tests.factor @@ -205,7 +205,7 @@ Set-Cookie: oo="bar; a=b"; comment="your mom"; httponly=yes ! Live-fire exercise USING: http.server.static furnace.sessions furnace.alloy furnace.actions furnace.auth furnace.auth.login furnace.db -io.servers.connection io.files io.files.temp io.directories io +io.servers io.files io.files.temp io.directories io threads http.server.responses http.server.redirection furnace.redirection http.server.dispatchers db.tuples ; diff --git a/basis/http/server/remapping/remapping.factor b/basis/http/server/remapping/remapping.factor index 36e769731b..6eed900acc 100644 --- a/basis/http/server/remapping/remapping.factor +++ b/basis/http/server/remapping/remapping.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: namespaces assocs kernel io.servers.connection ; +USING: namespaces assocs kernel io.servers ; IN: http.server.remapping SYMBOL: port-remapping diff --git a/basis/http/server/server-docs.factor b/basis/http/server/server-docs.factor index 7e8d230971..5d1b231f60 100644 --- a/basis/http/server/server-docs.factor +++ b/basis/http/server/server-docs.factor @@ -1,5 +1,5 @@ USING: help.markup help.syntax io.streams.string quotations strings urls -http vocabs.refresh math io.servers.connection assocs ; +http vocabs.refresh math io.servers assocs ; IN: http.server HELP: trivial-responder @@ -109,7 +109,7 @@ ARTICLE: "http.server.variables" "HTTP server variables" } ; ARTICLE: "http.server" "HTTP server" -"The " { $vocab-link "http.server" } " vocabulary implements an HTTP and HTTPS server on top of " { $vocab-link "io.servers.connection" } "." +"The " { $vocab-link "http.server" } " vocabulary implements an HTTP and HTTPS server on top of " { $vocab-link "io.servers" } "." { $subsections "http.server.responders" "http.server.requests" diff --git a/basis/http/server/server.factor b/basis/http/server/server.factor index 9e4a8ac4bf..c5bc88f81f 100644 --- a/basis/http/server/server.factor +++ b/basis/http/server/server.factor @@ -15,7 +15,7 @@ io.encodings.binary io.streams.limited io.streams.string io.streams.throwing -io.servers.connection +io.servers io.timeouts io.crlf fry logging logging.insomniac calendar urls urls.encoding diff --git a/basis/io/servers/authors.txt b/basis/io/servers/authors.txt new file mode 100644 index 0000000000..1901f27a24 --- /dev/null +++ b/basis/io/servers/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/basis/io/servers/connection/authors.txt b/basis/io/servers/connection/authors.txt deleted file mode 100644 index 1901f27a24..0000000000 --- a/basis/io/servers/connection/authors.txt +++ /dev/null @@ -1 +0,0 @@ -Slava Pestov diff --git a/basis/io/servers/connection/connection-docs.factor b/basis/io/servers/connection/connection-docs.factor deleted file mode 100644 index 4dd8efdbe3..0000000000 --- a/basis/io/servers/connection/connection-docs.factor +++ /dev/null @@ -1,136 +0,0 @@ -USING: calendar classes concurrency.semaphores help.markup -help.syntax io io.sockets io.sockets.secure math quotations ; -IN: io.servers.connection - -ARTICLE: "server-config" "Threaded server configuration" -"The " { $link threaded-server } " tuple has a variety of slots which can be set before starting the server with " { $link start-server } "." -{ $subsections - "server-config-logging" - "server-config-listen" - "server-config-limit" - "server-config-stream" - "server-config-handler" -} ; - -ARTICLE: "server-config-logging" "Logging connections" -"The " { $snippet "name" } " slot of a threaded server instance should be set to a string naming the logging service name to use. See " { $link "logging" } " for details." ; - -ARTICLE: "server-config-listen" "Setting ports to listen on" -"The " { $snippet "insecure" } " slot of a threaded server instance contains an integer, an address specifier, or a sequence of address specifiers. Integer port numbers are interpreted as an " { $link inet4 } "/" { $link inet6 } " pair listening on all interfaces for given port number. All other address specifiers are interpeted as per " { $link "network-addressing" } "." -$nl -"The " { $snippet "secure" } " slot of a threaded server instance is interpreted in the same manner as the " { $snippet "insecure" } " slot, except that secure encrypted connections are then allowed. If this slot is set, the " { $snippet "secure-config" } " slot should also be set to a " { $link secure-config } " instance containing SSL server configuration. See " { $link "ssl-config" } " for details." -$nl -"Two utility words for producing address specifiers:" -{ $subsections - local-server - internet-server -} ; - -ARTICLE: "server-config-limit" "Limiting connections" -"The " { $snippet "max-connections" } " slot is initially set to " { $link f } ", which disables connection limiting, but can be set to an integer specifying the maximum number of simultaneous connections." -$nl -"Another method to limit connections is to set the " { $snippet "semaphore" } " slot to a " { $link semaphore } ". The server will hold the semaphore while servicing the client connection." -$nl -"Setting the " { $snippet "max-connections" } " slot is equivalent to storing a semaphore with this initial count in the " { $snippet "semaphore" } " slot. The " { $snippet "semaphore" } " slot is useful for enforcing a maximum connection count shared between multiple threaded servers. See " { $link "concurrency.semaphores" } " for details." ; - -ARTICLE: "server-config-stream" "Client stream parameters" -"The " { $snippet "encoding" } " and " { $snippet "timeout" } " slots of the threaded server can be set to an encoding descriptor or a " { $link duration } ", respectively. See " { $link "io.encodings" } " and " { $link "io.timeouts" } " for details." ; - -ARTICLE: "server-config-handler" "Client handler quotation" -"The " { $snippet "handler" } " slot of a threaded server instance should be set to a quotation which handles client connections. Client handlers are run in their own thread, with the following variables rebound:" -{ $list - { $link input-stream } - { $link output-stream } - { $link local-address } - { $link remote-address } - { $link threaded-server } -} -"An alternate way to implement client handlers is to subclass " { $link threaded-server } ", and define a method on " { $link handle-client* } "." -$nl -"The two methods are equivalent, representing a functional versus an object-oriented approach to the problem." ; - -ARTICLE: "server-examples" "Threaded server examples" -"The " { $vocab-link "time-server" } " vocabulary implements a simple threaded server which sends the current time to the client. The " { $vocab-link "concurrency.distributed" } ", " { $vocab-link "ftp.server" } ", and " { $vocab-link "http.server" } " vocabularies demonstrate more complex usage of the threaded server library." ; - -ARTICLE: "io.servers.connection" "Threaded servers" -"The " { $vocab-link "io.servers.connection" } " vocabulary implements a generic server abstraction for " { $link "network-connection" } ". A set of threads listen for connections, and additional threads are spawned for each client connection. In addition to this basic functionality, it provides some advanced features such as logging, connection limits and secure socket support." -{ $subsections "server-examples" } -"Creating threaded servers with client handler quotations:" -{ $subsections } -"Client handlers can also be implemented by subclassing a threaded server; see " { $link "server-config-handler" } " for details:" -{ $subsections - threaded-server - new-threaded-server - handle-client* -} -"The server must be configured before it can be started." -{ $subsections "server-config" } -"Starting the server:" -{ $subsections start-server } -"Stopping the server:" -{ $subsections stop-server } -"Waiting for the server to stop:" -{ $subsections wait-for-server } -"Combinator for running a server:" -{ $subsections with-threaded-server } -"From within the dynamic scope of a client handler, several words can be used to interact with the threaded server:" -{ $subsections - stop-this-server - secure-port - insecure-port -} -"Additionally, the " { $link local-address } " and " -{ $subsections remote-address } " variables are set, as in " { $link with-client } "." ; - -ABOUT: "io.servers.connection" - -HELP: threaded-server -{ $var-description "In client handlers, stores the current threaded server instance." } -{ $class-description "The class of threaded servers. New instances are created with " { $link } ". This class may be subclassed, and instances of subclasses should be created with " { $link new-threaded-server } ". See " { $link "server-config" } " for slot documentation." } ; - -HELP: new-threaded-server -{ $values { "encoding" "an encoding descriptor" } { "class" class } { "threaded-server" threaded-server } } -{ $description "Creates a new instance of a subclass of " { $link threaded-server } ". Subclasses can implement the " { $link handle-client* } " generic word." } ; - -HELP: -{ $values { "encoding" "an encoding descriptor" } { "threaded-server" threaded-server } } -{ $description "Creates a new threaded server with streams encoded " { $snippet "encoding" } ". Its slots should be filled in as per " { $link "server-config" } ", before " { $link start-server } " is called to begin waiting for connections." } ; - -HELP: remote-address -{ $var-description "Variable holding the address specifier of the current client connection. See " { $link "network-addressing" } "." } ; - -HELP: handle-client* -{ $values { "threaded-server" threaded-server } } -{ $contract "Handles a client connection. Default implementation calls quotation stored in the " { $snippet "handler" } " slot of the threaded server." } ; - -HELP: start-server -{ $values { "threaded-server" threaded-server } } -{ $description "Starts a threaded server and returns after the server is fully running. Throws an error if any of the ports cannot be aquired." } -{ $notes "Use " { $link stop-server } " or " { $link stop-this-server } " to stop the server." } ; - -HELP: stop-server -{ $values { "threaded-server" threaded-server } } -{ $description "Stops a threaded server, preventing it from accepting any more connections. All client connections which have already been opened continue to be serviced." } ; - -HELP: wait-for-server -{ $values { "threaded-server" threaded-server } } -{ $description "Waits for a threaded server to stop serving new connections." } ; - -HELP: stop-this-server -{ $description "Stops the current threaded server, preventing it from accepting any more connections. All client connections which have already been opened continue to be serviced." } ; - -HELP: with-threaded-server -{ $values - { "threaded-server" threaded-server } { "quot" quotation } -} -{ $description "Runs a server and calls a quotation, stopping the server once the quotation returns." } ; - -HELP: secure-port -{ $values { "n/f" { $maybe integer } } } -{ $description "Outputs one of the port numbers on which the current threaded server accepts secure socket connections. Outputs " { $link f } " if the current threaded server does not accept secure socket connections." } -{ $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ; - -HELP: insecure-port -{ $values { "n/f" { $maybe integer } } } -{ $description "Outputs one of the port numbers on which the current threaded server accepts ordinary socket connections. Outputs " { $link f } " if the current threaded server does not accept ordinary socket connections." } -{ $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ; diff --git a/basis/io/servers/connection/connection-tests.factor b/basis/io/servers/connection/connection-tests.factor deleted file mode 100644 index 72f4706957..0000000000 --- a/basis/io/servers/connection/connection-tests.factor +++ /dev/null @@ -1,46 +0,0 @@ -USING: accessors calendar concurrency.promises fry io -io.encodings.ascii io.servers.connection -io.servers.connection.private io.sockets kernel namespaces -sequences threads tools.test ; -IN: io.servers.connection - -[ t ] [ ascii listen-on empty? ] unit-test - -[ f ] [ - ascii - 25 internet-server >>insecure - listen-on - empty? -] unit-test - -[ t ] [ - T{ inet4 f "1.2.3.4" 1234 } T{ inet4 f "1.2.3.5" 1235 } - [ log-connection ] 2keep - [ remote-address get = ] [ local-address get = ] bi* - and -] unit-test - -[ ] [ ascii init-server drop ] unit-test - -[ 10 ] [ - ascii - 10 >>max-connections - init-server semaphore>> count>> -] unit-test - -[ "Hello world." ] [ - ascii - 5 >>max-connections - 0 >>insecure - [ "Hello world." write stop-this-server ] >>handler - [ - "localhost" insecure-port ascii drop stream-contents - ] with-threaded-server -] unit-test - -[ ] [ - ascii - 5 >>max-connections - 0 >>insecure - start-server [ '[ _ wait-for-server ] in-thread ] [ stop-server ] bi -] unit-test diff --git a/basis/io/servers/connection/connection.factor b/basis/io/servers/connection/connection.factor deleted file mode 100644 index 940b20f762..0000000000 --- a/basis/io/servers/connection/connection.factor +++ /dev/null @@ -1,254 +0,0 @@ -! Copyright (C) 2003, 2010 Slava Pestov, Doug Coleman. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays calendar combinators -combinators.short-circuit concurrency.combinators -concurrency.count-downs concurrency.flags -concurrency.semaphores continuations debugger destructors fry -io io.sockets io.sockets.secure io.streams.duplex io.styles -io.timeouts kernel logging make math math.parser namespaces -present prettyprint random sequences sets strings threads ; -FROM: namespaces => set ; -IN: io.servers.connection - -TUPLE: threaded-server < identity-tuple -name -log-level -secure -insecure -secure-config -servers -max-connections -semaphore -timeout -encoding -handler -server-stopped -secure-context ; - -SYMBOL: running-servers -running-servers [ HS{ } clone ] initialize - -ERROR: server-already-running threaded-server ; - -ERROR: server-not-running threaded-server ; - - - -: local-server ( port -- addrspec ) "localhost" swap ; - -: internet-server ( port -- addrspec ) f swap ; - -: new-threaded-server ( encoding class -- threaded-server ) - new - "server" >>name - DEBUG >>log-level - >>secure-config - 1 minutes >>timeout - [ "No handler quotation" throw ] >>handler - swap >>encoding ; - -: ( encoding -- threaded-server ) - threaded-server new-threaded-server ; - -GENERIC: handle-client* ( threaded-server -- ) - -insecure ( obj -- obj ) - -M: inet >insecure 1array ; -M: inet4 >insecure 1array ; -M: inet6 >insecure 1array ; -M: local >insecure 1array ; -M: integer >insecure internet-server 1array ; -M: string >insecure internet-server 1array ; -M: array >insecure [ >insecure ] map ; -M: f >insecure ; - -: >secure ( addrspec -- addrspec' ) - >insecure - [ dup secure? [ ] unless ] map ; - -: listen-on ( threaded-server -- addrspecs ) - [ secure>> >secure ] [ insecure>> >insecure ] bi append - [ resolve-host ] map concat ; - -: accepted-connection ( remote local -- ) - [ - [ "remote: " % present % ", " % ] - [ "local: " % present % ] - bi* - ] "" make - \ accepted-connection NOTICE log-message ; - -: log-connection ( remote local -- ) - [ accepted-connection ] - [ [ remote-address set ] [ local-address set ] bi* ] - 2bi ; - -M: threaded-server handle-client* handler>> call( -- ) ; - -: handle-client ( client remote local -- ) - '[ - _ _ log-connection - threaded-server get - [ timeout>> timeouts ] [ handle-client* ] bi - ] with-stream ; - -\ handle-client NOTICE add-error-logging - -: client-thread-name ( addrspec -- string ) - [ threaded-server get name>> ] dip - unparse-short " connection from " glue ; - -: (accept-connection) ( server -- ) - [ accept ] [ addr>> ] bi - [ '[ _ _ _ handle-client ] ] - [ drop client-thread-name ] 2bi - spawn drop ; - -: accept-connection ( server -- ) - threaded-server get semaphore>> - [ [ (accept-connection) ] with-semaphore ] - [ (accept-connection) ] - if* ; - -: with-existing-secure-context ( threaded-server quot -- ) - [ secure-context>> secure-context ] dip with-variable ; inline - -: accept-loop ( server -- ) - [ accept-connection ] [ accept-loop ] bi ; - -: start-accept-loop ( threaded-server server -- ) - '[ _ accept-loop ] with-existing-secure-context ; - -\ start-accept-loop NOTICE add-error-logging - -: create-secure-context ( threaded-server -- threaded-server ) - dup secure>> [ - dup secure-config>> >>secure-context - ] when ; - -: init-server ( threaded-server -- threaded-server ) - create-secure-context - >>server-stopped - dup semaphore>> [ - dup max-connections>> [ - >>semaphore - ] when* - ] unless ; - -ERROR: no-ports-configured threaded-server ; - -: (make-servers) ( theaded-server addrspecs -- servers ) - swap encoding>> - '[ [ _ |dispose ] map ] with-destructors ; - -: set-servers ( threaded-server -- threaded-server ) - dup [ - dup dup listen-on [ no-ports-configured ] [ (make-servers) ] if-empty - >>servers - ] with-existing-secure-context ; - -: server-thread-name ( threaded-server addrspec -- string ) - [ name>> ] [ addr>> present ] bi* " server on " glue ; - -PRIVATE> - -: start-server ( threaded-server -- threaded-server ) - init-server - [ - dup threaded-server [ - [ ] [ name>> ] bi - [ - set-servers - dup add-running-server - dup servers>> - [ - [ '[ _ _ [ start-accept-loop ] with-disposal ] ] - [ server-thread-name ] 2bi spawn drop - ] with each - ] with-logging - ] with-variable - ] keep ; - -: server-running? ( threaded-server -- ? ) - server-stopped>> [ value>> not ] [ f ] if* ; - -: stop-server ( threaded-server -- ) - dup server-running? [ - [ remove-running-server ] - [ - [ - [ secure-context>> [ &dispose drop ] when* ] - [ [ f ] change-servers drop dispose-each ] bi - ] with-destructors - ] - [ server-stopped>> raise-flag ] tri - ] [ - drop - ] if ; - -: stop-this-server ( -- ) - threaded-server get stop-server ; - -: wait-for-server ( threaded-server -- ) - server-stopped>> wait-for-flag ; - -: with-threaded-server ( threaded-server quot -- ) - [ start-server ] dip over - '[ - [ _ threaded-server _ with-variable ] - [ _ stop-server ] - [ ] cleanup - ] call ; inline - -> ] dip - filter [ f ] [ first addr>> port>> ] if-empty ; inline - -PRIVATE> - -: secure-port ( -- n/f ) [ addr>> secure? ] first-port ; - -: insecure-port ( -- n/f ) [ addr>> secure? not ] first-port ; - -: secure-addr ( -- inet ) - threaded-server get servers>> [ addr>> secure? ] filter random ; - -: insecure-addr ( -- inet ) - threaded-server get servers>> [ addr>> secure? not ] filter random addr>> ; - -: server. ( threaded-server -- ) - [ [ "=== " write name>> ] [ ] bi write-object nl ] - [ servers>> [ addr>> present print ] each ] bi ; - -: all-servers ( -- sequence ) - running-servers get-global members ; - -: get-servers-named ( string -- sequence ) - [ all-servers ] dip '[ name>> _ = ] filter ; - -: servers. ( -- ) - all-servers [ server. ] each ; - -: stop-all-servers ( -- ) - all-servers [ stop-server ] each ; diff --git a/basis/io/servers/connection/summary.txt b/basis/io/servers/connection/summary.txt deleted file mode 100644 index 8269ecfc38..0000000000 --- a/basis/io/servers/connection/summary.txt +++ /dev/null @@ -1 +0,0 @@ -Multi-threaded TCP/IP servers diff --git a/basis/io/servers/connection/tags.txt b/basis/io/servers/connection/tags.txt deleted file mode 100644 index 992ae12982..0000000000 --- a/basis/io/servers/connection/tags.txt +++ /dev/null @@ -1 +0,0 @@ -network diff --git a/basis/io/servers/servers-docs.factor b/basis/io/servers/servers-docs.factor new file mode 100644 index 0000000000..051dfad975 --- /dev/null +++ b/basis/io/servers/servers-docs.factor @@ -0,0 +1,136 @@ +USING: calendar classes concurrency.semaphores help.markup +help.syntax io io.sockets io.sockets.secure math quotations ; +IN: io.servers + +ARTICLE: "server-config" "Threaded server configuration" +"The " { $link threaded-server } " tuple has a variety of slots which can be set before starting the server with " { $link start-server } "." +{ $subsections + "server-config-logging" + "server-config-listen" + "server-config-limit" + "server-config-stream" + "server-config-handler" +} ; + +ARTICLE: "server-config-logging" "Logging connections" +"The " { $snippet "name" } " slot of a threaded server instance should be set to a string naming the logging service name to use. See " { $link "logging" } " for details." ; + +ARTICLE: "server-config-listen" "Setting ports to listen on" +"The " { $snippet "insecure" } " slot of a threaded server instance contains an integer, an address specifier, or a sequence of address specifiers. Integer port numbers are interpreted as an " { $link inet4 } "/" { $link inet6 } " pair listening on all interfaces for given port number. All other address specifiers are interpeted as per " { $link "network-addressing" } "." +$nl +"The " { $snippet "secure" } " slot of a threaded server instance is interpreted in the same manner as the " { $snippet "insecure" } " slot, except that secure encrypted connections are then allowed. If this slot is set, the " { $snippet "secure-config" } " slot should also be set to a " { $link secure-config } " instance containing SSL server configuration. See " { $link "ssl-config" } " for details." +$nl +"Two utility words for producing address specifiers:" +{ $subsections + local-server + internet-server +} ; + +ARTICLE: "server-config-limit" "Limiting connections" +"The " { $snippet "max-connections" } " slot is initially set to " { $link f } ", which disables connection limiting, but can be set to an integer specifying the maximum number of simultaneous connections." +$nl +"Another method to limit connections is to set the " { $snippet "semaphore" } " slot to a " { $link semaphore } ". The server will hold the semaphore while servicing the client connection." +$nl +"Setting the " { $snippet "max-connections" } " slot is equivalent to storing a semaphore with this initial count in the " { $snippet "semaphore" } " slot. The " { $snippet "semaphore" } " slot is useful for enforcing a maximum connection count shared between multiple threaded servers. See " { $link "concurrency.semaphores" } " for details." ; + +ARTICLE: "server-config-stream" "Client stream parameters" +"The " { $snippet "encoding" } " and " { $snippet "timeout" } " slots of the threaded server can be set to an encoding descriptor or a " { $link duration } ", respectively. See " { $link "io.encodings" } " and " { $link "io.timeouts" } " for details." ; + +ARTICLE: "server-config-handler" "Client handler quotation" +"The " { $snippet "handler" } " slot of a threaded server instance should be set to a quotation which handles client connections. Client handlers are run in their own thread, with the following variables rebound:" +{ $list + { $link input-stream } + { $link output-stream } + { $link local-address } + { $link remote-address } + { $link threaded-server } +} +"An alternate way to implement client handlers is to subclass " { $link threaded-server } ", and define a method on " { $link handle-client* } "." +$nl +"The two methods are equivalent, representing a functional versus an object-oriented approach to the problem." ; + +ARTICLE: "server-examples" "Threaded server examples" +"The " { $vocab-link "time-server" } " vocabulary implements a simple threaded server which sends the current time to the client. The " { $vocab-link "concurrency.distributed" } ", " { $vocab-link "ftp.server" } ", and " { $vocab-link "http.server" } " vocabularies demonstrate more complex usage of the threaded server library." ; + +ARTICLE: "io.servers" "Threaded servers" +"The " { $vocab-link "io.servers" } " vocabulary implements a generic server abstraction for " { $link "network-connection" } ". A set of threads listen for connections, and additional threads are spawned for each client connection. In addition to this basic functionality, it provides some advanced features such as logging, connection limits and secure socket support." +{ $subsections "server-examples" } +"Creating threaded servers with client handler quotations:" +{ $subsections } +"Client handlers can also be implemented by subclassing a threaded server; see " { $link "server-config-handler" } " for details:" +{ $subsections + threaded-server + new-threaded-server + handle-client* +} +"The server must be configured before it can be started." +{ $subsections "server-config" } +"Starting the server:" +{ $subsections start-server } +"Stopping the server:" +{ $subsections stop-server } +"Waiting for the server to stop:" +{ $subsections wait-for-server } +"Combinator for running a server:" +{ $subsections with-threaded-server } +"From within the dynamic scope of a client handler, several words can be used to interact with the threaded server:" +{ $subsections + stop-this-server + secure-port + insecure-port +} +"Additionally, the " { $link local-address } " and " +{ $subsections remote-address } " variables are set, as in " { $link with-client } "." ; + +ABOUT: "io.servers" + +HELP: threaded-server +{ $var-description "In client handlers, stores the current threaded server instance." } +{ $class-description "The class of threaded servers. New instances are created with " { $link } ". This class may be subclassed, and instances of subclasses should be created with " { $link new-threaded-server } ". See " { $link "server-config" } " for slot documentation." } ; + +HELP: new-threaded-server +{ $values { "encoding" "an encoding descriptor" } { "class" class } { "threaded-server" threaded-server } } +{ $description "Creates a new instance of a subclass of " { $link threaded-server } ". Subclasses can implement the " { $link handle-client* } " generic word." } ; + +HELP: +{ $values { "encoding" "an encoding descriptor" } { "threaded-server" threaded-server } } +{ $description "Creates a new threaded server with streams encoded " { $snippet "encoding" } ". Its slots should be filled in as per " { $link "server-config" } ", before " { $link start-server } " is called to begin waiting for connections." } ; + +HELP: remote-address +{ $var-description "Variable holding the address specifier of the current client connection. See " { $link "network-addressing" } "." } ; + +HELP: handle-client* +{ $values { "threaded-server" threaded-server } } +{ $contract "Handles a client connection. Default implementation calls quotation stored in the " { $snippet "handler" } " slot of the threaded server." } ; + +HELP: start-server +{ $values { "threaded-server" threaded-server } } +{ $description "Starts a threaded server and returns after the server is fully running. Throws an error if any of the ports cannot be aquired." } +{ $notes "Use " { $link stop-server } " or " { $link stop-this-server } " to stop the server." } ; + +HELP: stop-server +{ $values { "threaded-server" threaded-server } } +{ $description "Stops a threaded server, preventing it from accepting any more connections. All client connections which have already been opened continue to be serviced." } ; + +HELP: wait-for-server +{ $values { "threaded-server" threaded-server } } +{ $description "Waits for a threaded server to stop serving new connections." } ; + +HELP: stop-this-server +{ $description "Stops the current threaded server, preventing it from accepting any more connections. All client connections which have already been opened continue to be serviced." } ; + +HELP: with-threaded-server +{ $values + { "threaded-server" threaded-server } { "quot" quotation } +} +{ $description "Runs a server and calls a quotation, stopping the server once the quotation returns." } ; + +HELP: secure-port +{ $values { "n/f" { $maybe integer } } } +{ $description "Outputs one of the port numbers on which the current threaded server accepts secure socket connections. Outputs " { $link f } " if the current threaded server does not accept secure socket connections." } +{ $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ; + +HELP: insecure-port +{ $values { "n/f" { $maybe integer } } } +{ $description "Outputs one of the port numbers on which the current threaded server accepts ordinary socket connections. Outputs " { $link f } " if the current threaded server does not accept ordinary socket connections." } +{ $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ; diff --git a/basis/io/servers/servers-tests.factor b/basis/io/servers/servers-tests.factor new file mode 100644 index 0000000000..bcba7f7d90 --- /dev/null +++ b/basis/io/servers/servers-tests.factor @@ -0,0 +1,46 @@ +USING: accessors calendar concurrency.promises fry io +io.encodings.ascii io.servers +io.servers.private io.sockets kernel namespaces +sequences threads tools.test ; +IN: io.servers + +[ t ] [ ascii listen-on empty? ] unit-test + +[ f ] [ + ascii + 25 internet-server >>insecure + listen-on + empty? +] unit-test + +[ t ] [ + T{ inet4 f "1.2.3.4" 1234 } T{ inet4 f "1.2.3.5" 1235 } + [ log-connection ] 2keep + [ remote-address get = ] [ local-address get = ] bi* + and +] unit-test + +[ ] [ ascii init-server drop ] unit-test + +[ 10 ] [ + ascii + 10 >>max-connections + init-server semaphore>> count>> +] unit-test + +[ "Hello world." ] [ + ascii + 5 >>max-connections + 0 >>insecure + [ "Hello world." write stop-this-server ] >>handler + [ + "localhost" insecure-port ascii drop stream-contents + ] with-threaded-server +] unit-test + +[ ] [ + ascii + 5 >>max-connections + 0 >>insecure + start-server [ '[ _ wait-for-server ] in-thread ] [ stop-server ] bi +] unit-test diff --git a/basis/io/servers/servers.factor b/basis/io/servers/servers.factor new file mode 100644 index 0000000000..66d0112561 --- /dev/null +++ b/basis/io/servers/servers.factor @@ -0,0 +1,254 @@ +! Copyright (C) 2003, 2010 Slava Pestov, Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors arrays calendar combinators +combinators.short-circuit concurrency.combinators +concurrency.count-downs concurrency.flags +concurrency.semaphores continuations debugger destructors fry +io io.sockets io.sockets.secure io.streams.duplex io.styles +io.timeouts kernel logging make math math.parser namespaces +present prettyprint random sequences sets strings threads ; +FROM: namespaces => set ; +IN: io.servers + +TUPLE: threaded-server < identity-tuple +name +log-level +secure +insecure +secure-config +servers +max-connections +semaphore +timeout +encoding +handler +server-stopped +secure-context ; + +SYMBOL: running-servers +running-servers [ HS{ } clone ] initialize + +ERROR: server-already-running threaded-server ; + +ERROR: server-not-running threaded-server ; + + + +: local-server ( port -- addrspec ) "localhost" swap ; + +: internet-server ( port -- addrspec ) f swap ; + +: new-threaded-server ( encoding class -- threaded-server ) + new + "server" >>name + DEBUG >>log-level + >>secure-config + 1 minutes >>timeout + [ "No handler quotation" throw ] >>handler + swap >>encoding ; + +: ( encoding -- threaded-server ) + threaded-server new-threaded-server ; + +GENERIC: handle-client* ( threaded-server -- ) + +insecure ( obj -- obj ) + +M: inet >insecure 1array ; +M: inet4 >insecure 1array ; +M: inet6 >insecure 1array ; +M: local >insecure 1array ; +M: integer >insecure internet-server 1array ; +M: string >insecure internet-server 1array ; +M: array >insecure [ >insecure ] map ; +M: f >insecure ; + +: >secure ( addrspec -- addrspec' ) + >insecure + [ dup secure? [ ] unless ] map ; + +: listen-on ( threaded-server -- addrspecs ) + [ secure>> >secure ] [ insecure>> >insecure ] bi append + [ resolve-host ] map concat ; + +: accepted-connection ( remote local -- ) + [ + [ "remote: " % present % ", " % ] + [ "local: " % present % ] + bi* + ] "" make + \ accepted-connection NOTICE log-message ; + +: log-connection ( remote local -- ) + [ accepted-connection ] + [ [ remote-address set ] [ local-address set ] bi* ] + 2bi ; + +M: threaded-server handle-client* handler>> call( -- ) ; + +: handle-client ( client remote local -- ) + '[ + _ _ log-connection + threaded-server get + [ timeout>> timeouts ] [ handle-client* ] bi + ] with-stream ; + +\ handle-client NOTICE add-error-logging + +: client-thread-name ( addrspec -- string ) + [ threaded-server get name>> ] dip + unparse-short " connection from " glue ; + +: (accept-connection) ( server -- ) + [ accept ] [ addr>> ] bi + [ '[ _ _ _ handle-client ] ] + [ drop client-thread-name ] 2bi + spawn drop ; + +: accept-connection ( server -- ) + threaded-server get semaphore>> + [ [ (accept-connection) ] with-semaphore ] + [ (accept-connection) ] + if* ; + +: with-existing-secure-context ( threaded-server quot -- ) + [ secure-context>> secure-context ] dip with-variable ; inline + +: accept-loop ( server -- ) + [ accept-connection ] [ accept-loop ] bi ; + +: start-accept-loop ( threaded-server server -- ) + '[ _ accept-loop ] with-existing-secure-context ; + +\ start-accept-loop NOTICE add-error-logging + +: create-secure-context ( threaded-server -- threaded-server ) + dup secure>> [ + dup secure-config>> >>secure-context + ] when ; + +: init-server ( threaded-server -- threaded-server ) + create-secure-context + >>server-stopped + dup semaphore>> [ + dup max-connections>> [ + >>semaphore + ] when* + ] unless ; + +ERROR: no-ports-configured threaded-server ; + +: (make-servers) ( theaded-server addrspecs -- servers ) + swap encoding>> + '[ [ _ |dispose ] map ] with-destructors ; + +: set-servers ( threaded-server -- threaded-server ) + dup [ + dup dup listen-on [ no-ports-configured ] [ (make-servers) ] if-empty + >>servers + ] with-existing-secure-context ; + +: server-thread-name ( threaded-server addrspec -- string ) + [ name>> ] [ addr>> present ] bi* " server on " glue ; + +PRIVATE> + +: start-server ( threaded-server -- threaded-server ) + init-server + [ + dup threaded-server [ + [ ] [ name>> ] bi + [ + set-servers + dup add-running-server + dup servers>> + [ + [ '[ _ _ [ start-accept-loop ] with-disposal ] ] + [ server-thread-name ] 2bi spawn drop + ] with each + ] with-logging + ] with-variable + ] keep ; + +: server-running? ( threaded-server -- ? ) + server-stopped>> [ value>> not ] [ f ] if* ; + +: stop-server ( threaded-server -- ) + dup server-running? [ + [ remove-running-server ] + [ + [ + [ secure-context>> [ &dispose drop ] when* ] + [ [ f ] change-servers drop dispose-each ] bi + ] with-destructors + ] + [ server-stopped>> raise-flag ] tri + ] [ + drop + ] if ; + +: stop-this-server ( -- ) + threaded-server get stop-server ; + +: wait-for-server ( threaded-server -- ) + server-stopped>> wait-for-flag ; + +: with-threaded-server ( threaded-server quot -- ) + [ start-server ] dip over + '[ + [ _ threaded-server _ with-variable ] + [ _ stop-server ] + [ ] cleanup + ] call ; inline + +> ] dip + filter [ f ] [ first addr>> port>> ] if-empty ; inline + +PRIVATE> + +: secure-port ( -- n/f ) [ addr>> secure? ] first-port ; + +: insecure-port ( -- n/f ) [ addr>> secure? not ] first-port ; + +: secure-addr ( -- inet ) + threaded-server get servers>> [ addr>> secure? ] filter random ; + +: insecure-addr ( -- inet ) + threaded-server get servers>> [ addr>> secure? not ] filter random addr>> ; + +: server. ( threaded-server -- ) + [ [ "=== " write name>> ] [ ] bi write-object nl ] + [ servers>> [ addr>> present print ] each ] bi ; + +: all-servers ( -- sequence ) + running-servers get-global members ; + +: get-servers-named ( string -- sequence ) + [ all-servers ] dip '[ name>> _ = ] filter ; + +: servers. ( -- ) + all-servers [ server. ] each ; + +: stop-all-servers ( -- ) + all-servers [ stop-server ] each ; diff --git a/basis/io/servers/summary.txt b/basis/io/servers/summary.txt new file mode 100644 index 0000000000..8269ecfc38 --- /dev/null +++ b/basis/io/servers/summary.txt @@ -0,0 +1 @@ +Multi-threaded TCP/IP servers diff --git a/basis/io/servers/tags.txt b/basis/io/servers/tags.txt new file mode 100644 index 0000000000..992ae12982 --- /dev/null +++ b/basis/io/servers/tags.txt @@ -0,0 +1 @@ +network diff --git a/basis/io/sockets/sockets-docs.factor b/basis/io/sockets/sockets-docs.factor index d0977dd3d0..95ad57a46d 100644 --- a/basis/io/sockets/sockets-docs.factor +++ b/basis/io/sockets/sockets-docs.factor @@ -52,7 +52,7 @@ $nl { { $link inet4 } " - a TCP/IP connection to an IPv4 address and port number; no name lookup is performed" } { { $link inet6 } " - a TCP/IP connection to an IPv6 address and port number; no name lookup is performed" } } -"The " { $vocab-link "io.servers.connection" } " library defines high-level wrappers around " { $link } " which makes it easy to listen for IPv4, IPv6 and secure socket connections simultaneously, perform logging, and optionally only allow connections from the loopback interface." +"The " { $vocab-link "io.servers" } " library defines high-level wrappers around " { $link } " which makes it easy to listen for IPv4, IPv6 and secure socket connections simultaneously, perform logging, and optionally only allow connections from the loopback interface." $nl "The " { $vocab-link "io.sockets.secure" } " vocabulary implements secure, encrypted sockets via SSL and TLS." ; @@ -170,7 +170,7 @@ HELP: { $code "f 1234 resolve-host" } "To start a server which listens for connections from the loopback interface only, use an address specifier returned by the following code, where 1234 is the desired port number:" { $code "\"localhost\" 1234 resolve-host" } - "Since " { $link resolve-host } " can return multiple address specifiers, your server code must listen on them all to work properly. The " { $vocab-link "io.servers.connection" } " vocabulary can be used to help with this." + "Since " { $link resolve-host } " can return multiple address specifiers, your server code must listen on them all to work properly. The " { $vocab-link "io.servers" } " vocabulary can be used to help with this." $nl "To start a TCP/IP server which listens for connections on a randomly-assigned port, set the port number in the address specifier to 0, and then read the " { $snippet "addr" } " slot of the server instance to obtain the actual port number it is listening on:" { $unchecked-example diff --git a/basis/mime/multipart/multipart-tests.factor b/basis/mime/multipart/multipart-tests.factor index 6c3094fe22..bfeb1335ee 100644 --- a/basis/mime/multipart/multipart-tests.factor +++ b/basis/mime/multipart/multipart-tests.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs continuations fry http.server io io.encodings.ascii io.files io.files.unique -io.servers.connection io.streams.duplex io.streams.string +io.servers io.streams.duplex io.streams.string kernel math.ranges mime.multipart multiline namespaces random sequences strings threads tools.test ; IN: mime.multipart.tests diff --git a/basis/tools/deploy/deploy-tests.factor b/basis/tools/deploy/deploy-tests.factor index fa446ad44c..e8888717ab 100644 --- a/basis/tools/deploy/deploy-tests.factor +++ b/basis/tools/deploy/deploy-tests.factor @@ -52,7 +52,7 @@ os macosx? [ ] each USING: http.client http.server http.server.dispatchers -http.server.responses http.server.static io.servers.connection ; +http.server.responses http.server.static io.servers ; SINGLETON: quit-responder diff --git a/extra/fuel/remote/remote.factor b/extra/fuel/remote/remote.factor index a8007bd858..e7b797fc19 100644 --- a/extra/fuel/remote/remote.factor +++ b/extra/fuel/remote/remote.factor @@ -1,8 +1,7 @@ ! Copyright (C) 2009, 2010 Jose Antonio Ortega Ruiz. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors debugger io io.encodings.utf8 io.servers.connection +USING: accessors debugger io io.encodings.utf8 io.servers kernel listener math namespaces ; - IN: fuel.remote ( port -- ) diff --git a/extra/webapps/site-watcher/site-watcher.factor b/extra/webapps/site-watcher/site-watcher.factor index 05fabfcf9d..a354544399 100644 --- a/extra/webapps/site-watcher/site-watcher.factor +++ b/extra/webapps/site-watcher/site-watcher.factor @@ -8,7 +8,7 @@ furnace.auth.features.registration furnace.auth.login furnace.boilerplate furnace.redirection html.forms http.server http.server.dispatchers kernel namespaces site-watcher site-watcher.db site-watcher.private urls validators io.sockets.secure.unix.debug -io.servers.connection io.files.temp db db.tuples sequences +io.servers io.files.temp db db.tuples sequences webapps.site-watcher.common webapps.site-watcher.watching webapps.site-watcher.spidering ; QUALIFIED: assocs diff --git a/extra/webapps/todo/todo.factor b/extra/webapps/todo/todo.factor index e5753f3c53..01ed2402f7 100644 --- a/extra/webapps/todo/todo.factor +++ b/extra/webapps/todo/todo.factor @@ -122,7 +122,7 @@ furnace.auth.features.edit-profile furnace.auth.features.deactivate-user db.sqlite furnace.alloy -io.servers.connection +io.servers io.sockets.secure ; : ( responder -- responder' ) diff --git a/extra/websites/concatenative/concatenative.factor b/extra/websites/concatenative/concatenative.factor index 35e4150ba9..61b4f7d887 100644 --- a/extra/websites/concatenative/concatenative.factor +++ b/extra/websites/concatenative/concatenative.factor @@ -1,7 +1,7 @@ ! Copyright (c) 2008, 2010 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: accessors kernel sequences assocs io.files io.pathnames -io.sockets io.sockets.secure io.servers.connection +io.sockets io.sockets.secure io.servers namespaces db db.tuples db.sqlite smtp urls logging.insomniac html.templates.chloe