corrections
[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
LM
74
75 signal (SIGINT, &stop_server);
76 signal (SIGQUIT, &stop_server);
77 signal (SIGABRT, &stop_server);
78 signal (SIGSEGV, &stop_server);
79 signal (SIGTERM, &stop_server);
89f0e084
LM
80}
81
82/* terminate network context */
83
84void terminate_network_context (void)
85{
7d4815a1
LM
86 closesocket (sock);
87 closesocket (conn);
89f0e084
LM
88#ifdef _WIN32 /* Windows */
89 WSACleanup ();
90#endif
91}
00afbb65 92
89f0e084
LM
93/* open listening socket */
94
7d4815a1 95int open_listening_socket (int port)
89f0e084 96{
1e0cfbd7
LM
97 int val = 1;
98
163f56b1 99 VERBOSE (DEBUG, PRINT ("Opening socket\n"));
1e0cfbd7 100 //socket_t sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
7d4815a1
LM
101 if (sock != INVALID_SOCKET) {
102 int rc = closesocket (sock);
103 if (rc == SOCKET_ERROR) {
104 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
105 }
106 sock = INVALID_SOCKET;
107 }
108 sock = socket (AF_INET, SOCK_STREAM, 0);
9ff99d58 109 if (sock == INVALID_SOCKET) {
7d4815a1 110 return 0;
9ff99d58 111 }
00afbb65
LM
112
113 struct sockaddr_in addr = {0};
7a6b7a44 114 //bzero (&addr, sizeof (addr));
1e0cfbd7
LM
115 //addr.sin_family = PF_INET;
116 addr.sin_family = AF_INET;
00afbb65
LM
117 addr.sin_port = htons (port);
118 addr.sin_addr.s_addr = htonl (INADDR_ANY);
119
163f56b1 120 VERBOSE (DEBUG, PRINT ("Binding socket\n"));
1e0cfbd7 121 //setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val));
00afbb65 122 int rc = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
9ff99d58 123 if (rc == SOCKET_ERROR) {
163f56b1 124 VERBOSE (ERROR, PERROR ("error: bind %d\n", ERRNO));
00afbb65 125 rc = closesocket (sock);
9ff99d58 126 if (rc == SOCKET_ERROR) {
163f56b1 127 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
00afbb65 128 }
7d4815a1
LM
129 sock = INVALID_SOCKET;
130 return 0;
00afbb65
LM
131 }
132
163f56b1 133 VERBOSE (DEBUG, PRINT ("Configuring socket\n"));
9ff99d58 134#ifndef _WIN32 /* Posix */
00afbb65
LM
135 fcntl (sock, F_SETFL, O_NONBLOCK);
136#endif
00afbb65
LM
137 rc = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
138 if (rc < 0) {
163f56b1 139 VERBOSE (ERROR, PERROR ("error: %s\n", "setsockopt/TCP_NODELAY"));
00afbb65 140 closesocket (sock);
9ff99d58 141 if (rc == SOCKET_ERROR) {
163f56b1 142 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
04a2223d 143 }
7d4815a1
LM
144 sock = INVALID_SOCKET;
145 return 0;
04a2223d
LM
146 }
147
148 rc = listen (sock, BACKLOG);
149 if (rc < 0) {
163f56b1 150 VERBOSE (ERROR, PERROR ("error: %s\n", "listen"));
04a2223d
LM
151 closesocket (sock);
152 if (rc == SOCKET_ERROR) {
163f56b1 153 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
9ff99d58 154 }
7d4815a1
LM
155 sock = INVALID_SOCKET;
156 return 0;
00afbb65
LM
157 }
158
7d4815a1 159 return 1;
00afbb65
LM
160}
161
04a2223d
LM
162/* accept incomming connection */
163
7d4815a1 164int accept_incoming_connection (void)
04a2223d 165{
7d4815a1
LM
166 if (sock == INVALID_SOCKET) {
167 VERBOSE (ERROR, PERROR ("Can't accept connection from closed socket\n"));
168 return 0;
169 }
170
171 if (conn != INVALID_SOCKET) {
172 int rc = closesocket (conn);
173 if (rc == SOCKET_ERROR) {
174 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
175 }
176 conn = INVALID_SOCKET;
177 }
178 conn = accept (sock, NULL, 0);
179 if (conn == INVALID_SOCKET) {
180 return 0;
04a2223d
LM
181 }
182
183#ifndef _WIN32 /* POSIX */
7d4815a1 184 fcntl (conn, F_SETFL, O_NONBLOCK);
04a2223d
LM
185#endif
186 int val = 1;
7d4815a1 187 int rc = setsockopt (conn, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
04a2223d 188 if (rc < 0) {
163f56b1 189 VERBOSE (ERROR, PERROR ("error: %s\n", "setsockopt/TCP_NODELAY"));
7d4815a1 190 closesocket (conn);
04a2223d 191 if (rc == SOCKET_ERROR) {
163f56b1 192 VERBOSE (ERROR, PERROR ("error: close %d\n", ERRNO));
04a2223d 193 }
7d4815a1
LM
194 conn = INVALID_SOCKET;
195 return 0;
04a2223d
LM
196 }
197
7d4815a1 198 return 1;
04a2223d
LM
199}
200
7d4815a1 201/* close connection socket */
89f0e084 202
7d4815a1 203void close_connection (void)
04a2223d 204{
7d4815a1 205 int rc = closesocket (conn);
89f0e084 206 if (rc == SOCKET_ERROR) {
163f56b1 207 VERBOSE (ERROR, PERROR ("error: %d\n", ERRNO));
89f0e084 208 }
7d4815a1 209 conn = INVALID_SOCKET;
89f0e084 210}
04a2223d 211
89f0e084 212/* receive data from socket */
04a2223d 213
7d4815a1 214int receive_data (unsigned char **pdata)
89f0e084
LM
215{
216 unsigned char buffer[BUFFER_SIZE] = {0};
217 unsigned char *data = NULL;
218 int len = 0;
04a2223d 219
7d4815a1
LM
220 if (conn == INVALID_SOCKET) {
221 VERBOSE (ERROR, PERROR ("Can't read data from closed socket\n"));
222 return 0;
223 }
224
89f0e084 225 while (1) {
04a2223d 226
89f0e084
LM
227 /* timeout management */
228 fd_set rfds;
229 struct timeval tv = { 0, TIMEOUT };
230 FD_ZERO (&rfds);
7d4815a1 231 FD_SET (conn, &rfds);
89f0e084 232
7d4815a1 233 int retval = select (conn + 1, &rfds, NULL, NULL, &tv);
89f0e084
LM
234 if (retval != 1) { /* 0 or SOCKET_ERROR */
235 break;
236 }
04a2223d 237
89f0e084 238 /* read from socket */
7d4815a1 239 int rc = read (conn, buffer, BUFFER_SIZE);
89f0e084
LM
240
241 if (rc == 0) { /* sock closed */
242 if (data) {
243 free (data);
244 data = NULL;
245 len = 0;
246 }
247 break;
248
249 } else if ((rc < 0) && (ERRNO != EAGAIN)) { /* error */
250 if (data) {
251 free (data);
252 data = NULL;
253 }
254 len = -1;
255 break;
256
257 } else if (rc > 0) {
258 data = realloc (data, len + rc);
259 memcpy (data + len, buffer, rc);
260 len += rc;
261 }
262 }
04a2223d 263
89f0e084
LM
264 if (pdata != NULL) {
265 *pdata = data;
266 }
267 return len;
04a2223d
LM
268}
269
89f0e084
LM
270/* send data onto socket */
271
7d4815a1 272int send_data (unsigned char *data, int len)
89f0e084
LM
273{
274 int index = 0;
275
7d4815a1
LM
276 if (conn == INVALID_SOCKET) {
277 VERBOSE (ERROR, PERROR ("Can't read data from closed socket\n"));
278 return 0;
279 }
280
89f0e084 281 while (index < len) {
7d4815a1 282 int rc = write (conn, data + index, len - index);
89f0e084
LM
283
284 if (rc == 0) { /* sock closed */
285 index = 0;
286 break;
287 } else if ((rc < 0) && (ERRNO != EAGAIN)) { /* error */
288 index = -1;
289 break;
290 } else if (rc > 0) {
291 index += rc;
292 }
293 }
294
295 return index;
296}
06ec8057
LM
297
298/* vim: set ts=4 sw=4 et: */