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