1 /**********************************************************
2 *
3 * socket_manager.c -- Socket Manager file handler portion of the Mp3Splt utility
4 * Utility for mp3/ogg splitting without decoding
5 *
6 * Copyright (c) 2002-2004 M. Trotta - <matteo.trotta@lib.unimib.it>
7 * Copyright (c) 2005-2014 Alexandru Munteanu - m@ioalex.net
8 *
9 * http://mp3splt.sourceforge.net
10 */
11
12 /**********************************************************
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
27 * USA.
28 *
29 *********************************************************/
30
31 /*!\file
32
33 Manages a socket connection
34 */
35
36 #include <unistd.h>
37
38 #ifdef __WIN32__
39 #define _WIN32_WINNT 0x0501
40 #include <ws2tcpip.h>
41 #include <windows.h>
42 #include <winsock2.h>
43 #else
44 #include <netdb.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #endif
48
49 #ifdef __WIN32__
50 #include <malloc.h>
51 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
52 #include <stdlib.h>
53 #else
54 #include <alloca.h>
55 #endif
56
57 #include <string.h>
58
59 #include "splt.h"
60 #include "socket_manager.h"
61
62 #define SPLT_BUFFER_SIZE 1024
63 #define SPLT_MAXIMUM_NUMBER_OF_LINES_READ 1000
64
65 static void splt_sm_handle_response_and_free(char **first_line, splt_socket_handler *sh,
66 splt_state *state);
67
68 static char *get_message_decorated_with_http(splt_socket_handler *sh, const char *message,
69 splt_state *state);
70 static char *get_message_with_proxy(splt_socket_handler *sh, const char *message, splt_state *state);
71 static char *get_message_without_proxy(splt_socket_handler *sh, const char *message);
72 static int message_starts_with_get(const char *message);
73
splt_sm_connect(splt_socket_handler * sh,const char * hostname,int port,splt_state * state)74 void splt_sm_connect(splt_socket_handler *sh, const char *hostname, int port, splt_state *state)
75 {
76 const char *real_hostname = hostname;
77 int real_port = port;
78 if (splt_pr_has_proxy(state))
79 {
80 real_hostname = splt_pr_get_proxy_address(state);
81 real_port = splt_pr_get_proxy_port(state);
82 }
83
84 splt_d_print_debug(state, "\nConnecting on host %s:%d\n", real_hostname, real_port);
85
86 int err = splt_su_copy(hostname, &sh->hostname);
87 if (err < 0) { sh->error = err; return; }
88
89 #ifdef __WIN32__
90 WSADATA winsock;
91 long winsockinit = WSAStartup(0x0101,&winsock);
92 if (winsockinit != 0)
93 {
94 splt_e_set_strerror_msg(state);
95 sh->error = SPLT_FREEDB_ERROR_INITIALISE_SOCKET;
96 return;
97 }
98 #endif
99
100 struct addrinfo hints;
101 memset(&hints, 0, sizeof(struct addrinfo));
102 hints.ai_family = AF_UNSPEC;
103 hints.ai_socktype = SOCK_STREAM;
104
105 struct addrinfo *result;
106
107 char *port_as_string = alloca(16);
108 snprintf(port_as_string, 16, "%d", real_port);
109
110 int return_code = getaddrinfo(real_hostname, port_as_string, &hints, &result);
111 if (return_code != 0) {
112 splt_e_set_strerr_msg(state, gai_strerror(return_code));
113 splt_e_set_error_data(state, real_hostname);
114 sh->error = SPLT_FREEDB_ERROR_CANNOT_GET_HOST;
115 return;
116 }
117
118 struct addrinfo *result_p;
119 for (result_p = result; result_p != NULL; result_p = result_p->ai_next)
120 {
121 sh->fd = socket(result_p->ai_family, result_p->ai_socktype, result_p->ai_protocol);
122 if (sh->fd == -1)
123 {
124 splt_e_set_strerror_msg(state);
125 continue;
126 }
127
128 if (connect(sh->fd, result_p->ai_addr, result_p->ai_addrlen) != -1)
129 {
130 break;
131 }
132
133 splt_e_set_strerror_msg(state);
134 close(sh->fd);
135 }
136
137 if (result_p == NULL) {
138 splt_e_set_error_data(state, real_hostname);
139 sh->error = SPLT_FREEDB_ERROR_CANNOT_CONNECT;
140 freeaddrinfo(result);
141 return;
142 }
143
144 freeaddrinfo(result);
145
146 splt_d_print_debug(state, " ... connected.\n");
147 }
148
splt_sm_send(splt_socket_handler * sh,const char * message,splt_state * state)149 void splt_sm_send(splt_socket_handler *sh, const char *message,
150 splt_state *state)
151 {
152 splt_d_print_debug(state, "\nSending message _%s_\n", message);
153
154 if (send(sh->fd, message, strlen(message), 0) == -1)
155 {
156 splt_e_set_strerror_msg(state);
157 splt_e_set_error_data(state, sh->hostname);
158 sh->error = SPLT_FREEDB_ERROR_CANNOT_SEND_MESSAGE;
159 }
160
161 splt_d_print_debug(state, " ... message sent.\n");
162 }
163
splt_sm_send_http_message(splt_socket_handler * sh,const char * message,splt_state * state)164 void splt_sm_send_http_message(splt_socket_handler *sh, const char *message,
165 splt_state *state)
166 {
167 char *message_with_http = get_message_decorated_with_http(sh, message, state);
168 if (message_with_http == NULL)
169 {
170 return;
171 }
172
173 splt_sm_send(sh, message_with_http, state);
174
175 if (message_with_http)
176 {
177 free(message_with_http);
178 message_with_http = NULL;
179 }
180 }
181
get_message_decorated_with_http(splt_socket_handler * sh,const char * message,splt_state * state)182 static char *get_message_decorated_with_http(splt_socket_handler *sh, const char *message,
183 splt_state *state)
184 {
185 if (splt_pr_has_proxy(state) && message_starts_with_get(message))
186 {
187 return get_message_with_proxy(sh, message, state);
188 }
189
190 return get_message_without_proxy(sh, message);
191 }
192
message_starts_with_get(const char * message)193 static int message_starts_with_get(const char *message)
194 {
195 if (strlen(message) < 4)
196 {
197 return SPLT_FALSE;
198 }
199
200 if (message[0] == 'G' && message[1] == 'E' && message[2] == 'T' && message[3] == ' ')
201 {
202 return SPLT_TRUE;
203 }
204
205 return SPLT_FALSE;
206 }
207
get_message_with_proxy(splt_socket_handler * sh,const char * message,splt_state * state)208 static char *get_message_with_proxy(splt_socket_handler *sh, const char *message,
209 splt_state *state)
210 {
211 char *message_with_proxy = NULL;
212 int err = splt_su_append_str(&message_with_proxy,
213 "GET http://", sh->hostname, message + 4, " HTTP/1.0\r\n",
214 "UserAgent: ", SPLT_PACKAGE_NAME, "/", SPLT_PACKAGE_VERSION, "\r\n",
215 "Host: ", sh->hostname, NULL);
216 if (err < 0) { sh->error = err; return NULL; }
217
218 if (splt_pr_has_proxy_authentification(state))
219 {
220 splt_su_append_str(&message_with_proxy,
221 "\r\nProxy-Authorization: Basic ",
222 splt_pr_get_proxy_authentification(state), NULL);
223 if (err < 0)
224 {
225 sh->error = err;
226 free(message_with_proxy);
227 return NULL;
228 }
229 }
230
231 splt_su_append_str(&message_with_proxy, "\r\n\r\n", NULL);
232 if (err < 0)
233 {
234 sh->error = err;
235 free(message_with_proxy);
236 return NULL;
237 }
238
239 return message_with_proxy;
240 }
241
get_message_without_proxy(splt_socket_handler * sh,const char * message)242 static char *get_message_without_proxy(splt_socket_handler *sh, const char *message)
243 {
244 char *message_with_http = NULL;
245 int err = splt_su_append_str(&message_with_http,
246 message, " HTTP/1.0\r\nHost: ", sh->hostname, "\r\n\r\n", NULL);
247 if (err < 0) { sh->error = err; return NULL; }
248
249 return message_with_http;
250 }
251
splt_sm_process_without_headers_functor(const char * received_line,int line_number,void * user_data)252 int splt_sm_process_without_headers_functor(const char *received_line,
253 int line_number, void *user_data)
254 {
255 splt_sm_functor_decorator *sm_fd = (splt_sm_functor_decorator *) user_data;
256
257 if (!sm_fd->processing_headers)
258 {
259 int real_line_number =
260 sm_fd->line_number_after_headers - sm_fd->num_lines_to_skip;
261
262 if (real_line_number > 0)
263 {
264 int we_continue = sm_fd->functor(received_line, real_line_number, sm_fd->user_data);
265 if (!we_continue)
266 {
267 return SPLT_FALSE;
268 }
269 }
270 sm_fd->line_number_after_headers++;
271 }
272
273 if (strlen(received_line) == 0)
274 {
275 sm_fd->processing_headers = SPLT_FALSE;
276 }
277
278 return SPLT_TRUE;
279 }
280
splt_sm_receive_and_process_without_headers_with_recv(splt_socket_handler * sh,splt_state * state,ssize_t (* recv_func)(int fd,void * buf,size_t len,int flags),int (* process_functor)(const char * received_line,int line_number,void * user_data),void * user_data,int number_of_lines_to_skip_after_headers)281 char *splt_sm_receive_and_process_without_headers_with_recv(splt_socket_handler *sh,
282 splt_state *state,
283 ssize_t (*recv_func)(int fd, void *buf, size_t len, int flags),
284 int (*process_functor)(const char *received_line, int line_number, void *user_data),
285 void *user_data, int number_of_lines_to_skip_after_headers)
286 {
287 splt_sm_functor_decorator *sm_fd = malloc(sizeof(splt_sm_functor_decorator));
288 if (!sm_fd)
289 {
290 sh->error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY;
291 return NULL;
292 }
293
294 sm_fd->functor = process_functor;
295 sm_fd->user_data = user_data;
296 sm_fd->processing_headers = SPLT_TRUE;
297 sm_fd->num_lines_to_skip = number_of_lines_to_skip_after_headers;
298 sm_fd->line_number_after_headers = 1;
299 sm_fd->line_number = 1;
300
301 char *first_line = splt_sm_receive_and_process_with_recv(sh, state,
302 recv_func, splt_sm_process_without_headers_functor, sm_fd);
303
304 free(sm_fd);
305 sm_fd = NULL;
306
307 return first_line;
308 }
309
splt_sm_receive_and_process_without_headers(splt_socket_handler * sh,splt_state * state,int (* process_functor)(const char * received_line,int line_number,void * user_data),void * user_data,int number_of_lines_to_skip_after_headers)310 void splt_sm_receive_and_process_without_headers(splt_socket_handler *sh,
311 splt_state *state,
312 int (*process_functor)(const char *received_line, int line_number, void *user_data),
313 void *user_data, int number_of_lines_to_skip_after_headers)
314 {
315
316 #ifdef __WIN32__
317 char *first_line =
318 splt_sm_receive_and_process_without_headers_with_recv(sh, state, NULL,
319 process_functor, user_data, number_of_lines_to_skip_after_headers);
320 #else
321 char *first_line =
322 splt_sm_receive_and_process_without_headers_with_recv(sh, state, recv,
323 process_functor, user_data, number_of_lines_to_skip_after_headers);
324 #endif
325
326 splt_sm_handle_response_and_free(&first_line, sh, state);
327 }
328
splt_sm_receive_and_process(splt_socket_handler * sh,splt_state * state,int (* process_functor)(const char * received_line,int line_number,void * user_data),void * user_data)329 void splt_sm_receive_and_process(splt_socket_handler *sh, splt_state *state,
330 int (*process_functor)(const char *received_line, int line_number, void *user_data),
331 void *user_data)
332 {
333 #ifdef __WIN32__
334 char *first_line =
335 splt_sm_receive_and_process_with_recv(sh, state, NULL, process_functor, user_data);
336 #else
337 char *first_line =
338 splt_sm_receive_and_process_with_recv(sh, state, recv, process_functor, user_data);
339 #endif
340
341 splt_sm_handle_response_and_free(&first_line, sh, state);
342 }
343
splt_sm_receive_and_process_with_recv(splt_socket_handler * sh,splt_state * state,ssize_t (* recv_func)(int fd,void * buf,size_t len,int flags),int (* process_functor)(const char * received_line,int line_number,void * user_data),void * user_data)344 char *splt_sm_receive_and_process_with_recv(splt_socket_handler *sh, splt_state *state,
345 ssize_t (*recv_func)(int fd, void *buf, size_t len, int flags),
346 int (*process_functor)(const char *received_line, int line_number, void *user_data),
347 void *user_data)
348 {
349 splt_d_print_debug(state, "\nWaiting for response ...");
350
351 int err = SPLT_OK;
352 char *first_line = NULL;
353
354 char *lines = NULL;
355
356 char *remaining_line = NULL;
357 int remaining_line_size = 0;
358
359 char buffer[SPLT_BUFFER_SIZE] = { '\0' };
360
361 int number_of_lines_read = 0;
362
363 char *line_begin = NULL;
364 char *line_end = NULL;
365
366 int line_number = 1;
367
368 while (number_of_lines_read < SPLT_MAXIMUM_NUMBER_OF_LINES_READ) {
369 memset(buffer, '\0', SPLT_BUFFER_SIZE);
370 #ifdef __WIN32__
371 int received_bytes = recv(sh->fd, buffer, SPLT_BUFFER_SIZE, 0);
372 #else
373 int received_bytes = recv_func(sh->fd, buffer, SPLT_BUFFER_SIZE, 0);
374 #endif
375 if (received_bytes == -1)
376 {
377 splt_e_set_strerror_msg(state);
378 splt_e_set_error_data(state, sh->hostname);
379 sh->error = SPLT_FREEDB_ERROR_CANNOT_RECV_MESSAGE;
380 goto end;
381 }
382
383 if (received_bytes == 0)
384 {
385 break;
386 }
387
388 err = splt_su_set(&lines, remaining_line, remaining_line_size, NULL);
389 if (err < 0) { sh->error = err; goto end; }
390
391 err = splt_su_append(&lines, buffer, received_bytes, NULL);
392 if (err < 0) { sh->error = err; goto end; }
393
394 remaining_line_size += received_bytes;
395
396 if (!lines)
397 {
398 continue;
399 }
400
401 line_begin = lines;
402 line_end = NULL;
403
404 while ((line_end = strchr(line_begin, '\n')) != NULL)
405 {
406 int line_size = (line_end - line_begin) + 1;
407
408 char *line = NULL;
409 err = splt_su_set(&line, line_begin, line_size, "\0", 1, NULL);
410 if (err < 0) { sh->error = err; goto end; }
411
412 splt_su_line_to_unix(line);
413 splt_su_str_cut_last_char(line);
414
415 splt_d_print_debug(state, "Received line _%s_\n", line);
416
417 if (line_number == 1)
418 {
419 err = splt_su_copy(line, &first_line);
420 if (err < 0) { sh->error = err; goto end; }
421 }
422
423 int we_continue = process_functor(line, line_number, user_data);
424
425 line_number++;
426
427 if (line)
428 {
429 free(line);
430 line = NULL;
431 }
432
433 if (!we_continue)
434 {
435 goto end;
436 }
437
438 remaining_line_size -= line_size;
439 line_begin = line_end + 1;
440 }
441
442 err = splt_su_set(&remaining_line, line_begin, remaining_line_size, NULL);
443 if (err < 0) { sh->error = err; goto end; }
444 }
445
446 end:
447 if (lines)
448 {
449 free(lines);
450 lines = NULL;
451 }
452 if (remaining_line)
453 {
454 free(remaining_line);
455 remaining_line = NULL;
456 }
457
458 return first_line;
459 }
460
splt_sm_close(splt_socket_handler * sh,splt_state * state)461 void splt_sm_close(splt_socket_handler *sh, splt_state *state)
462 {
463 if (closesocket(sh->fd) == -1)
464 {
465 splt_e_set_strerror_msg(state);
466 sh->error = SPLT_FREEDB_ERROR_CANNOT_DISCONNECT;
467 }
468
469 #ifdef __WIN32__
470 WSACleanup();
471 #endif
472 }
473
splt_sm_socket_handler_new(int * error)474 splt_socket_handler *splt_sm_socket_handler_new(int *error)
475 {
476 splt_socket_handler *sh = malloc(sizeof(splt_socket_handler));
477 if (sh == NULL)
478 {
479 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY;
480 return NULL;
481 }
482 memset(sh, 0x0, sizeof(splt_socket_handler));
483
484 sh->error = SPLT_OK;
485 sh->hostname = NULL;
486
487 return sh;
488 }
489
splt_sm_socket_handler_free(splt_socket_handler ** sh)490 void splt_sm_socket_handler_free(splt_socket_handler **sh)
491 {
492 if (!sh || !*sh)
493 {
494 return;
495 }
496
497 if ((*sh)->hostname)
498 {
499 free((*sh)->hostname);
500 (*sh)->hostname = NULL;
501 }
502
503 free(*sh);
504 *sh = NULL;
505 }
506
splt_sm_handle_response_and_free(char ** first_line,splt_socket_handler * sh,splt_state * state)507 static void splt_sm_handle_response_and_free(char **first_line, splt_socket_handler *sh, splt_state *state)
508 {
509 if (!first_line) { return; }
510 if (!*first_line) { return; }
511
512 if ((strstr(*first_line, "50") != NULL) ||
513 (strstr(*first_line, "40") != NULL))
514 {
515 const char *ptr = NULL;
516 if ((ptr = strchr(*first_line, ' ')))
517 {
518 splt_c_put_info_message_to_client(state, "Host response: %s\n", ptr + 1);
519 }
520 sh->error = SPLT_FREEDB_ERROR_SITE;
521 }
522
523 free(*first_line);
524 *first_line = NULL;
525 }
526
527