/[osn-commons]/trunk/freehttpd/freehttpd.c
ViewVC logotype

Annotation of /trunk/freehttpd/freehttpd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (hide annotations)
Sat Aug 10 18:33:37 2024 UTC (7 months, 3 weeks ago) by rakinar2
File MIME type: text/x-c
File size: 5713 byte(s)
feat: add freehttpd source files to the project

1 rakinar2 44 #include "freehttpd.h"
2     #include "request.h"
3     #include <arpa/inet.h>
4     #include <stdbool.h>
5     #include <stdint.h>
6     #include <stdio.h>
7     #include <stdlib.h>
8     #include <string.h>
9     #include <sys/socket.h>
10     #include <sys/types.h>
11     #include <unistd.h>
12    
13     struct freehttpd
14     {
15     int sockfd;
16     freehttpd_config_t *config;
17     };
18    
19     static freehttpd_config_t *
20     freehttpd_config_init ()
21     {
22     struct freehttpd_config *config = calloc (1, sizeof (freehttpd_config_t));
23    
24     if (config == NULL)
25     return NULL;
26    
27     config->port = 80;
28     config->addr = NULL;
29     config->max_listen_queue = 5;
30     config->max_method_len = 16;
31     config->max_uri_len = 8192;
32     config->max_version_len = 16;
33    
34     return config;
35     }
36    
37     static void
38     freehttpd_config_free (freehttpd_config_t *config)
39     {
40     if (config == NULL)
41     return;
42    
43     free (config->addr);
44     free (config);
45     }
46    
47     freehttpd_t *
48     freehttpd_init ()
49     {
50     freehttpd_t *freehttpd = calloc (1, sizeof (freehttpd_t));
51    
52     if (freehttpd == NULL)
53     return NULL;
54    
55     freehttpd->sockfd = -1;
56     freehttpd->config = freehttpd_config_init ();
57     return freehttpd;
58     }
59    
60     ecode_t
61     freehttpd_setopt (freehttpd_t *freehttpd, freehttpd_opt_t opt, void *value)
62     {
63     if (opt >= CONFIG_OPTION_COUNT)
64     return E_UNKNOWN_OPT;
65    
66     switch (opt)
67     {
68     case FREEHTTPD_CONFIG_PORT:
69     freehttpd->config->port = *(unsigned int *) value;
70     break;
71    
72     case FREEHTTPD_CONFIG_ADDR:
73     freehttpd->config->addr
74     = value == NULL ? NULL : strdup ((const char *) value);
75     break;
76    
77     case FREEHTTPD_CONFIG_MAX_LISTEN_QUEUE:
78     freehttpd->config->max_listen_queue = *(unsigned int *) value;
79     break;
80    
81     case FREEHTTPD_CONFIG_MAX_METHOD_LEN:
82     freehttpd->config->max_method_len = *(size_t *) value;
83     break;
84    
85     case FREEHTTPD_CONFIG_MAX_URI_LEN:
86     freehttpd->config->max_uri_len = *(size_t *) value;
87     break;
88    
89     case FREEHTTPD_CONFIG_MAX_VERSION_LEN:
90     freehttpd->config->max_version_len = *(size_t *) value;
91     break;
92    
93     default:
94     return E_UNKNOWN_OPT;
95     }
96    
97     return E_OK;
98     }
99    
100     void
101     freehttpd_free (freehttpd_t *freehttpd)
102     {
103     if (freehttpd == NULL)
104     return;
105    
106     freehttpd_config_free (freehttpd->config);
107     free (freehttpd);
108     }
109    
110     static ecode_t
111     freehttpd_create_socket (freehttpd_t *freehttpd)
112     {
113     int sockfd = socket (AF_INET, SOCK_STREAM, 0);
114    
115     if (sockfd < 0)
116     return E_SYSCALL_SOCKET;
117    
118     int opt = 1;
119    
120     if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
121     return E_SYSCALL_SETSOCKOPT;
122    
123     freehttpd->sockfd = sockfd;
124     return E_OK;
125     }
126    
127     static struct sockaddr_in
128     freehttpd_setup_addrinfo (freehttpd_t *freehttpd)
129     {
130     struct sockaddr_in addr = { 0 };
131     const char *addr_host = freehttpd->config->addr;
132    
133     addr.sin_family = AF_INET;
134     addr.sin_port = htons (freehttpd->config->port);
135     addr.sin_addr.s_addr
136     = addr_host == NULL ? INADDR_ANY : inet_addr (addr_host);
137    
138     return addr;
139     }
140    
141     static ecode_t
142     freehttpd_bind (freehttpd_t *freehttpd, struct sockaddr_in *addr_in)
143     {
144     if (bind (freehttpd->sockfd, (struct sockaddr *) addr_in, sizeof (*addr_in))
145     < 0)
146     return E_SYSCALL_BIND;
147    
148     return E_OK;
149     }
150    
151     static ecode_t
152     freehttpd_listen (freehttpd_t *freehttpd)
153     {
154     unsigned int max_listen_queue = freehttpd->config->max_listen_queue;
155    
156     if (listen (freehttpd->sockfd, (int) max_listen_queue) < 0)
157     return E_SYSCALL_LISTEN;
158    
159     return E_OK;
160     }
161    
162     static ecode_t
163     freehttpd_loop (freehttpd_t *freehttpd)
164     {
165     while (true)
166     {
167     struct sockaddr_in client_addr = { 0 };
168     socklen_t client_addr_len = sizeof (client_addr);
169     int client_sockfd
170     = accept (freehttpd->sockfd, (struct sockaddr *) &client_addr,
171     &client_addr_len);
172    
173     if (client_sockfd < 0)
174     return E_SYSCALL_ACCEPT;
175    
176     ecode_t code = E_OK;
177     freehttpd_request_t *request
178     = freehttpd_request_parse (freehttpd, client_sockfd, &code);
179    
180     if (code != E_OK)
181     {
182     close (client_sockfd);
183     continue;
184     }
185    
186     fprintf (stdout, "Incoming: %s %s %s\n", request->method,
187     request->uri, request->version);
188    
189     FILE *client = fdopen (client_sockfd, "w");
190    
191     if (client == NULL)
192     {
193     freehttpd_request_free (request);
194     continue;
195     }
196    
197     fprintf (client, "%s 200 OK\r\n", request->version);
198     fprintf (client, "Server: FreeHTTPD\r\n");
199     fprintf (client, "Content-Type: text/html; charset=\"utf-8\"\r\n");
200     fprintf (client, "Content-Length: 24\r\n");
201     fprintf (client, "Connection: close\r\n");
202     fprintf (client, "\r\n");
203     fprintf (client, "<h1>Hello, World!</h1>\r\n");
204     fflush (client);
205     freehttpd_request_free (request);
206     fclose (client);
207     }
208    
209     return E_OK;
210     }
211    
212     ecode_t
213     freehttpd_start (freehttpd_t *restrict freehttpd)
214     {
215     ecode_t code = E_OK;
216     struct sockaddr_in addr_in;
217    
218     if ((code = freehttpd_create_socket (freehttpd)) != E_OK)
219     return code;
220    
221     addr_in = freehttpd_setup_addrinfo (freehttpd);
222    
223     if ((code = freehttpd_bind (freehttpd, &addr_in)) != E_OK)
224     return code;
225    
226     if ((code = freehttpd_listen (freehttpd)) != E_OK)
227     return code;
228    
229     return freehttpd_loop (freehttpd);
230     }
231    
232     const freehttpd_config_t *
233     freehttpd_get_config (freehttpd_t *freehttpd)
234     {
235     return freehttpd->config;
236     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26