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