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