Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 156 lines (127 sloc) 5.033 kb
93c3abf @davidreynolds Added license info
authored
1 ;;
2 ;; rooster - epoll server
3 ;;
4 ;; http://github.com/davidreynolds/rooster
5 ;;
6 ;; Copyright 2010 David Reynolds
7 ;; All rights reserved.
8 ;;
9 ;; Use and distribution licensed under BSD license. See
10 ;; LICENSE for full text of BSD license.
11 ;;
12
a9b53ea @davidreynolds Modified README to show how to require Rooster.
authored
13 (declare
14 (uses rooster-utils tcp srfi-13 srfi-69)
27180bd @davidreynolds Preparing Rooster for becoming a web server
authored
15 (export run-rooster fd-list send-to-client send-to-all remove-client))
c1a5a97 @davidreynolds modified the server.scm to be a module and updated the examples... I'…
authored
16
a9b53ea @davidreynolds Modified README to show how to require Rooster.
authored
17 (use epoll)
6d954c4 @davidreynolds initial commit
authored
18
ae942b8 @davidreynolds renamed ev-main-loop to run-rooster (for now). also exported more fun…
authored
19 ;; _server_fd and epfd are both initialized in run-rooster
42beaa5 @davidreynolds removed global listener and replaced it with a local listener that se…
authored
20 (define _server_fd)
87c2cdc @davidreynolds made it so rooster compiles into a shared library
authored
21 (define epfd)
ae942b8 @davidreynolds renamed ev-main-loop to run-rooster (for now). also exported more fun…
authored
22 (define fd-list '())
23
043362c @davidreynolds added source dir and build dir and makefile
authored
24 (define (filter-out-fd fd)
25 ;; builds a new list after filtering out fd
26 (let loop ((li fd-list) (newlist '()))
27 (if (null? li)
28 newlist
29 (if (eq? fd (car li))
30 (loop (cdr li) newlist)
31 (loop (cdr li) (append newlist (list (car li))))))))
32
33 (define (remove-client fd)
34 (set! fd-list (filter-out-fd fd))
a9b53ea @davidreynolds Modified README to show how to require Rooster.
authored
35 (remove-client-buffers! fd)
8802cf8 @davidreynolds removed all epoll stuff in favor of using the new epoll egg
authored
36 (epoll-delete epfd fd)
5bd181b @davidreynolds renamed ##net#whatever to net-whatever
authored
37 (net-close fd))
043362c @davidreynolds added source dir and build dir and makefile
authored
38
a9b53ea @davidreynolds Modified README to show how to require Rooster.
authored
39 ;; this is set to the request handler passed through run-rooster
40 (define _RequestHandler)
41
6d954c4 @davidreynolds initial commit
authored
42 (define (send-to-client fd str)
43 ;; this function doesn't actually _send_ to the client. it appends
44 ;; `str` to the client's write buffer until it's time to really
45 ;; write on the socket (epoll tells us when to write)
a9b53ea @davidreynolds Modified README to show how to require Rooster.
authored
46 (let ((buf (fd-write-buffer fd)))
47 (set-fd-write-buffer! fd (string-append buf str)))
3759ab0 @davidreynolds clients can now talk to eachother through a super simple chat system
authored
48
8802cf8 @davidreynolds removed all epoll stuff in favor of using the new epoll egg
authored
49 (epoll-modify epfd fd _WRITE))
6d954c4 @davidreynolds initial commit
authored
50
5312022 @davidreynolds modified the read loop to be tighter
authored
51 (define (send-to-all buf sender-fd)
52 (let fdloop ((fds fd-list))
53 (unless (null? fds)
54 (let ((d (car fds)))
55 (if (eq? sender-fd d)
56 (send-to-client d buf)
db5b707 @davidreynolds Better handling of socket reads.
authored
57 (send-to-client d (string-append "\r\n" buf))))
5312022 @davidreynolds modified the read loop to be tighter
authored
58 (fdloop (cdr fds)))))
59
6d954c4 @davidreynolds initial commit
authored
60 (define (accept-fd sfd)
5bd181b @davidreynolds renamed ##net#whatever to net-whatever
authored
61 (let ((fd (net-accept sfd #f #f)))
6d954c4 @davidreynolds initial commit
authored
62 (setnonblock fd)
63 (init-client fd)
043362c @davidreynolds added source dir and build dir and makefile
authored
64 (set! fd-list (cons fd fd-list))
b01099f @davidreynolds Read from client on initial connection.
authored
65 (epoll-add epfd fd _READ)
078d4de @davidreynolds Added chat example and modified some of the APIs in server.scm. Also …
authored
66
b01099f @davidreynolds Read from client on initial connection.
authored
67 ;; For reading the request sent from client (headers, body, etc).
68 (read-handler fd)))
6d954c4 @davidreynolds initial commit
authored
69
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
70 (define (write-handler fd)
71 ;; epoll tells us to write to socket
a9b53ea @davidreynolds Modified README to show how to require Rooster.
authored
72 (let ((buf (fd-write-buffer fd)))
5bd181b @davidreynolds renamed ##net#whatever to net-whatever
authored
73 (net-write fd buf (string-length buf)))
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
74
75 ;; clear out write buffer
a9b53ea @davidreynolds Modified README to show how to require Rooster.
authored
76 (set-fd-write-buffer! fd "")
db5b707 @davidreynolds Better handling of socket reads.
authored
77 (set-fd-read-buffer! fd "")
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
78
27180bd @davidreynolds Preparing Rooster for becoming a web server
authored
79 ;; TODO: only remove-client if connection: close
80 (remove-client fd))
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
81
db5b707 @davidreynolds Better handling of socket reads.
authored
82 (define (read-from-socket fd)
83 ;; read in 4kb blocks
84 (let* ((rbuf (make-string 4096))
7976e5f @davidreynolds Fixed a paren alignment
authored
85 (res (net-read fd rbuf 4096)))
db5b707 @davidreynolds Better handling of socket reads.
authored
86 (if (= res 0)
87 (remove-client fd)
88 (substring rbuf 0 res))))
d20423a @davidreynolds broke out the read loop from read-handler
authored
89
d0585a9 @davidreynolds Adding basic HTTP header processing
authored
90 (define (_on_headers fd data)
91 ;; parse headers contained in buf
92 (let* ((eol (string-contains data "\r\n"))
93 (start-line (string-split (substring data 0 eol) " "))
94 (method (car start-line))
95 (uri (cadr start-line))
96 (version (caddr start-line)))
97
98 (if (not (string-prefix? "HTTP/" version))
99 (remove-client fd)
100
e3f3339 @davidreynolds amended comment
authored
101 ;; TODO: Next step would be to parse content-length and read N bytes
d0585a9 @davidreynolds Adding basic HTTP header processing
authored
102 ;; Then pass request to _RequestHandler instead of a string.
103 ;; That let's _RequestHandler do controller dispatching.
104 (_RequestHandler fd ""))))
105
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
106 (define (read-handler fd)
107 ;; epoll tells us to read from socket
db5b707 @davidreynolds Better handling of socket reads.
authored
108 (let ((len 104857600)
7976e5f @davidreynolds Fixed a paren alignment
authored
109 (rcur (string-length (fd-read-buffer fd)))
110 (buf (read-from-socket fd)))
db5b707 @davidreynolds Better handling of socket reads.
authored
111
27180bd @davidreynolds Preparing Rooster for becoming a web server
authored
112 (unless (eq? buf 0)
113 (if (< (+ rcur (string-length buf)) len)
114 (set-fd-read-buffer! fd (string-append (fd-read-buffer fd) buf)))
db5b707 @davidreynolds Better handling of socket reads.
authored
115
d0585a9 @davidreynolds Adding basic HTTP header processing
authored
116 ;; eoh = end of headers
117 (let* ((fdbuf (fd-read-buffer fd))
118 (eoh (string-contains fdbuf "\r\n\r\n"))
119 (headers (substring fdbuf 0 eoh)))
120 (_on_headers fd headers)))))
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
121
8802cf8 @davidreynolds removed all epoll stuff in favor of using the new epoll egg
authored
122 ;; this function is passed to epoll-wait as a callback
6d954c4 @davidreynolds initial commit
authored
123 (define (fd-event-list-handler ls)
124 ;; takes a list of (fd . events) pairs
42beaa5 @davidreynolds removed global listener and replaced it with a local listener that se…
authored
125 (unless (null? ls)
6d954c4 @davidreynolds initial commit
authored
126 (let* ((pair (car ls))
127 (fd (car pair)))
42beaa5 @davidreynolds removed global listener and replaced it with a local listener that se…
authored
128 (if (eq? fd _server_fd)
129 (accept-fd _server_fd)
6d954c4 @davidreynolds initial commit
authored
130 (cond ((= (bitwise-and (cdr pair) _WRITE) _WRITE)
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
131 (write-handler fd))
6d954c4 @davidreynolds initial commit
authored
132
133 ((= (bitwise-and (cdr pair) _READ) _READ)
f103cf5 @davidreynolds broke up the read and write ops to separate functions (read-handler a…
authored
134 (read-handler fd))))
6d954c4 @davidreynolds initial commit
authored
135
136 ;; loop over rest of (fd . events) list of pairs
137 (fd-event-list-handler (cdr ls)))))
138
87c2cdc @davidreynolds made it so rooster compiles into a shared library
authored
139 ;; pass server stuff here (like port number) and a request handler
140 ;; so the server can pass requests to the programmer-defined handler
ae942b8 @davidreynolds renamed ev-main-loop to run-rooster (for now). also exported more fun…
authored
141 (define (run-rooster request-handler)
42beaa5 @davidreynolds removed global listener and replaced it with a local listener that se…
authored
142 (let* ((listener (tcp-listen 6666))
143 (sfd (tcp-listener-fileno listener)))
87c2cdc @davidreynolds made it so rooster compiles into a shared library
authored
144
145 ;; set global server fd
42beaa5 @davidreynolds removed global listener and replaced it with a local listener that se…
authored
146 (set! _server_fd sfd)
8802cf8 @davidreynolds removed all epoll stuff in favor of using the new epoll egg
authored
147 (set! epfd (epoll-create))
ae942b8 @davidreynolds renamed ev-main-loop to run-rooster (for now). also exported more fun…
authored
148 (set! _RequestHandler request-handler)
87c2cdc @davidreynolds made it so rooster compiles into a shared library
authored
149
8802cf8 @davidreynolds removed all epoll stuff in favor of using the new epoll egg
authored
150 (epoll-add epfd sfd _READ)
87c2cdc @davidreynolds made it so rooster compiles into a shared library
authored
151
6d954c4 @davidreynolds initial commit
authored
152 (let loop ()
8802cf8 @davidreynolds removed all epoll stuff in favor of using the new epoll egg
authored
153 ;; pass epoll callback to epoll-wait
154 (epoll-wait epfd 200 fd-event-list-handler)
6d954c4 @davidreynolds initial commit
authored
155 (loop))))
Something went wrong with that request. Please try again.