-
Notifications
You must be signed in to change notification settings - Fork 0
/
forever-http-loop.c
135 lines (114 loc) · 3.69 KB
/
forever-http-loop.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <arpa/inet.h> /* inet_ntoa */
#include <signal.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define LISTENQ 1024 /* second argument to listen() */
#define PORTNUM 80
/* Simplifies calls to bind(), connect(), and accept() */
typedef struct sockaddr SA;
int open_listenfd(int port){
int listenfd, optval=1;
struct sockaddr_in serveraddr;
/* Create a socket descriptor */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
/* Eliminates "Address already in use" error from bind. */
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int)) < 0)
return -1;
// 6 is TCP's protocol number
// enable this, much faster : 4000 req/s -> 17000 req/s
if (setsockopt(listenfd, 6, TCP_CORK,
(const void *)&optval , sizeof(int)) < 0)
return -1;
/* Listenfd will be an endpoint for all requests to port
on any IP address for this host */
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
return -1;
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, LISTENQ) < 0)
return -1;
return listenfd;
}
void process(int fd, struct sockaddr_in *clientaddr){
char *res = "HTTP/1.1 200 OK\r\nContent-Length: 6\r\nConnection: close\r\n\r\nBye.\r\n";
char buf[256];
char ts[22];
time_t t;
struct tm *tmp;
/* create a timestamp */
t = time(NULL);
tmp = localtime(&t);
strftime(ts, sizeof(ts)-1, "%FT%TZ", tmp);
printf("%s accept request, fd is %d, pid is %d, ip is %s\n", \
ts, fd, getpid(), inet_ntoa(clientaddr->sin_addr));
recv(fd, buf, sizeof(buf), 0);
send(fd, res, strlen(res), 0);
}
int main(int argc, char** argv){
struct sockaddr_in clientaddr;
int default_port = PORTNUM,
listenfd,
connfd;
socklen_t clientlen = sizeof clientaddr;
const char* s = getenv("PORT");
if (s != NULL) {
default_port = atoi(s);
}
setbuf(stdout, NULL); // do not buffer stdout
/* handle signals being PID 1 */
signal(SIGHUP, exit);
signal(SIGINT, exit);
signal(SIGQUIT, exit);
signal(SIGTRAP, exit);
signal(SIGABRT, exit);
signal(SIGKILL, exit);
signal(SIGUSR1, exit);
signal(SIGUSR2, exit);
signal(SIGTERM, exit);
signal(SIGSTOP, exit);
// Ignore SIGPIPE signal, so if browser cancels the request, it
// won't kill the whole process.
signal(SIGPIPE, SIG_IGN);
listenfd = open_listenfd(default_port);
if (listenfd > 0) {
printf("listen on port %d, fd is %d.\n", default_port, listenfd);
} else {
perror("ERROR");
exit(listenfd);
}
for(int i = 0; i < 10; i++) {
int pid = fork();
if (pid == 0) { // child
while(1){
connfd = accept(listenfd, (SA *)&clientaddr, &clientlen);
process(connfd, &clientaddr);
close(connfd);
}
} else if (pid > 0) { // parent
printf("child pid is %d.\n", pid);
} else {
perror("fork");
}
}
while(1){
connfd = accept(listenfd, (SA *)&clientaddr, &clientlen);
process(connfd, &clientaddr);
close(connfd);
}
return 0;
}