Mercurial > urweb
comparison src/c/driver.c @ 138:d6d78055f001
Change driver to use Pthreads
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Sat, 19 Jul 2008 18:56:57 -0400 |
parents | 133fa2d51bb4 |
children | adfa2c7a75da |
comparison
equal
deleted
inserted
replaced
137:4ffdbf429e8d | 138:d6d78055f001 |
---|---|
3 #include <string.h> | 3 #include <string.h> |
4 #include <sys/types.h> | 4 #include <sys/types.h> |
5 #include <sys/socket.h> | 5 #include <sys/socket.h> |
6 #include <netinet/in.h> | 6 #include <netinet/in.h> |
7 | 7 |
8 #include <pthread.h> | |
9 | |
8 #include "lacweb.h" | 10 #include "lacweb.h" |
9 | 11 |
10 int lw_port = 8080; | 12 int lw_port = 8080; |
11 int lw_backlog = 10; | 13 int lw_backlog = 10; |
12 int lw_bufsize = 1024; | 14 int lw_bufsize = 1024; |
13 | 15 |
14 void lw_handle(lw_context, char*); | 16 void lw_handle(lw_context, char*); |
15 | 17 |
16 static void worker(int sock) { | 18 typedef struct node { |
17 char buf[lw_bufsize+1], *back = buf, *s; | 19 int fd; |
20 struct node *next; | |
21 } *node; | |
22 | |
23 static node front = NULL, back = NULL; | |
24 | |
25 static int empty() { | |
26 return front == NULL; | |
27 } | |
28 | |
29 static void enqueue(int fd) { | |
30 node n = malloc(sizeof(struct node)); | |
31 | |
32 n->fd = fd; | |
33 n->next = NULL; | |
34 if (back) | |
35 back->next = n; | |
36 else | |
37 front = n; | |
38 back = n; | |
39 } | |
40 | |
41 static int dequeue() { | |
42 int ret = front->fd; | |
43 | |
44 front = front->next; | |
45 if (!front) | |
46 back = NULL; | |
47 | |
48 return ret; | |
49 } | |
50 | |
51 static pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; | |
52 static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; | |
53 | |
54 static void *worker(void *data) { | |
55 int me = *(int *)data; | |
56 lw_context ctx = lw_init(1024, 1024); | |
18 | 57 |
19 while (1) { | 58 while (1) { |
20 int r = recv(sock, back, lw_bufsize - (back - buf), 0); | 59 char buf[lw_bufsize+1], *back = buf, *s; |
21 | 60 int sock; |
22 if (r < 0) { | 61 |
23 fprintf(stderr, "Recv failed\n"); | 62 pthread_mutex_lock(&queue_mutex); |
24 close(sock); | 63 while (empty()) |
25 return; | 64 pthread_cond_wait(&queue_cond, &queue_mutex); |
65 sock = dequeue(); | |
66 pthread_mutex_unlock(&queue_mutex); | |
67 | |
68 printf("Handling connection with thread #%d.\n", me); | |
69 | |
70 while (1) { | |
71 int r = recv(sock, back, lw_bufsize - (back - buf), 0); | |
72 | |
73 if (r < 0) { | |
74 fprintf(stderr, "Recv failed\n"); | |
75 break; | |
76 } | |
77 | |
78 if (r == 0) { | |
79 printf("Connection closed.\n"); | |
80 break; | |
81 } | |
82 | |
83 printf("Received %d bytes.\n", r); | |
84 | |
85 back += r; | |
86 *back = 0; | |
87 | |
88 if (s = strstr(buf, "\r\n\r\n")) { | |
89 char *cmd, *path; | |
90 | |
91 *s = 0; | |
92 | |
93 if (!(s = strstr(buf, "\r\n"))) { | |
94 fprintf(stderr, "No newline in buf\n"); | |
95 break; | |
96 } | |
97 | |
98 *s = 0; | |
99 cmd = s = buf; | |
100 | |
101 if (!strsep(&s, " ")) { | |
102 fprintf(stderr, "No first space in HTTP command\n"); | |
103 break; | |
104 } | |
105 | |
106 if (strcmp(cmd, "GET")) { | |
107 fprintf(stderr, "Not ready for non-get command: %s\n", cmd); | |
108 break; | |
109 } | |
110 | |
111 path = s; | |
112 if (!strsep(&s, " ")) { | |
113 fprintf(stderr, "No second space in HTTP command\n"); | |
114 break; | |
115 } | |
116 | |
117 printf("Serving URI %s....\n", path); | |
118 | |
119 ctx = lw_init(1024, 1024); | |
120 lw_write (ctx, "HTTP/1.1 200 OK\r\n"); | |
121 lw_write(ctx, "Content-type: text/html\r\n\r\n"); | |
122 lw_write(ctx, "<html>"); | |
123 lw_handle(ctx, path); | |
124 lw_write(ctx, "</html>"); | |
125 | |
126 lw_send(ctx, sock); | |
127 | |
128 printf("Done with client.\n\n"); | |
129 break; | |
130 } | |
26 } | 131 } |
27 | 132 |
28 if (r == 0) { | 133 close(sock); |
29 printf("Connection closed.\n"); | 134 lw_reset(ctx); |
30 close(sock); | 135 } |
31 return; | 136 } |
32 } | 137 |
33 | 138 int main(int argc, char *argv[]) { |
34 printf("Received %d bytes.\n", r); | |
35 | |
36 back += r; | |
37 *back = 0; | |
38 | |
39 if (s = strstr(buf, "\r\n\r\n")) { | |
40 char *cmd, *path; | |
41 lw_context ctx; | |
42 | |
43 *s = 0; | |
44 | |
45 if (!(s = strstr(buf, "\r\n"))) { | |
46 fprintf(stderr, "No newline in buf\n"); | |
47 close(sock); | |
48 return; | |
49 } | |
50 | |
51 *s = 0; | |
52 cmd = s = buf; | |
53 | |
54 if (!strsep(&s, " ")) { | |
55 fprintf(stderr, "No first space in HTTP command\n"); | |
56 close(sock); | |
57 return; | |
58 } | |
59 | |
60 if (strcmp(cmd, "GET")) { | |
61 fprintf(stderr, "Not ready for non-get command: %s\n", cmd); | |
62 close(sock); | |
63 return; | |
64 } | |
65 | |
66 path = s; | |
67 if (!strsep(&s, " ")) { | |
68 fprintf(stderr, "No second space in HTTP command\n"); | |
69 close(sock); | |
70 return; | |
71 } | |
72 | |
73 printf("Serving URI %s....\n", path); | |
74 | |
75 ctx = lw_init(1024, 1024); | |
76 lw_write (ctx, "HTTP/1.1 200 OK\r\n"); | |
77 lw_write(ctx, "Content-type: text/html\r\n\r\n"); | |
78 lw_write(ctx, "<html>"); | |
79 lw_handle(ctx, path); | |
80 lw_write(ctx, "</html>"); | |
81 | |
82 lw_send(ctx, sock); | |
83 | |
84 lw_free(ctx); | |
85 printf("Done with client.\n\n"); | |
86 close(sock); | |
87 return; | |
88 } | |
89 } | |
90 } | |
91 | |
92 int main() { | |
93 // The skeleton for this function comes from Beej's sockets tutorial. | 139 // The skeleton for this function comes from Beej's sockets tutorial. |
94 int sockfd, new_fd; // listen on sock_fd, new connection on new_fd | 140 int sockfd; // listen on sock_fd |
95 struct sockaddr_in my_addr; | 141 struct sockaddr_in my_addr; |
96 struct sockaddr_in their_addr; // connector's address information | 142 struct sockaddr_in their_addr; // connector's address information |
97 int sin_size, yes = 1; | 143 int sin_size, yes = 1; |
144 int nthreads, i, *names; | |
145 | |
146 if (argc < 2) { | |
147 fprintf(stderr, "No thread count specified\n"); | |
148 return 1; | |
149 } | |
150 | |
151 nthreads = atoi(argv[1]); | |
152 if (nthreads <= 0) { | |
153 fprintf(stderr, "Invalid thread count\n"); | |
154 return 1; | |
155 } | |
156 names = calloc(nthreads, sizeof(int)); | |
98 | 157 |
99 sockfd = socket(PF_INET, SOCK_STREAM, 0); // do some error checking! | 158 sockfd = socket(PF_INET, SOCK_STREAM, 0); // do some error checking! |
100 | 159 |
101 if (sockfd < 0) { | 160 if (sockfd < 0) { |
102 fprintf(stderr, "Listener socket creation failed\n"); | 161 fprintf(stderr, "Listener socket creation failed\n"); |
125 | 184 |
126 sin_size = sizeof their_addr; | 185 sin_size = sizeof their_addr; |
127 | 186 |
128 printf("Listening on port %d....\n", lw_port); | 187 printf("Listening on port %d....\n", lw_port); |
129 | 188 |
189 for (i = 0; i < nthreads; ++i) { | |
190 pthread_t thread; | |
191 names[i] = i; | |
192 if (pthread_create(&thread, NULL, worker, &names[i])) { | |
193 fprintf(stderr, "Error creating worker thread #%d\n", i); | |
194 return 1; | |
195 } | |
196 } | |
197 | |
130 while (1) { | 198 while (1) { |
131 new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); | 199 int new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); |
132 | 200 |
133 if (new_fd < 0) { | 201 if (new_fd < 0) { |
134 fprintf(stderr, "Socket accept failed\n"); | 202 fprintf(stderr, "Socket accept failed\n"); |
135 return 1; | 203 return 1; |
136 } | 204 } |
137 | 205 |
138 printf("Accepted connection.\n"); | 206 printf("Accepted connection.\n"); |
139 worker(new_fd); | 207 |
140 } | 208 pthread_mutex_lock(&queue_mutex); |
141 } | 209 enqueue(new_fd); |
210 pthread_mutex_unlock(&queue_mutex); | |
211 pthread_cond_broadcast(&queue_cond); | |
212 } | |
213 } |