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