1 ! Copyright (C) 2003, 2010 Slava Pestov, Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays calendar combinators
4 combinators.short-circuit concurrency.combinators
5 concurrency.count-downs concurrency.flags
6 concurrency.semaphores continuations debugger destructors fry
7 io io.sockets io.sockets.secure io.streams.duplex io.styles
8 io.timeouts kernel logging make math math.parser namespaces
9 present prettyprint random sequences sets strings threads ;
12 TUPLE: threaded-server < identity-tuple
27 SYMBOL: running-servers
28 running-servers [ HS{ } clone ] initialize
30 ERROR: server-not-running threaded-server ;
32 ERROR: server-already-running threaded-server ;
36 : must-be-running ( threaded-server -- threaded-server )
37 dup running-servers get in? [ server-not-running ] unless ;
39 : must-not-be-running ( threaded-server -- threaded-server )
40 dup running-servers get in? [ server-already-running ] when ;
42 : add-running-server ( threaded-server -- )
44 running-servers get adjoin ;
46 : remove-running-server ( threaded-server -- )
48 running-servers get delete ;
52 : local-server ( port -- addrspec ) "localhost" swap <inet> ;
54 : internet-server ( port -- addrspec ) f swap <inet> ;
56 : new-threaded-server ( encoding class -- threaded-server )
60 <secure-config> >>secure-config
62 [ "No handler quotation" throw ] >>handler
65 : <threaded-server> ( encoding -- threaded-server )
66 threaded-server new-threaded-server ;
68 GENERIC: handle-client* ( threaded-server -- )
72 GENERIC: >insecure ( obj -- obj )
74 M: inet >insecure 1array ;
75 M: inet4 >insecure 1array ;
76 M: inet6 >insecure 1array ;
77 M: local >insecure 1array ;
78 M: integer >insecure internet-server 1array ;
79 M: string >insecure internet-server 1array ;
80 M: array >insecure [ >insecure ] map ;
83 : >secure ( addrspec -- addrspec' )
84 >insecure [ dup secure? [ f <secure> ] unless ] map ;
86 : configurable-addrspecs ( addrspecs -- addrspecs' )
87 [ inet6? not ipv6-supported? or ] filter ;
89 : listen-on ( threaded-server -- addrspecs )
90 [ secure>> ssl-supported? [ >secure ] [ drop { } ] if ]
91 [ insecure>> >insecure ] bi append
92 [ resolve-host ] map concat configurable-addrspecs ;
94 : accepted-connection ( remote local -- )
96 [ "remote: " % present % ", " % ]
97 [ "local: " % present % ]
100 \ accepted-connection NOTICE log-message ;
102 : log-connection ( remote local -- )
103 [ accepted-connection ]
104 [ [ remote-address set ] [ local-address set ] bi* ]
107 M: threaded-server handle-client* handler>> call( -- ) ;
109 : handle-client ( client remote local -- )
113 [ timeout>> timeouts ] [ handle-client* ] bi
116 \ handle-client NOTICE add-error-logging
118 : client-thread-name ( addrspec -- string )
119 [ threaded-server get name>> ] dip
120 unparse-short " connection from " glue ;
122 : (accept-connection) ( server -- )
123 [ accept ] [ addr>> ] bi
124 [ '[ _ _ _ handle-client ] ]
125 [ drop client-thread-name ] 2bi
128 : accept-connection ( server -- )
129 threaded-server get semaphore>>
130 [ [ (accept-connection) ] with-semaphore ]
131 [ (accept-connection) ]
134 : with-existing-secure-context ( threaded-server quot -- )
135 [ secure-context>> secure-context ] dip with-variable ; inline
137 : accept-loop ( server -- )
138 [ accept-connection ] [ accept-loop ] bi ;
140 : start-accept-loop ( threaded-server server -- )
141 '[ _ accept-loop ] with-existing-secure-context ;
143 \ start-accept-loop NOTICE add-error-logging
145 : create-secure-context ( threaded-server -- threaded-server )
146 dup secure>> ssl-supported? and [
147 dup secure-config>> <secure-context> >>secure-context
150 : init-server ( threaded-server -- threaded-server )
151 create-secure-context
152 <flag> >>server-stopped
154 dup max-connections>> [
155 <semaphore> >>semaphore
159 ERROR: no-ports-configured threaded-server ;
161 : (make-servers) ( theaded-server addrspecs -- servers )
163 '[ [ _ <server> |dispose ] map ] with-destructors ;
165 : set-servers ( threaded-server -- threaded-server )
168 [ no-ports-configured ] [ (make-servers) ] if-empty
170 ] with-existing-secure-context ;
172 : server-thread-name ( threaded-server addrspec -- string )
173 [ name>> ] [ addr>> present ] bi* " server on " glue ;
177 : start-server ( threaded-server -- threaded-server )
180 dup threaded-server [
184 dup add-running-server
187 [ '[ _ _ [ start-accept-loop ] with-disposal ] ]
188 [ server-thread-name ] 2bi spawn drop
194 : server-running? ( threaded-server -- ? )
195 server-stopped>> [ value>> not ] [ f ] if* ;
197 : stop-server ( threaded-server -- )
198 dup server-running? [
199 [ remove-running-server ]
202 [ secure-context>> [ &dispose drop ] when* ]
203 [ [ f ] change-servers drop dispose-each ] bi
206 [ server-stopped>> raise-flag ] tri
211 : stop-this-server ( -- )
212 threaded-server get stop-server ;
214 : wait-for-server ( threaded-server -- )
215 server-stopped>> wait-for-flag ;
217 : with-threaded-server ( threaded-server quot -- )
218 [ start-server ] dip over
220 [ _ threaded-server _ with-variable ]
227 GENERIC: connect-addr ( addrspec -- addrspec )
229 M: inet4 connect-addr [ "127.0.0.1" ] dip port>> <inet4> ;
231 M: inet6 connect-addr [ "::1" ] dip port>> <inet6> ;
233 M: secure connect-addr addrspec>> connect-addr f <secure> ;
235 M: local connect-addr ;
239 : server-addrs ( -- addrspecs )
240 threaded-server get servers>> [ addr>> connect-addr ] map ;
242 : secure-addr ( -- addrspec )
243 server-addrs [ secure? ] filter random ;
245 : insecure-addr ( -- addrspec )
246 server-addrs [ secure? ] reject random ;
248 : server. ( threaded-server -- )
249 [ [ "=== " write name>> ] [ ] bi write-object nl ]
250 [ servers>> [ addr>> present print ] each ] bi ;
252 : all-servers ( -- sequence )
253 running-servers get-global members ;
255 : get-servers-named ( string -- sequence )
256 [ all-servers ] dip '[ name>> _ = ] filter ;
259 all-servers [ server. ] each ;
261 : stop-all-servers ( -- )
262 all-servers [ stop-server ] each ;