buggy code (2)
[webserver.git] / server.c
CommitLineData
00afbb65
LM
1/* depend: */
2/* cflags: */
3/* linker: color.o debug.o */
4
5#include <assert.h>
6#include <stdio.h>
7#include <stdlib.h>
89f0e084 8#include <string.h>
00afbb65
LM
9#ifdef _WIN32 /* Windows */
10#include <winsock2.h>
11#include <ws2tcpip.h>
12#else /* Posix */
13#include <errno.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <netinet/ip.h>
17#include <netinet/tcp.h>
18//#include <sys/types.h>
19//#include <sys/socket.h>
89f0e084 20#include <sys/select.h>
00afbb65
LM
21#endif
22
23#include "debug.h"
24
25#include "server.h"
26
89f0e084 27/* compat */
00afbb65
LM
28
29#ifdef _WIN32 /* Windows */
00afbb65
LM
30#define PF_INET AF_INET
31#define ERRNO (WSAGetLastError ())
32#else /* Posix */
00afbb65
LM
33#define closesocket close
34#define ERRNO errno
00afbb65
LM
35#define SOCKET_ERROR -1
36#endif
37
89f0e084
LM
38/* types */
39
00afbb65
LM
40/* constants */
41
04a2223d 42#define BACKLOG 5
00afbb65 43#define BUFFER_SIZE 4096
04a2223d 44#define TIMEOUT 100000
00afbb65
LM
45
46/* macros */
47
48/* gobal variables */
49
89f0e084 50/* init network context */
00afbb65 51
89f0e084 52void init_network_context (void)
00afbb65
LM
53{
54#ifdef _WIN32 /* Windows */
55 WSADATA WSAData;
56 WSAStartup (MAKEWORD(2,0), &WSAData);
57 assert (INVALID_SOCKET == (socket_t)-1);
9ff99d58 58 assert (SOCKET_ERROR == -1);
00afbb65 59#endif
89f0e084
LM
60}
61
62/* terminate network context */
63
64void terminate_network_context (void)
65{
66#ifdef _WIN32 /* Windows */
67 WSACleanup ();
68#endif
69}
00afbb65 70
89f0e084
LM
71/* open listening socket */
72
73socket_t open_listening_socket (int port)
74{
00afbb65
LM
75 VERBOSE (DEBUG, fprintf (stdout, "Opening socket\n"));
76 socket_t sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
9ff99d58 77 if (sock == INVALID_SOCKET) {
00afbb65 78 return -1;
9ff99d58 79 }
00afbb65
LM
80
81 struct sockaddr_in addr = {0};
82 addr.sin_family = PF_INET;
83 addr.sin_port = htons (port);
84 addr.sin_addr.s_addr = htonl (INADDR_ANY);
85
86 VERBOSE (DEBUG, fprintf (stdout, "Binding socket\n"));
87 int rc = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
9ff99d58 88 if (rc == SOCKET_ERROR) {
04a2223d 89 VERBOSE (ERROR, fprintf (stderr, "error: bind %d\n", ERRNO));
00afbb65 90 rc = closesocket (sock);
9ff99d58 91 if (rc == SOCKET_ERROR) {
04a2223d 92 VERBOSE (ERROR, fprintf (stderr, "error: close %d\n", ERRNO));
00afbb65
LM
93 }
94 return -1;
95 }
96
97 VERBOSE (DEBUG, fprintf (stdout, "Configuring socket\n"));
9ff99d58 98#ifndef _WIN32 /* Posix */
00afbb65
LM
99 fcntl (sock, F_SETFL, O_NONBLOCK);
100#endif
101 int val = 1;
102 rc = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
103 if (rc < 0) {
04a2223d 104 VERBOSE (ERROR, fprintf (stderr, "error: %s\n", "setsockopt/TCP_NODELAY"));
00afbb65 105 closesocket (sock);
9ff99d58 106 if (rc == SOCKET_ERROR) {
04a2223d
LM
107 VERBOSE (ERROR, fprintf (stderr, "error: close %d\n", ERRNO));
108 }
109 return -1;
110 }
111
112 rc = listen (sock, BACKLOG);
113 if (rc < 0) {
114 VERBOSE (ERROR, fprintf (stderr, "error: %s\n", "listen"));
115 closesocket (sock);
116 if (rc == SOCKET_ERROR) {
117 VERBOSE (ERROR, fprintf (stderr, "error: close %d\n", ERRNO));
9ff99d58 118 }
00afbb65
LM
119 return -1;
120 }
121
122 return sock;
123}
124
04a2223d
LM
125/* accept incomming connection */
126
89f0e084 127socket_t accept_incoming_connection (socket_t sock)
04a2223d 128{
89f0e084 129 socket_t connection = accept (sock, NULL, 0);
04a2223d 130 if (connection < 0) {
89f0e084 131 return INVALID_SOCKET;
04a2223d
LM
132 }
133
134#ifndef _WIN32 /* POSIX */
135 fcntl (connection, F_SETFL, O_NONBLOCK);
136#endif
137 int val = 1;
89f0e084 138 int rc = setsockopt (connection, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
04a2223d
LM
139 if (rc < 0) {
140 VERBOSE (ERROR, fprintf (stderr, "error: %s\n", "setsockopt/TCP_NODELAY"));
141 closesocket (connection);
142 if (rc == SOCKET_ERROR) {
143 VERBOSE (ERROR, fprintf (stderr, "error: close %d\n", ERRNO));
144 }
89f0e084 145 return INVALID_SOCKET;
04a2223d
LM
146 }
147
148 return connection;
149}
150
89f0e084
LM
151/* close listening socket */
152
153void close_socket (socket_t sock)
04a2223d 154{
89f0e084
LM
155 int rc = closesocket (sock);
156 if (rc == SOCKET_ERROR) {
157 VERBOSE (ERROR, fprintf (stderr, "error: %d\n", ERRNO));
158 }
159}
04a2223d 160
89f0e084 161/* receive data from socket */
04a2223d 162
89f0e084
LM
163int receive_data (socket_t sock, unsigned char **pdata)
164{
165 unsigned char buffer[BUFFER_SIZE] = {0};
166 unsigned char *data = NULL;
167 int len = 0;
04a2223d 168
89f0e084 169 while (1) {
04a2223d 170
89f0e084
LM
171 /* timeout management */
172 fd_set rfds;
173 struct timeval tv = { 0, TIMEOUT };
174 FD_ZERO (&rfds);
175 FD_SET (sock, &rfds);
176
177 int retval = select (sock + 1, &rfds, NULL, NULL, &tv);
178 if (retval != 1) { /* 0 or SOCKET_ERROR */
179 break;
180 }
04a2223d 181
89f0e084
LM
182 /* read from socket */
183 int rc = read (sock, buffer, BUFFER_SIZE);
184
185 if (rc == 0) { /* sock closed */
186 if (data) {
187 free (data);
188 data = NULL;
189 len = 0;
190 }
191 break;
192
193 } else if ((rc < 0) && (ERRNO != EAGAIN)) { /* error */
194 if (data) {
195 free (data);
196 data = NULL;
197 }
198 len = -1;
199 break;
200
201 } else if (rc > 0) {
202 data = realloc (data, len + rc);
203 memcpy (data + len, buffer, rc);
204 len += rc;
205 }
206 }
04a2223d 207
89f0e084
LM
208 if (pdata != NULL) {
209 *pdata = data;
210 }
211 return len;
04a2223d
LM
212}
213
89f0e084
LM
214/* send data onto socket */
215
216int send_data (socket_t sock, unsigned char *data, int len)
217{
218 int index = 0;
219
220 while (index < len) {
221 int rc = write (sock, data + index, len - index);
222
223 if (rc == 0) { /* sock closed */
224 index = 0;
225 break;
226 } else if ((rc < 0) && (ERRNO != EAGAIN)) { /* error */
227 index = -1;
228 break;
229 } else if (rc > 0) {
230 index += rc;
231 }
232 }
233
234 return index;
235}
06ec8057
LM
236
237/* vim: set ts=4 sw=4 et: */