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