buggy code (2)
[webserver.git] / server.c
1 /* depend: */
2 /* cflags: */
3 /* linker: color.o debug.o */
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
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>
20 #include <sys/select.h>
21 #endif
22
23 #include "debug.h"
24
25 #include "server.h"
26
27 /* compat */
28
29 #ifdef _WIN32 /* Windows */
30 #define PF_INET AF_INET
31 #define ERRNO (WSAGetLastError ())
32 #else /* Posix */
33 #define closesocket close
34 #define ERRNO errno
35 #define SOCKET_ERROR -1
36 #endif
37
38 /* types */
39
40 /* constants */
41
42 #define BACKLOG 5
43 #define BUFFER_SIZE 4096
44 #define TIMEOUT 100000
45
46 /* macros */
47
48 /* gobal variables */
49
50 /* init network context */
51
52 void init_network_context (void)
53 {
54 #ifdef _WIN32 /* Windows */
55 WSADATA WSAData;
56 WSAStartup (MAKEWORD(2,0), &WSAData);
57 assert (INVALID_SOCKET == (socket_t)-1);
58 assert (SOCKET_ERROR == -1);
59 #endif
60 }
61
62 /* terminate network context */
63
64 void terminate_network_context (void)
65 {
66 #ifdef _WIN32 /* Windows */
67 WSACleanup ();
68 #endif
69 }
70
71 /* open listening socket */
72
73 socket_t open_listening_socket (int port)
74 {
75 VERBOSE (DEBUG, fprintf (stdout, "Opening socket\n"));
76 socket_t sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
77 if (sock == INVALID_SOCKET) {
78 return -1;
79 }
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));
88 if (rc == SOCKET_ERROR) {
89 VERBOSE (ERROR, fprintf (stderr, "error: bind %d\n", ERRNO));
90 rc = closesocket (sock);
91 if (rc == SOCKET_ERROR) {
92 VERBOSE (ERROR, fprintf (stderr, "error: close %d\n", ERRNO));
93 }
94 return -1;
95 }
96
97 VERBOSE (DEBUG, fprintf (stdout, "Configuring socket\n"));
98 #ifndef _WIN32 /* Posix */
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) {
104 VERBOSE (ERROR, fprintf (stderr, "error: %s\n", "setsockopt/TCP_NODELAY"));
105 closesocket (sock);
106 if (rc == SOCKET_ERROR) {
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));
118 }
119 return -1;
120 }
121
122 return sock;
123 }
124
125 /* accept incomming connection */
126
127 socket_t accept_incoming_connection (socket_t sock)
128 {
129 socket_t connection = accept (sock, NULL, 0);
130 if (connection < 0) {
131 return INVALID_SOCKET;
132 }
133
134 #ifndef _WIN32 /* POSIX */
135 fcntl (connection, F_SETFL, O_NONBLOCK);
136 #endif
137 int val = 1;
138 int rc = setsockopt (connection, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
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 }
145 return INVALID_SOCKET;
146 }
147
148 return connection;
149 }
150
151 /* close listening socket */
152
153 void close_socket (socket_t sock)
154 {
155 int rc = closesocket (sock);
156 if (rc == SOCKET_ERROR) {
157 VERBOSE (ERROR, fprintf (stderr, "error: %d\n", ERRNO));
158 }
159 }
160
161 /* receive data from socket */
162
163 int 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;
168
169 while (1) {
170
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 }
181
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 }
207
208 if (pdata != NULL) {
209 *pdata = data;
210 }
211 return len;
212 }
213
214 /* send data onto socket */
215
216 int 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 }
236
237 /* vim: set ts=4 sw=4 et: */