server.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #include <time.h>
  2. #include <stdio.h>
  3. #include <signal.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <pthread.h>
  8. #include <arpa/inet.h>
  9. #include <sys/socket.h>
  10. #include "sockio.h"
  11. const uint16_t SERVER_PORT = 1092;
  12. const uint16_t MAX_CLIENT_NUM = 20;
  13. const char WWW_PATH[] = "../www";
  14. const char USERNAME[] = "3190101092";
  15. const char PASSWORD[] = "1092";
  16. int serv_sock; // server socket
  17. int clnt_socks[MAX_CLIENT_NUM]; // client sockets
  18. struct sockaddr_in clnt_addrs[MAX_CLIENT_NUM]; // client addresses
  19. // test string prefix
  20. int strprefix(const char *s, const char *prefix)
  21. {
  22. for (; *s && *prefix; s++, prefix++)
  23. {
  24. if (*s != *prefix)
  25. {
  26. return 0;
  27. }
  28. }
  29. if (*prefix)
  30. {
  31. return 0;
  32. }
  33. return 1;
  34. }
  35. // test string suffix
  36. int strsuffix(const char *s, const char *suffix)
  37. {
  38. int s_len = strlen(s), suffix_len = strlen(suffix);
  39. if (s_len < suffix_len)
  40. {
  41. return 0;
  42. }
  43. for (s += s_len - suffix_len; *suffix; s++, suffix++)
  44. {
  45. if (*s != *suffix)
  46. {
  47. return 0;
  48. }
  49. }
  50. return 1;
  51. }
  52. // test object key-value pair
  53. int strmatch(const char *s, const char *key, const char *value)
  54. {
  55. int key_len = strlen(key);
  56. const char *p = strstr(s, key);
  57. if (p == NULL || p[key_len] != '=')
  58. {
  59. return 0;
  60. }
  61. for (p += key_len + 1; *p && *p != '&' && *value; p++, value++)
  62. {
  63. if (*p != *value)
  64. {
  65. return 0;
  66. }
  67. }
  68. if (*p && *p != '&' || *value)
  69. {
  70. return 0;
  71. }
  72. return 1;
  73. }
  74. // get content type from filename
  75. const char *getcontenttype(const char *s)
  76. {
  77. if (strsuffix(s, ".html"))
  78. {
  79. return "text/html";
  80. }
  81. else if (strsuffix(s, ".jpg"))
  82. {
  83. return "image/jpeg";
  84. }
  85. return "text/plain";
  86. }
  87. // send http header
  88. void send_header(int clnt_sock, struct buffer *send_buf, struct buffer *line_buf,
  89. const char *protocol, const char *status, const char *content_type, size_t content_length)
  90. {
  91. line_buf->len = sprintf(line_buf->buf, "%s %s\r\n"
  92. "Content-Type: %s; charset=utf-8\r\n"
  93. "Content-Length: %lu\r\n"
  94. "\r\n",
  95. protocol, status, content_type, content_length);
  96. sputline(clnt_sock, send_buf, line_buf);
  97. printf("\tresponse: protocol = %s, status = %s, content type = %s, content length = %lu.\n", protocol, status, content_type, content_length);
  98. }
  99. // handle connection
  100. void *conn(void *id)
  101. {
  102. uint16_t clnt_id = *(uint16_t *)id;
  103. int clnt_sock = clnt_socks[clnt_id];
  104. struct buffer recv_buf, send_buf, line_buf, body_buf;
  105. memset(&recv_buf, 0, sizeof(recv_buf));
  106. memset(&send_buf, 0, sizeof(send_buf));
  107. memset(&line_buf, 0, sizeof(line_buf));
  108. memset(&body_buf, 0, sizeof(body_buf));
  109. char method[32], url[1024], protocol[32];
  110. for (;;)
  111. {
  112. // request line
  113. int n = sgetline(clnt_sock, &recv_buf, &line_buf);
  114. if (n < 0)
  115. {
  116. break;
  117. }
  118. {
  119. char *s = line_buf.buf, *p = method;
  120. for (; *s != ' '; s++, p++)
  121. {
  122. *p = *s;
  123. }
  124. *p = '\0';
  125. s++, p = url;
  126. for (; *s != ' '; s++, p++)
  127. {
  128. *p = *s;
  129. }
  130. *p = '\0';
  131. s++, p = protocol;
  132. for (; *s != '\r'; s++, p++)
  133. {
  134. *p = *s;
  135. }
  136. *p = '\0';
  137. }
  138. // request headers
  139. size_t content_length = 0;
  140. for (;;)
  141. {
  142. n = sgetline(clnt_sock, &recv_buf, &line_buf);
  143. if (n <= 2)
  144. {
  145. break;
  146. }
  147. if (strprefix(line_buf.buf, "Content-Length: "))
  148. {
  149. for (char *s = line_buf.buf + strlen("Content-Length: "); *s != '\r'; s++)
  150. {
  151. content_length = content_length * 10 + *s - '0';
  152. }
  153. }
  154. }
  155. if (n < 0)
  156. {
  157. break;
  158. }
  159. printf("Client %hu request: method = %s, url = %s, protocol = %s, content length = %lu.\n", clnt_id, method, url, protocol, content_length);
  160. // request body
  161. char *request_body = (char *)malloc(content_length + 1);
  162. for (char *s = request_body; s < request_body + content_length; s++)
  163. {
  164. *s = sgetc(clnt_sock, &recv_buf);
  165. }
  166. request_body[content_length] = '\0';
  167. if (strcmp(method, "GET") == 0)
  168. {
  169. FILE *fp = fopen(url + 1, "rb");
  170. if (fp == NULL)
  171. {
  172. body_buf.len = sprintf(body_buf.buf, "The requested file %s was not found on this server", url);
  173. send_header(clnt_sock, &send_buf, &line_buf, protocol, "404 Not Found", "text/plain", body_buf.len);
  174. sputline(clnt_sock, &send_buf, &body_buf);
  175. }
  176. else
  177. {
  178. fseek(fp, 0, SEEK_END);
  179. send_header(clnt_sock, &send_buf, &line_buf, protocol, "200 OK", getcontenttype(url), ftell(fp));
  180. fseek(fp, 0, SEEK_SET);
  181. for (;;)
  182. {
  183. body_buf.len = fread(body_buf.buf, 1, BUF_SIZE, fp);
  184. if (body_buf.len == 0)
  185. {
  186. break;
  187. }
  188. sputline(clnt_sock, &send_buf, &body_buf);
  189. }
  190. }
  191. }
  192. else if (strcmp(method, "POST") == 0)
  193. {
  194. if (strcmp(url, "/dopost") == 0)
  195. {
  196. int login = strmatch(request_body, "login", USERNAME) && strmatch(request_body, "pass", PASSWORD);
  197. body_buf.len = sprintf(body_buf.buf, "<html><body>%s</body></html>", login ? "登录成功" : "登录失败");
  198. send_header(clnt_sock, &send_buf, &line_buf, protocol, "200 OK", "text/html", body_buf.len);
  199. sputline(clnt_sock, &send_buf, &body_buf);
  200. }
  201. else
  202. {
  203. body_buf.len = sprintf(body_buf.buf, "The requested URL %s was not found on this server", url);
  204. send_header(clnt_sock, &send_buf, &line_buf, protocol, "404 Not Found", "text/plain", body_buf.len);
  205. sputline(clnt_sock, &send_buf, &body_buf);
  206. }
  207. }
  208. free(request_body);
  209. sflush(clnt_sock, &send_buf);
  210. if (strcmp(method, "POST") == 0)
  211. {
  212. break;
  213. }
  214. }
  215. close(clnt_sock);
  216. printf("Client %hu disconnected.\n", clnt_id);
  217. clnt_socks[clnt_id] = -1;
  218. return NULL;
  219. }
  220. // close sockets before exit
  221. void stop_server(int sig)
  222. {
  223. for (uint16_t i = 0; i < MAX_CLIENT_NUM; i++)
  224. {
  225. if (clnt_socks[i] != -1)
  226. {
  227. close(clnt_socks[i]);
  228. printf("Client %hu disconnected.\n", i);
  229. clnt_socks[i] = -1;
  230. }
  231. }
  232. close(serv_sock);
  233. puts("Stop listening.");
  234. exit(0);
  235. }
  236. int main()
  237. {
  238. chdir(WWW_PATH);
  239. memset(clnt_socks, -1, sizeof(clnt_socks));
  240. // create server socket
  241. serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  242. if (serv_sock == -1)
  243. {
  244. puts("Create socket failed.");
  245. exit(1);
  246. }
  247. // bind address to server socket
  248. struct sockaddr_in serv_addr;
  249. memset(&serv_addr, 0, sizeof(serv_addr));
  250. serv_addr.sin_family = AF_INET;
  251. serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  252. serv_addr.sin_port = htons(SERVER_PORT);
  253. if (bind(serv_sock, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
  254. {
  255. puts("Bind socket failed.");
  256. exit(1);
  257. }
  258. // listen on server socket
  259. if (listen(serv_sock, MAX_CLIENT_NUM) == -1)
  260. {
  261. puts("Listen socket failed.");
  262. exit(1);
  263. }
  264. puts("Start listening on port 1092...");
  265. signal(SIGINT, stop_server);
  266. for (;;)
  267. {
  268. // accept connection
  269. struct sockaddr_in clnt_addr;
  270. socklen_t clnt_addr_size = sizeof(clnt_addr);
  271. int clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size);
  272. if (clnt_sock == -1)
  273. {
  274. puts("Create socket failed.");
  275. continue;
  276. }
  277. // allocate client id
  278. for (uint16_t i = 0; i < MAX_CLIENT_NUM; i++)
  279. {
  280. if (clnt_socks[i] == -1)
  281. {
  282. clnt_socks[i] = clnt_sock;
  283. clnt_addrs[i] = clnt_addr;
  284. // create thread
  285. pthread_t pid;
  286. if (pthread_create(&pid, NULL, conn, &i) != 0)
  287. {
  288. puts("Create thread failed.");
  289. clnt_socks[i] = -1;
  290. break;
  291. }
  292. printf("Client %hu (%s:%hu) connected. pid = %lu.\n", i, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port), pid);
  293. break;
  294. }
  295. }
  296. }
  297. return 0;
  298. }