add tests
[webserver.git] / server.c
CommitLineData
00afbb65 1#include <assert.h>
7d4815a1 2#include <signal.h>
00afbb65
LM
3#include <stdio.h>
4#include <stdlib.h>
89f0e084 5#include <string.h>
00afbb65
LM
6#ifdef _WIN32 /* Windows */
7#include <winsock2.h>
8#include <ws2tcpip.h>
9#else /* Posix */
10#include <errno.h>
11#include <unistd.h>
12#include <fcntl.h>
13#include <netinet/ip.h>
14#include <netinet/tcp.h>
89f0e084 15#include <sys/select.h>
00afbb65 16#endif
7a6b7a44 17#include <unistd.h>
00afbb65
LM
18
19#include "debug.h"
20
21#include "server.h"
22
7d4815a1 23/* types */
00afbb65
LM
24
25#ifdef _WIN32 /* Windows */
7d4815a1 26typedef SOCKET socket_t;
00afbb65 27#else /* Posix */
7d4815a1 28typedef int socket_t;
00afbb65
LM
29#endif
30
31/* constants */
32
04a2223d 33#define BACKLOG 5
00afbb65 34#define BUFFER_SIZE 4096
04a2223d 35#define TIMEOUT 100000
00afbb65
LM
36
37/* macros */
38
7d4815a1
LM
39#ifdef _WIN32 /* Windows */
40#define PF_INET AF_INET
41#define ERRNO (WSAGetLastError ())
42#else /* Posix */
43#define closesocket close
44#define ERRNO errno
45#define SOCKET_ERROR -1
46#define INVALID_SOCKET -1
47#endif
48
00afbb65
LM
49/* gobal variables */
50
7d4815a1
LM
51socket_t sock = INVALID_SOCKET;
52socket_t conn = INVALID_SOCKET;
53
54/* stop server */
55
56void stop_server (int sig)
57{
58 VERBOSE (INFO, PRINT ("Signal: %d\n", sig));
59 terminate_network_context ();
60 exit (0);
61}
62
89f0e084 63/* init network context */
00afbb65 64
89f0e084 65void init_network_context (void)
00afbb65
LM
66{
67#ifdef _WIN32 /* Windows */
68 WSADATA WSAData;
69 WSAStartup (MAKEWORD(2,0), &WSAData);
7d4815a1 70
00afbb65 71 assert (INVALID_SOCKET == (socket_t)-1);
9ff99d58 72 assert (SOCKET_ERROR == -1);
00afbb65 73#endif
7d4815a1 74
8ca9131b 75#ifndef _WIN32 /* Posix */
7d4815a1 76 signal (SIGINT, &stop_server);
8ca9131b 77#endif
7d4815a1
LM
78 signal (SIGABRT, &stop_server);
79 signal (SIGSEGV, &stop_server);
80 signal (SIGTERM, &stop_server);
89f0e084
LM
81}
82
83/* terminate network context */
84
85void terminate_network_context (void)
86{
7d4815a1
LM
87 closesocket (sock);
88 closesocket (conn);
89f0e084
LM
89#ifdef _WIN32 /* Windows */
90 WSACleanup ();
91#endif
92}
00afbb65 93
89f0e084
LM
94/* open listening socket */
95
7d4815a1 96int open_listening_socket (int port)
89f0e084 97{
1e0cfbd7
LM
98 int val = 1;
99
163f56b1 100 VERBOSE (DEBUG, PRINT ("Opening socket\n"));
1e0cfbd7 101 //socket_t sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
7d4815a1
LM
102 if (sock != INVALID_SOCKET) {
103 int rc = closesocket (sock);
104 if (rc == SOCKET_ERROR) {
105 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
106 }
107 sock = INVALID_SOCKET;
108 }
109 sock = socket (AF_INET, SOCK_STREAM, 0);
9ff99d58 110 if (sock == INVALID_SOCKET) {
7d4815a1 111 return 0;
9ff99d58 112 }
00afbb65
LM
113
114 struct sockaddr_in addr = {0};
7a6b7a44 115 //bzero (&addr, sizeof (addr));
1e0cfbd7
LM
116 //addr.sin_family = PF_INET;
117 addr.sin_family = AF_INET;
00afbb65
LM
118 addr.sin_port = htons (port);
119 addr.sin_addr.s_addr = htonl (INADDR_ANY);
120
163f56b1 121 VERBOSE (DEBUG, PRINT ("Binding socket\n"));
1e0cfbd7 122 //setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val));
00afbb65 123 int rc = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
9ff99d58 124 if (rc == SOCKET_ERROR) {
163f56b1 125 VERBOSE (ERROR, PERROR ("error: bind %d\n", ERRNO));
00afbb65 126 rc = closesocket (sock);
9ff99d58 127 if (rc == SOCKET_ERROR) {
163f56b1 128 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
00afbb65 129 }
7d4815a1
LM
130 sock = INVALID_SOCKET;
131 return 0;
00afbb65
LM
132 }
133
163f56b1 134 VERBOSE (DEBUG, PRINT ("Configuring socket\n"));
9ff99d58 135#ifndef _WIN32 /* Posix */
00afbb65
LM
136 fcntl (sock, F_SETFL, O_NONBLOCK);
137#endif
00afbb65
LM
138 rc = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
139 if (rc < 0) {
163f56b1 140 VERBOSE (ERROR, PERROR ("error: %s\n", "setsockopt/TCP_NODELAY"));
00afbb65 141 closesocket (sock);
9ff99d58 142 if (rc == SOCKET_ERROR) {
163f56b1 143 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
04a2223d 144 }
7d4815a1
LM
145 sock = INVALID_SOCKET;
146 return 0;
04a2223d
LM
147 }
148
149 rc = listen (sock, BACKLOG);
150 if (rc < 0) {
163f56b1 151 VERBOSE (ERROR, PERROR ("error: %s\n", "listen"));
04a2223d
LM
152 closesocket (sock);
153 if (rc == SOCKET_ERROR) {
163f56b1 154 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
9ff99d58 155 }
7d4815a1
LM
156 sock = INVALID_SOCKET;
157 return 0;
00afbb65
LM
158 }
159
7d4815a1 160 return 1;
00afbb65
LM
161}
162
04a2223d
LM
163/* accept incomming connection */
164
7d4815a1 165int accept_incoming_connection (void)
04a2223d 166{
7d4815a1
LM
167 if (sock == INVALID_SOCKET) {
168 VERBOSE (ERROR, PERROR ("Can't accept connection from closed socket\n"));
169 return 0;
170 }
171
172 if (conn != INVALID_SOCKET) {
173 int rc = closesocket (conn);
174 if (rc == SOCKET_ERROR) {
175 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
176 }
177 conn = INVALID_SOCKET;
178 }
179 conn = accept (sock, NULL, 0);
180 if (conn == INVALID_SOCKET) {
181 return 0;
04a2223d
LM
182 }
183
184#ifndef _WIN32 /* POSIX */
7d4815a1 185 fcntl (conn, F_SETFL, O_NONBLOCK);
04a2223d
LM
186#endif
187 int val = 1;
7d4815a1 188 int rc = setsockopt (conn, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
04a2223d 189 if (rc < 0) {
163f56b1 190 VERBOSE (ERROR, PERROR ("error: %s\n", "setsockopt/TCP_NODELAY"));
7d4815a1 191 closesocket (conn);
04a2223d 192 if (rc == SOCKET_ERROR) {
163f56b1 193 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
04a2223d 194 }
7d4815a1
LM
195 conn = INVALID_SOCKET;
196 return 0;
04a2223d
LM
197 }
198
7d4815a1 199 return 1;
04a2223d
LM
200}
201
7d4815a1 202/* close connection socket */
89f0e084 203
7d4815a1 204void close_connection (void)
04a2223d 205{
7d4815a1 206 int rc = closesocket (conn);
89f0e084 207 if (rc == SOCKET_ERROR) {
163f56b1 208 VERBOSE (ERROR, PERROR ("error: %d\n", ERRNO));
89f0e084 209 }
7d4815a1 210 conn = INVALID_SOCKET;
89f0e084 211}
04a2223d 212
89f0e084 213/* receive data from socket */
04a2223d 214
cae06547 215int receive_data (char **pdata)
89f0e084 216{
cae06547
LM
217 char buffer[BUFFER_SIZE] = {0};
218 char *data = NULL;
89f0e084 219 int len = 0;
04a2223d 220
7d4815a1
LM
221 if (conn == INVALID_SOCKET) {
222 VERBOSE (ERROR, PERROR ("Can't read data from closed socket\n"));
223 return 0;
224 }
225
89f0e084 226 while (1) {
04a2223d 227
89f0e084
LM
228 /* timeout management */
229 fd_set rfds;
230 struct timeval tv = { 0, TIMEOUT };
231 FD_ZERO (&rfds);
7d4815a1 232 FD_SET (conn, &rfds);
89f0e084 233
7d4815a1 234 int retval = select (conn + 1, &rfds, NULL, NULL, &tv);
89f0e084
LM
235 if (retval != 1) { /* 0 or SOCKET_ERROR */
236 break;
237 }
04a2223d 238
89f0e084 239 /* read from socket */
cae06547
LM
240 int rc = recv (conn, buffer, BUFFER_SIZE, 0);
241 VERBOSE (DEBUG, PRINT ("rc: %d\nerrno: %d\n", rc, ERRNO));
89f0e084
LM
242
243 if (rc == 0) { /* sock closed */
244 if (data) {
245 free (data);
246 data = NULL;
247 len = 0;
248 }
249 break;
250
251 } else if ((rc < 0) && (ERRNO != EAGAIN)) { /* error */
252 if (data) {
253 free (data);
254 data = NULL;
255 }
256 len = -1;
257 break;
258
259 } else if (rc > 0) {
260 data = realloc (data, len + rc);
261 memcpy (data + len, buffer, rc);
262 len += rc;
263 }
264 }
04a2223d 265
89f0e084
LM
266 if (pdata != NULL) {
267 *pdata = data;
268 }
269 return len;
04a2223d
LM
270}
271
89f0e084
LM
272/* send data onto socket */
273
cae06547 274int send_data (char *data, int len)
89f0e084
LM
275{
276 int index = 0;
277
7d4815a1
LM
278 if (conn == INVALID_SOCKET) {
279 VERBOSE (ERROR, PERROR ("Can't read data from closed socket\n"));
280 return 0;
281 }
282
89f0e084 283 while (index < len) {
0930e936 284 int rc = send (conn, data + index, len - index, 0);
89f0e084
LM
285
286 if (rc == 0) { /* sock closed */
287 index = 0;
288 break;
289 } else if ((rc < 0) && (ERRNO != EAGAIN)) { /* error */
290 index = -1;
291 break;
292 } else if (rc > 0) {
293 index += rc;
294 }
295 }
296
297 return index;
298}
06ec8057
LM
299
300/* vim: set ts=4 sw=4 et: */