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 }