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