comparison seobeo/main.c @ 3:2758f5527d2b

[Seobeo] Working on simple TCP server and client logic.
author June Park <parkjune1995@gmail.com>
date Wed, 24 Sep 2025 18:49:09 -0700
parents adcfad6e86fb
children 0b3b4f5887bb
comparison
equal deleted inserted replaced
2:8a43dedbe530 3:2758f5527d2b
1 /* 1 /*
2 ** server.c -- a stream socket server demo 2 ** server.c -- a stream socket server demo
3 */ 3 */
4 4
5 #include "seobeo/seobeo.h" 5 #include "seobeo/seobeo.h"
6
7 Dowa_PHashMap cache;
6 8
7 void SigchildHandler(int s) 9 void SigchildHandler(int s)
8 { 10 {
9 (void)s; // quiet unused variable warning 11 (void)s; // quiet unused variable warning
10 12
14 while(waitpid(-1, NULL, WNOHANG) > 0); 16 while(waitpid(-1, NULL, WNOHANG) > 0);
15 17
16 errno = saved_errno; 18 errno = saved_errno;
17 } 19 }
18 20
19
20 void *GetInternetaddr(struct sockaddr *sa)
21 {
22 if (sa->sa_family == AF_INET)
23 {
24 return &(((struct sockaddr_in*)sa)->sin_addr);
25 }
26
27 return &(((struct sockaddr_in6*)sa)->sin6_addr);
28 }
29
30 void HandleClientRequest(int client_fd) 21 void HandleClientRequest(int client_fd)
31 { 22 {
32 FILE *file = fopen("seobeo/index.html", "rb"); 23 size_t idx = Dowa_HashMap_GetPosition(cache, "index.html");
33 if (!file) { 24 Dowa_PHashEntry entry = cache->entries[idx];
34 perror("fopen"); 25 if (!entry) {
26 // 404 response if missing
27 const char *not_found =
28 "HTTP/1.1 404 Not Found\r\n"
29 "Content-Length: 0\r\n"
30 "Connection: close\r\n"
31 "\r\n";
32 send(client_fd, not_found, strlen(not_found), 0);
33 close(client_fd);
35 return; 34 return;
36 } 35 }
37 36
38 fseek(file, 0, SEEK_END); 37 // 3) Prepare header with the correct content‐length
39 size_t size = ftell(file); 38 size_t body_size = entry->capacity;
40 fseek(file, 0, SEEK_SET); 39 const char *template =
41
42 char *data = malloc(size);
43 fread(data, 1, size, file);
44 fclose(file);
45
46 char *header = malloc(100);
47 sprintf(
48 header,
49 "HTTP/1.1 200 OK\r\n" 40 "HTTP/1.1 200 OK\r\n"
50 "Content-Type: text/html\r\n" 41 "Content-Type: text/html\r\n"
51 "Content-Length: %zu\r\n" 42 "Content-Length: %zu\r\n"
52 "Connection: close\r\n" 43 "Connection: close\r\n"
53 "\r\n", 44 "\r\n";
54 size
55 );
56 45
57 send(client_fd, header, strlen(header), 0); 46 // Compute how large the header is and allocate just enough space
47 int header_len = snprintf(NULL, 0, template, body_size);
48 char *header = malloc(header_len + 1);
49 if (!header) {
50 perror("malloc");
51 close(client_fd);
52 return;
53 }
54 snprintf(header, header_len + 1, template, body_size);
55
56 // 4) Send header
57 send(client_fd, header, header_len, 0);
58 free(header);
59
60 // 5) Stream the body in a loop until everything is sent
58 ssize_t total_sent = 0; 61 ssize_t total_sent = 0;
59 while (total_sent < size) 62 const char *body = entry->buffer;
63 while ((size_t)total_sent < body_size)
60 { 64 {
61 ssize_t sent = send(client_fd, data + total_sent, size - total_sent, 0); 65 ssize_t sent = send(
62 if (sent <= 0) break; 66 client_fd,
67 body + total_sent,
68 body_size - total_sent,
69 0
70 );
71 if (sent <= 0)
72 {
73 // error or connection closed by client
74 break;
75 }
63 total_sent += sent; 76 total_sent += sent;
64 } 77 }
65 78
79 // 6) Tear down
66 close(client_fd); 80 close(client_fd);
67 } 81 }
68 82
69 int main(void) 83 int main(void)
70 { 84 {
71 int32 client_fd; 85 cache = Dowa_HashMap_Create(1024);
72 struct sockaddr_storage client_addr; 86 if (Dowa_Cache_Folder(cache, "seobeo/pages") != 0)
73 socklen_t sin_size; 87 {
74 88 perror("Dowa_Cache_Folder");
75 char client_inet_addr[INET6_ADDRSTRLEN]; 89 return -1;
90 }
76 91
77 struct sigaction sa; 92 struct sigaction sa;
78 93
79 sa.sa_handler = SigchildHandler; // reap all dead processes 94 sa.sa_handler = SigchildHandler; // reap all dead processes
80 sigemptyset(&sa.sa_mask); 95 sigemptyset(&sa.sa_mask);
83 perror("sigaction"); 98 perror("sigaction");
84 exit(1); 99 exit(1);
85 } 100 }
86 101
87 int sock_fd = Seobeo_CreateSocket(1, "6969", 10); 102 int sock_fd = Seobeo_CreateSocket(1, "6969", 10);
88 103 Seobeo_ListenClient(sock_fd, &HandleClientRequest);
89 printf("server: waiting for connections...\n");
90
91 while (1)
92 {
93 sin_size = sizeof(client_addr);
94 client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
95
96 if (client_fd == -1)
97 {
98 perror("accept");
99 break;
100 }
101
102 inet_ntop(
103 client_addr.ss_family,
104 GetInternetaddr((struct sockaddr *)&client_addr),
105 client_inet_addr, sizeof client_inet_addr);
106
107 printf("server: got connection from %s\n", client_inet_addr);
108
109 // Create a child process
110 if (!fork())
111 {
112 close(sock_fd);
113 HandleClientRequest(client_fd);
114 exit(0);
115 }
116
117 close(client_fd);
118 }
119 104
120 return 0; 105 return 0;
121 } 106 }
122 107