adapt to linux
[webserver.git] / webserver.c
CommitLineData
8512671a
LM
1/* depend: */
2/* cflags: */
3/* linker: color.o debug.o */
4
184be781 5#include <assert.h>
8512671a
LM
6#include <stdio.h>
7#include <stdlib.h>
184be781
LM
8#ifdef _WIN32 /* Windows */
9#include <winsock2.h>
10#include <ws2tcpip.h>
11#else /* Posix */
47deaa73 12#include <errno.h>
184be781
LM
13#include <unistd.h>
14#include <fcntl.h>
47deaa73
LM
15#include <netinet/ip.h>
16#include <netinet/tcp.h>
184be781
LM
17#include <sys/types.h>
18#include <sys/socket.h>
19#endif
8512671a
LM
20
21#include "debug.h"
22
184be781
LM
23/* types */
24
25#ifdef _WIN32 /* Windows */
26typedef SOCKET socket_t;
27#else /* Posix */
28typedef int socket_t;
29#endif
30
8512671a
LM
31/* constants */
32
33#define BUFFER_SIZE 4096
34
35/* macros */
36
37/* gobal variables */
38
39char *progname = NULL;
21ac031b 40int port = 8080;
8512671a
LM
41
42/* help function */
43
44int usage (int ret)
45{
46 FILE *fid = ret ? stderr : stdout;
47 fprintf (fid, "usage: %s\n", progname);
48 fprintf (fid, " -h : help message\n");
21ac031b 49 fprintf (fid, " -p : port number (%d)\n", port);
8512671a
LM
50 fprintf (fid, " -v : verbose level (%d)\n", verbose);
51
52 return ret;
53}
54
184be781
LM
55/* open listening socket */
56
57socket_t open_listening_socket (int port)
58{
59#ifdef _WIN32 /* Windows */
60 WSADATA WSAData;
61 WSAStartup (MAKEWORD(2,0), &WSAData);
62 assert (INVALID_SOCKET == (socket_t)-1);
63#endif
64
65 VERBOSE (DEBUG, fprintf (stdout, "Opening socket\n"));
66#ifdef _WIN32 /* Windows */
67 socket_t sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
68 if (sock == INVALID_SOCKET)
69 return -1;
70#else /* Posix */
71 socket_t sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
47deaa73 72 if (sock < 0)
184be781
LM
73 return -1;
74#endif
75
76 struct sockaddr_in addr = {0};
77#ifdef _WIN32 /* Windows */
78 addr.sin_family = AF_INET;
79#else /* Posix */
80 addr.sin_family = PF_INET;
81#endif
82 addr.sin_port = htons (port);
83 addr.sin_addr.s_addr = htonl (INADDR_ANY);
84
85 VERBOSE (DEBUG, fprintf (stdout, "Binding socket\n"));
86 int rc = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
87#ifdef _WIN32 /* Windows */
88 if (rc == SOCKET_ERROR) {
89 VERBOSE (ERROR, fprintf (stderr, "error: %d\n", WSAGetLastError ()));
90 if (closesocket (sock) == SOCKET_ERROR) {
91 VERBOSE (ERROR, fprintf (stderr, "error: %d\n", WSAGetLastError ()));
92 }
93#else /* Posix */
47deaa73 94 if (rc < 0) {
184be781
LM
95 VERBOSE (ERROR, fprintf (stderr, "error: %d\n", errno));
96 close (sock);
97#endif
98 return -1;
99 }
100
101 VERBOSE (DEBUG, fprintf (stdout, "Configuring socket\n"));
102#ifdef _WIN32 /* Windows */
103#else /* Posix */
104 fcntl (sock, F_SETFL, O_NONBLOCK);
105#endif
106 int val = 1;
107 rc = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof (val));
108 if (rc < 0) {
109 VERBOSE (ERROR, fprintf (stderr, "%s\n", "setsockopt/TCP_NODELAY"));
110#ifdef _WIN32 /* Windows */
111 closesocket (sock);
112#else /* Posix */
113 close (sock);
114#endif
115 return -1;
116 }
117
118 return sock;
119}
120
121/* close listening socket */
122void close_listening_socket (socket_t sock)
123{
124#ifdef _WIN32 /* Windows */
125 closesocket (sock);
126 WSACleanup ();
127#else /* Posix */
128 close (sock);
129#endif
130}
131
8512671a
LM
132/* main function */
133
134int main (int argc, char *argv[])
135{
136 int i = 0;
137 int ret = 0;
138
139 /* program name */
140
141 progname = argv[0];
142 while (progname[i] != '\0') {
143 if ((progname[i] == '/') || (progname[i] == '\\')) {
144 progname += i + 1;
145 i = 0;
146 } else {
147 i++;
148 }
149 }
150
151 /* argument processing */
152
153 while (argc-- > 1) {
154 char *arg = *(++argv);
155 if (arg[0] != '-') {
156 VERBOSE (ERROR, fprintf (stderr, "%s: invalid option -- '%s'\n", progname, arg); usage (1));
157 return 1;
158 }
159 char c = arg[1];
160 switch (c) {
21ac031b 161 case 'p':
8512671a
LM
162 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
163 if (arg == NULL) {
21ac031b
LM
164 VERBOSE (ERROR, fprintf (stderr, "%s: missing port number\n", progname); usage (1));
165 return 1;
166 }
167 port = atoi (arg);
168 if (port <= 0) {
169 VERBOSE (ERROR, fprintf (stderr, "%s: incorrect port number (%s)\n", progname, arg); usage (1));
8512671a
LM
170 return 1;
171 }
8512671a 172 break;
8512671a
LM
173 case 'v':
174 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
175 if (arg == NULL) {
176 VERBOSE (ERROR, fprintf (stderr, "%s: missing verbose level\n", progname); usage (1));
177 return 1;
178 }
179 verbose = atoi (arg);
180 break;
181 case 'h':
182 default:
183 return usage (c != 'h');
184 }
185 }
186
184be781
LM
187 VERBOSE (DEBUG, fprintf (stdout, "Initializing socket\n"));
188 socket_t sock = open_listening_socket (port);
189 if (sock == (socket_t)-1) {
190 VERBOSE (ERROR, fprintf (stderr, "Can't open listening socket\n"));
191 return 1;
192 }
193
194 VERBOSE (INFO, fprintf (stdout, "Listening socket on port %d\n", port));
195 sleep (2);
196
197 VERBOSE (DEBUG, fprintf (stdout, "Closing socket\n"));
198 close_listening_socket (sock);
199
8512671a
LM
200 return ret;
201}
202
203// test: webserver.exe -h
204// test: webserver.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
21ac031b 205// test: webserver.exe -_ 2> /dev/null | wc -l | xargs test 0 =
8512671a
LM
206// test: webserver.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
207// test: webserver.exe error 2>&1 | grep -q 'invalid option'
21ac031b
LM
208// test: webserver.exe -v 2>&1 | grep -q 'missing verbose level'
209// test: webserver.exe -p 2>&1 | grep -q 'missing port number'
210// test: webserver.exe -p -1 2>&1 | grep -q 'incorrect port number'
184be781
LM
211// test: webserver.exe | grep -q 'Listening socket on port 8080'
212// test: webserver.exe -p 8000 | grep -q 'Listening socket on port 8000'
8512671a
LM
213
214/* vim: set ts=4 sw=4 et: */