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