1 /***********************************************************************
2 * network.c: network related utility functions
3 ***********************************************************************
4 * Copyright (C) 2007 metro <me_t_ro@yahoo.com>
5 *
6 * This file is part of msdl, media stream downloader
7 *
8 * network-unrelated functions goes to msdllib.c
9 *
10 * struct stream_t is a stream describer, and
11 * stream_ctrl is stream controller, actually works as a
12 * network buffer and wrapper for all supported protocols.
13 *
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
29 *
30 ***********************************************************************/
31
32
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include <errno.h>
40 #include <ctype.h>
41 #include <fcntl.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <sys/select.h>
45
46 #include <netdb.h>
47 #include <netinet/in.h>
48 #include <sys/socket.h>
49 #include <arpa/inet.h>
50
51 #include "msdl.h"
52 #include "msdllib.h"
53 #include "display.h"
54 #include "network.h"
55
56
57 /*
58 * setup stream_t
59 */
new_stream_t(void)60 struct stream_t *new_stream_t(void)
61 {
62 struct stream_t *st = (struct stream_t *)xmalloc(sizeof(struct stream_t));
63 return st;
64 }
65
66
67
68 /*
69 * free stream_t
70 */
free_stream_t(struct stream_t * st)71 void free_stream_t(struct stream_t *st)
72 {
73 if(!st) return;
74
75 free(st);
76 }
77
78
streaming_init_common()79 struct stream_t *streaming_init_common()
80 {
81 struct stream_t *stream = new_stream_t();
82
83 stream->serverinfo = new_serverinfo_t();
84 stream->netsock = new_netsock_t();
85 stream->stream_ctrl = new_stream_ctrl_t();
86 stream->resumeinfo = new_resumeinfo_t();
87
88 return stream;
89 }
90
91
streaming_close_common(struct stream_t * stream)92 void streaming_close_common(struct stream_t *stream)
93 {
94 free(stream->localfile);
95 free_resumeinfo_t(stream->resumeinfo);
96 free_stream_ctrl_t(stream->stream_ctrl);
97 free_netsock_t(stream->netsock);
98 free_serverinfo_t(stream->serverinfo);
99 free_stream_t(stream);
100 }
101
102
103 /*
104 * setup buffer, setup URL.
105 */
new_stream_ctrl_t(void)106 struct stream_ctrl_t *new_stream_ctrl_t(void)
107 {
108
109 struct stream_ctrl_t *sc =
110 (struct stream_ctrl_t *)xmalloc(sizeof(struct stream_ctrl_t));
111
112 sc->write_buffer = xmalloc(BUF_SIZE);
113 sc->write_buffer_size = BUF_SIZE;
114
115 return sc;
116 }
117
118
119
new_serverinfo_t(void)120 struct serverinfo_t *new_serverinfo_t(void)
121 {
122 struct serverinfo_t *si =
123 (struct serverinfo_t *)xmalloc(sizeof(struct serverinfo_t));
124
125 return si;
126 }
127
128
free_serverinfo_t(struct serverinfo_t * si)129 void free_serverinfo_t(struct serverinfo_t *si)
130 {
131 if(!si) return;
132
133 si->connect_host = NULL;
134 if(si->host) free(si->host);
135 if(si->proxy_host) free(si->proxy_host);
136 free(si);
137 }
138
139
140
new_netsock_t(void)141 struct netsock_t *new_netsock_t(void)
142 {
143 struct netsock_t *ns =
144 (struct netsock_t *)xmalloc(sizeof(struct netsock_t));
145 ns->buffer = xmalloc(BUF_SIZE);
146 ns->buffer_size = BUF_SIZE;
147
148 return ns;
149 }
150
151
free_netsock_t(struct netsock_t * ns)152 void free_netsock_t(struct netsock_t *ns)
153 {
154 if(!ns) return;
155
156 if(ns->buffer) free(ns->buffer);
157 free(ns);
158 }
159
160
new_resumeinfo_t(void)161 struct resumeinfo_t *new_resumeinfo_t(void)
162 {
163 struct resumeinfo_t *ri =
164 (struct resumeinfo_t *)xmalloc(sizeof(struct resumeinfo_t));
165 ri->resume_req_success = 0;
166 ri->resume_start_offset = 0;
167
168 return ri;
169 }
170
171
free_resumeinfo_t(struct resumeinfo_t * ri)172 void free_resumeinfo_t(struct resumeinfo_t *ri)
173 {
174 free(ri);
175 }
176
177
178
179 /*
180 * free stream_ctrl;
181 */
free_stream_ctrl_t(struct stream_ctrl_t * sc)182 void free_stream_ctrl_t(struct stream_ctrl_t *sc)
183 {
184 if(!sc) return;
185
186 /* if(sc->url) free_url_t(sc->url); not malloc()ed in new_stream_ctrl_t,
187 thus, free this outside free_stream_ctrl_t().*/
188 if(sc->write_buffer) free(sc->write_buffer);
189 if(sc->retry_urlstr) free(sc->retry_urlstr);
190
191 free(sc);
192 }
193
194
195
196 /*
197 * set server information
198 */
set_serverinfo(struct serverinfo_t * serverinfo,char * target_host,int target_port,char * proxy_host,int proxy_port,int protocol_default_port)199 void set_serverinfo(struct serverinfo_t *serverinfo,
200 char *target_host,int target_port,
201 char *proxy_host,int proxy_port,int protocol_default_port)
202 {
203 if(!serverinfo) {
204 display(MSDL_ERR,"set_serverinfo: argument NULL\n");
205 return;
206 }
207
208 serverinfo->host = strdup(target_host);
209 serverinfo->port = (target_port) ? target_port : protocol_default_port;
210
211 serverinfo->connect_host = serverinfo->host;
212 serverinfo->connect_port = serverinfo->port;
213
214 if(proxy_host) {
215 serverinfo->proxy_host = strdup(proxy_host);
216 serverinfo->proxy_port = proxy_port;
217
218 serverinfo->connect_host = serverinfo->proxy_host; /* reset host to connect() */
219 serverinfo->connect_port = serverinfo->proxy_port; /* reset port to connect() */
220 }
221 else {
222 serverinfo->proxy_host = NULL;
223 serverinfo->proxy_port = 0;
224 }
225 }
226
227
228
set_serverinfo_by_proxy_string(struct serverinfo_t * serverinfo,char * host,int port,char * proxy_string,int protocol_default_port,int proxy_default_port)229 void set_serverinfo_by_proxy_string(struct serverinfo_t *serverinfo,
230 char *host,int port,char *proxy_string,
231 int protocol_default_port,int proxy_default_port)
232 {
233 char *proxy_str = NULL;
234 int proxy_port = 0;
235
236 if(proxy_string) {
237 char *port_str = NULL;
238 proxy_str = strdup(proxy_string);
239 port_str = strchr(proxy_str,':');
240
241 if(!port_str) {
242 display(MSDL_NOR,"proxy port not specified, assuming %d\n",proxy_default_port);
243 proxy_port = proxy_default_port;
244 }
245 else {
246 *port_str = '\0';/* separate proxy_str*/
247 port_str++;
248 proxy_port = atoi(port_str);
249 if(!proxy_port) {
250 proxy_port = proxy_default_port;
251 }
252 }
253 }
254
255 set_serverinfo(serverinfo,host,port,proxy_str,proxy_port,protocol_default_port);
256
257 if(proxy_str) free(proxy_str);
258 }
259
260
261
262 /*
263 * str: [ npt-hh ":" npt-mm ":" ] npt-ss [ "." *DIGIT ] | [00h][00m][00s] ["." *DIGIT]
264 * create 28983 like string from many formats like "8h3m3s" or "8:3:3"
265 *
266 * return value: NULL: really inacceptable, such as "0.0a1"
267 * npt-time: rtsp npt valid string (malloc)
268 */
create_time_str_from_many_formats(const char * str,char ** reason_ret)269 char *create_time_str_from_many_formats(const char *str,char **reason_ret)
270 {
271 enum {
272 SEC = 0,
273 MIN,
274 HOUR,
275 DAY, /* joke */
276 YEAR, /* joke */
277 NUM_COLS,
278 };
279
280 enum {
281 NOT_SEPARATED = 0,
282 COLON_SEPARATED,
283 CHAR_SEPARATED,
284 };
285
286 int i = 0;
287 int j = 0; /* only to slide sep_time */
288 int len = strlen(str);
289 int sep_time_filled[NUM_COLS] = {0};
290 uint64_t sep_time[NUM_COLS] = {0}; /* separated time */
291 int separated_way = NOT_SEPARATED;
292 int met_colon = 0;
293 uint64_t value = 0;
294 int npt_acceptable = 1;
295 char *str_after_dot = "\0"; /* points to empty string by default. includes '.' itself */
296 char *npt_time = NULL;
297 char *reason = NULL;
298
299
300 value = 0;
301 met_colon = 0;
302 npt_acceptable = 1;
303 for(i = 0 ; (i < len) && npt_acceptable ; i++) {
304 if('0' <= str[i] && str[i] <= '9') {
305 value *= 10;
306 value += str[i] - '0';
307 }
308 else if(str[i] == '.') { /* just seconds, like 3323.3 */
309 char *dot_pos = (char *)str + i;
310 if((i == 0) || (i == len - 1)) { /* dot was at the beginning or end of string */
311 reason = "\'.\' at the beginning or end of string";
312 npt_acceptable = 0;
313 break;
314 }
315 i++;
316 for(; i < len ; i++) {
317 if(('0' <= str[i]) && (str[i] <= '9')) {
318 continue;
319 }
320 else {
321 reason = "invalid char after \'.\'";
322 npt_acceptable = 0;
323 break;
324 }
325 }
326 /* string after dot was valid */
327 if(npt_acceptable) {
328 str_after_dot = dot_pos;
329 }
330 }
331 else if(str[i] == ':') { /* colon can be a separator, like 3:3:2 */
332 if(separated_way == CHAR_SEPARATED) {
333 reason = "confusing time separator";
334 npt_acceptable = 0;
335 break;
336 }
337
338 separated_way = COLON_SEPARATED;
339 if(met_colon < NUM_COLS - 1) { /* separator = column = 1 */
340
341 for(j = NUM_COLS - 1; j ; j--) {
342 sep_time[j] = sep_time[j - 1]; /* slide */
343 }
344 sep_time[0] = value;
345
346 met_colon++;
347 value = 0; /* reset value */
348 continue;
349 }
350 else { /* too many colons, return */
351 reason = "too many colons";
352 npt_acceptable = 0;
353 break;
354 }
355 }
356 else if(tolower(str[i]) == 'h' || tolower(str[i]) == 'm' || tolower(str[i]) == 's' ||
357 tolower(str[i]) == 'y'|| tolower(str[i]) == 'd') { /* hour, minute, stuff */
358 if(separated_way == COLON_SEPARATED) {
359 reason = "confusing time separator";
360 npt_acceptable = 0;
361 break;
362 }
363 separated_way = CHAR_SEPARATED;
364
365 switch(tolower(str[i])) {
366 case 'y':
367 if(sep_time_filled[YEAR]) {
368 reason = "year already specified";
369 npt_acceptable = 0;
370 break;
371 }
372 sep_time[YEAR] = value;
373 sep_time_filled[YEAR] = 1;
374 break;
375 case 'd':
376 if(sep_time_filled[DAY]) {
377 reason = "day already specified";
378 npt_acceptable = 0;
379 break;
380 }
381 sep_time[DAY] = value;
382 sep_time_filled[DAY] = 1;
383 break;
384 case 'h':
385 if(sep_time_filled[HOUR]) {
386 reason = "hour already specified";
387 npt_acceptable = 0;
388 break;
389 }
390 sep_time[HOUR] = value;
391 sep_time_filled[HOUR] = 1;
392 break;
393 case 'm':
394 if(sep_time_filled[MIN]) {
395 reason = "minute already specified";
396 npt_acceptable = 0;
397 break;
398 }
399 sep_time[MIN] = value;
400 sep_time_filled[MIN] = 1;
401 break;
402 case 's':
403 if(sep_time_filled[SEC]) {
404 reason = "second already specified";
405 npt_acceptable = 0;
406 break;
407 }
408 sep_time[SEC] = value;
409 sep_time_filled[SEC] = 1;
410 break;
411 default:
412 break;
413 }
414
415 value = 0;
416 }
417 else { /* invalid chraracter */
418 reason = "invalid character";
419 npt_acceptable = 0;
420 break;
421 }
422 }
423 if(separated_way != CHAR_SEPARATED) {
424 for(j = NUM_COLS - 1; j ; j--) {
425 sep_time[j] = sep_time[j - 1]; /* slide */
426 }
427 sep_time[0] = value;
428 }
429 else { /* CHAR_SEPARATED */
430 if(!sep_time_filled[SEC]) {
431 sep_time[0] = value;
432 }
433 else if(value){ /* has some value */
434 reason = "second already specified";
435 npt_acceptable = 0;
436 }
437 }
438
439
440 if(!npt_acceptable) {
441 if(reason_ret) {
442 *reason_ret = reason;
443 }
444 return NULL;
445 }
446 else {
447 uint64_t sec = 0;
448 npt_time = xmalloc(BUFSIZE_1K + strlen(str_after_dot));
449 /* hhmmss format */
450 /*
451 sec = sep_time[SEC] % 60;
452 carry = sep_time[SEC] / 60;
453 min = (sep_time[MIN] + carry) % 60;
454 carry = (sep_time[min] + carry) / 60;
455 hour = (sep_time[YEAR] * 365 + sep_time[DAY]) * 24 + sep_time[HOUR] + carry;
456 snprintf(npt_time,BUFSIZE_1K - 1 + strlen(str_after_dot),"%llu:%d:%d.%s",
457 (long long unsigned int)hour,(int)min,(int)sec,str_after_dot);
458 */
459
460 /* sec format */
461 sec = (((sep_time[YEAR] * 365 + sep_time[DAY]) * 24 + sep_time[HOUR]) * 60 +
462 sep_time[MIN]) * 60 + sep_time[SEC];
463 snprintf(npt_time,BUFSIZE_1K - 1 + strlen(str_after_dot),"%llu%s",
464 (long long unsigned int)sec,str_after_dot);
465
466 reason = "";
467 if(reason_ret) {
468 *reason_ret = reason;
469 }
470
471 return npt_time;
472 }
473 return NULL;
474 }
475
476
477 /*
478 * return true if Speed string was valid
479 * return value ... 1: valid 0: not valid
480 * reason_ret ... "": no error some string: error reason
481 */
speed_valid_and_guess(const char * str,int * guessed_speed,char ** reason_ret)482 int speed_valid_and_guess(const char *str,int *guessed_speed,char **reason_ret)
483 {
484 /* 1*DIGIT [ "." *DIGIT ] */
485 int i = 0;
486 int len = strlen(str);
487 int speed_valid = 1;
488 char *reason = NULL;
489 int value = 0;
490
491 value = 0;
492 speed_valid = 1;
493 for(i = 0 ; i < len ; i++) {
494 if('0' <= str[i] && str[i] <= '9') {
495 value *= 10;
496 value += str[i] - '0';
497 continue;
498 }
499 else if(str[i] == '.') {
500 if(i == 0) {
501 reason = "\'.\' at the beginning of speed string";
502 speed_valid = 0;
503 break;
504 }
505 i++;
506 for(; i < len ; i++) {
507 if(('0' <= str[i]) && (str[i] <= '9')) {
508 continue;
509 }
510 else {
511 reason = "invalid char after \'.\'";
512 speed_valid = 0;
513 break;
514 }
515 }
516 }
517 else {
518 reason = "invalid character";
519 speed_valid = 0;
520 break;
521 }
522 }
523
524
525 if(speed_valid) {
526 reason = "";
527 if(reason_ret) {
528 *reason_ret = reason;
529 }
530 /* do not care about guessed_speed */
531 return speed_valid;
532 }
533
534 /* invalid */
535 if(guessed_speed) {
536 *guessed_speed = value;
537 }
538 if(reason_ret) {
539 *reason_ret = reason;
540 }
541 return 0;
542 }
543
544
545
make_byterange_from_filesize(uint64_t filesize)546 char *make_byterange_from_filesize(uint64_t filesize)
547 {
548 char *rangestr = (char *)xmalloc(256);
549 snprintf(rangestr,255,"%llu-",(long long unsigned int)filesize);
550 return rangestr;
551 }
552
553
554
555 /*
556 * (url_t)->protocol_type.
557 * sets UNKNONW_PROTOCOL if protocol string not supported.
558 */
protocol_type_from_string(char * protocol)559 int protocol_type_from_string(char *protocol)
560 {
561 int protocol_type = UNKNOWN_PROTOCOL;
562
563 if(!strcasecmp(protocol,"mms") ||
564 !strcasecmp(protocol,"mmst")) {
565 protocol_type = MMST;
566 }
567 else if(!strcasecmp(protocol,"mmsh")) {
568 protocol_type = MMSH;
569 }
570 else if(!strcasecmp(protocol,"http")) {
571 protocol_type = HTTP;
572 }
573 else if(!strcasecmp(protocol,"rtsp")) {
574 protocol_type = RTSP;
575 }
576 else if(!strcasecmp(protocol,"ftp")) {
577 protocol_type = FTP;
578 }
579 else {
580 protocol_type = UNKNOWN_PROTOCOL;
581 }
582
583 return protocol_type;
584 }
585
586 /*
587 * use default timeout value.
588 */
server_connect(const char * servername,const int port)589 int server_connect(const char *servername,const int port)
590 {
591 return (server_connect_with_timeout(servername,port,SERVER_CONNECT_TIMEOUT));
592 }
593
594
595 /*
596 * connect to 'servername' with 'port'.
597 * return value : socket number ... success
598 * -1 ... error
599 */
server_connect_with_timeout(const char * servername,const int port,const double timeout)600 int server_connect_with_timeout(const char *servername,const int port,const double timeout)
601 {
602
603 int sock_server = 0;
604 int ret;
605
606 char hoststr[INET6_ADDRSTRLEN + 4]; /* IPv4 / IPv6 dual */
607 char portstr[8];
608 fd_set set;
609 struct addrinfo hints,*result = NULL;
610
611 struct timeval tv;
612 int try_count = 0;
613
614
615 if(!servername) {
616 goto failed;
617 }
618
619 if(0 <= port && port <= 0xffff) { /* valid params */
620 snprintf(portstr,7,"%d",port);
621 }
622 else {
623 display(MSDL_ERR,"port number %d not valid",port);
624 goto failed;
625 }
626
627 memset(&hints,0,sizeof(struct addrinfo));
628 hints.ai_family = AF_UNSPEC;
629 hints.ai_socktype = SOCK_STREAM;
630
631 ret = getaddrinfo(servername,portstr,&hints,&result);
632 if(ret != 0) {
633 display(MSDL_ERR,"Host [ %s ] not found. (%s)\n",servername,gai_strerror(ret));
634 goto failed;
635 }
636
637
638 if(result->ai_family == AF_INET6) {
639 inet_ntop(result->ai_family,
640 &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
641 hoststr,
642 sizeof(hoststr));
643 }
644 else { /* default IPv4 */
645 inet_ntop(result->ai_family,
646 &((struct sockaddr_in *)result->ai_addr)->sin_addr,
647 hoststr,
648 sizeof(hoststr));
649 }
650
651 /* display host:ports */
652 display(MSDL_NOR,"Host: [ %s:%s ] ",hoststr,portstr);
653
654
655 sock_server = socket(result->ai_family,result->ai_socktype,result->ai_protocol);
656
657 if(sock_server == -1) {
658 display(MSDL_ERR,"socket() error");
659 return -1;
660 }
661
662 /* Turn the socket to non-blocking socket, so we can timeout. */
663 fcntl(sock_server,F_SETFL,fcntl(sock_server,F_GETFL) | O_NONBLOCK);
664
665 if(connect(sock_server,result->ai_addr,result->ai_addrlen) == -1) {
666 /* failed not because it was non-blocking */
667 if(errno != EINPROGRESS) {
668 display(MSDL_ERR,"connect() failed");
669 goto failed;
670 }
671 }
672
673 for(;;) { /* display "connect ... " <- dots */
674
675 tv.tv_sec = (long)(timeout / 5);
676 tv.tv_usec = (long)(((timeout / 5) - (long)(timeout /5)) * 1000000);
677
678 FD_ZERO(&set);
679 FD_SET(sock_server,&set);
680
681 ret = select(sock_server+1,NULL,&set,NULL,&tv);
682
683 if(ret < 0) { /* select failed! */
684 display(MSDL_ERR,"select() failed");
685 goto failed;
686 }
687 else if(ret > 0) break;
688 else if(try_count >= 4) { /* repeat tv.tv_sec 5 times */
689 display(MSDL_ERR,"timeout!\n");
690 goto failed;
691 }
692
693 display(MSDL_NOR,".");
694 try_count++;
695 }
696
697 /* Turn the socket to blocking, as we don't need it. */
698 fcntl(sock_server, F_SETFL, fcntl(sock_server,F_GETFL) & ~O_NONBLOCK);
699
700 display(MSDL_NOR," connected!\n");
701
702 freeaddrinfo(result);
703 return sock_server;
704
705 /* failure */
706 failed:
707 if(sock_server) close(sock_server);
708 if(result) freeaddrinfo(result);
709 return -1;
710 }
711
712
713
714
715 /*
716 * prepare listning socket opening 'port'.
717 * protocol family can be specified by 'family'
718 *
719 * return value : sock ... success
720 * -1 ... failure
721 */
waiting_socket(int family,int port)722 int waiting_socket(int family,int port)
723 {
724 int sock;
725 int ret;
726 char portstr[8];
727 struct addrinfo hints,*result = NULL;
728
729 if(port < 0 || 0xffff < port) {
730 display(MSDL_ERR,"internal: invalid port number\n");
731 goto failed;
732 }
733
734 memset(portstr,0,8);
735 snprintf(portstr,7,"%d",port);
736
737
738 memset(&hints,0,sizeof(hints));
739 hints.ai_family = family;
740 hints.ai_socktype = SOCK_STREAM;
741 hints.ai_flags = AI_PASSIVE;
742
743
744 ret = getaddrinfo(NULL,portstr,&hints,&result);
745 if(ret != 0) {
746 perror("getaddrinfo() failed");
747 goto failed;
748 }
749
750 sock = socket(result->ai_family,result->ai_socktype,result->ai_protocol);
751 if(sock < 0) {
752 perror("socket() failed");
753 goto failed;
754 }
755
756
757 ret = bind(sock,(struct sockaddr *)result->ai_addr,result->ai_addrlen);
758 if(ret < 0) {
759 perror("bind() failed");
760 goto failed;
761 }
762
763
764 ret = listen(sock,1);
765 if(ret < 0) {
766 perror("listen() failed");
767 goto failed;
768 }
769
770 freeaddrinfo(result);
771 return sock;
772
773 failed:
774 if(result) freeaddrinfo(result);
775 return -1;
776 }
777
778
779
780 /*
781 * accept connectoin from client.
782 * return value : sock .. success
783 * -1 .. failure
784 */
accept_connection(int wait_sock)785 int accept_connection(int wait_sock)
786 {
787 struct sockaddr_storage ss;
788 socklen_t sslen;
789 int sock;
790 int ret;
791
792 ret = sock_check_data(wait_sock,15);
793 if(ret <= 0) {
794 return -1;
795 }
796
797 sslen = sizeof(ss);
798 sock = accept(wait_sock,(struct sockaddr *)&ss,&sslen);
799 if(sock == -1) {
800 perror("accept() failed");
801 return -1;
802 }
803
804 return sock;
805 }
806
807
808
809 /*
810 * this is wrapper for recv, and has timeout.
811 * return value: length --> success
812 * -1 --> error/timeout
813 * 0 --> eof
814 */
xrecv(int sock,void * buf,size_t count)815 int xrecv(int sock,void *buf,size_t count)
816 {
817 fd_set fds;
818 struct timeval tv;
819 int retval;
820
821 tv.tv_sec = XRECV_TIMEOUT;
822 tv.tv_usec = 0;
823
824 FD_ZERO(&fds);
825 FD_SET(sock,&fds);
826
827 retval = select(sock + 1,&fds,NULL,NULL,&tv);
828 if(retval == -1) { /* select() Error (system call error) */
829 perror("select() failed\n");
830 goto failed;
831 }
832 else if(!retval) { /* No data arrived (error)*/
833 display(MSDL_ERR,"timeout!! could not receive data\n");
834 goto failed;
835 }
836
837 retval = recv(sock,buf,count,0);
838
839 if(retval < 0) { /* recv() Error (system call error) */
840 perror("recv() failed\n");
841 goto failed;
842 }
843
844 return retval;
845
846 failed:
847 return -1;
848 }
849
850
851
852 /*
853 * send() wrapper
854 */
xsend(int sock,void * buf,size_t count)855 int xsend(int sock,void *buf,size_t count)
856 {
857 /* ignore SIGPIPE, this means if the server has closed the connection, ignore. ret will be < 0 anyways */
858 /*int ret = send(sock,buf,count,MSG_NOSIGNAL);*/
859 int ret = send(sock,buf,count,0);
860 return ret;
861 }
862
863
864
sock_check_data(int sock,const double timeout)865 int sock_check_data(int sock,const double timeout)
866 {
867
868 fd_set fds;
869 struct timeval tv;
870 int ret;
871
872 FD_ZERO(&fds);
873 FD_SET(sock,&fds);
874
875 tv.tv_sec = (long)timeout;
876 tv.tv_usec = (long)((timeout - (long)timeout) * 1000000);
877
878 ret = select(sock + 1,&fds,NULL,NULL,&tv);
879
880 if(ret == -1) {
881 perror("stream_check_data: select() failed");
882 }
883
884 return ret;
885 }
886
887
888
stream_check_data(struct stream_t * stream,const double timeout)889 int stream_check_data(struct stream_t *stream,const double timeout)
890 {
891 if(stream->netsock->data_len) {
892 return 1;
893 }
894
895 return sock_check_data(stream->netsock->sock,timeout);
896 }
897
898
899
900 /*
901 * recv count bytes of data from sock to buf.
902 * this is only used when count bytes of data are
903 * supposed to come from sock.
904 * this function must be used when 'count' bytes are guaranteed
905 * to be received.
906 * return value: length --> success.
907 * 0 --> eof
908 * -1 --> timeout or error (fatal)
909 */
get_data(int sock,void * buf,size_t count)910 int get_data(int sock,void *buf,size_t count)
911 {
912 int len;
913 size_t total = 0;
914
915 while(total < count) { /* more data to recv. */
916
917 len = xrecv(sock,(uint8_t *)buf + total,count - total);
918
919 if(len < 0) { /* Error. timeout, syscall error */
920 goto failed;
921 }
922 else if(len == 0) { /* EOF */
923 display(MSDL_ERR,"met EOF when %d bytes are to come\n",count);
924 goto meteof;
925 }
926
927 total += len;
928 }
929
930 return total;
931
932 meteof:
933 return 0;
934
935 failed:
936 return -1;
937 }
938
939
940
941 /*
942 * read 'size' bytes from *resources*. (read JUST size bytes, otherwise fails)
943 *
944 * *resources* are : [in this order]
945 * 1. netsock->buffer (data which came with http header)
946 * 2. netsock->sock (network)
947 *
948 * return value : size which read.
949 * -1 ... error/timeout
950 */
read_data(struct stream_t * stream,void * buffer,size_t size)951 int read_data(struct stream_t *stream, void *buffer, size_t size)
952 {
953 struct netsock_t *netsock = stream->netsock;
954 int len = 0; /* how many bytes are stored in 'buffer' */
955
956 /*
957 printf("read_data size = %d netsock->data_len = %d,"
958 " netsock->buffer_pos = %d\n",
959 size,netsock->data_len, netsock->buffer_pos);
960 */
961
962 if(netsock->data_len) {
963 /* there is a data to read in netsock->buffer */
964
965 len = (size < netsock->data_len)
966 ? size : netsock->data_len; /* smaller */
967
968 memcpy((uint8_t *)buffer,netsock->buffer + netsock->buffer_pos,len);
969
970 netsock->buffer_pos += len;
971 netsock->data_len -= len;
972
973 if(netsock->data_len == 0) {
974 netsock->buffer_pos = 0;
975 }
976 }
977 if(len < size) {
978 int ret = get_data(netsock->sock,(uint8_t *)buffer + len, size - len);
979 if(ret < 0) { /* get_data mets timeout/error */
980 return -1;
981 }
982 else {
983 len += ret;
984 }
985 }
986 return len;
987 }
988
989
990
991 /*
992 * different from read_data, this function's 3ed argument is
993 * max byte to read from stream.
994 * return value: len ... bytes stored in buffer
995 * 0 ...
996 * -1 ... timeout
997 */
recv_data(struct stream_t * stream,void * buffer,size_t max)998 int recv_data(struct stream_t *stream,void *buffer,size_t max)
999 {
1000 struct netsock_t *netsock = stream->netsock;
1001 int len; /* how many bytes are stored in 'buffer' */
1002 int ret;
1003
1004 if((len = netsock->data_len)) {
1005 /* there is a data to read in netsock->buffer */
1006
1007 len = (max < len) ? max : len; /* smaller */
1008
1009 memcpy((uint8_t *)buffer,netsock->buffer + netsock->buffer_pos,len);
1010
1011 netsock->buffer_pos += len;
1012 netsock->data_len -= len;
1013
1014 if(netsock->data_len == 0) {
1015 netsock->buffer_pos = 0;
1016 }
1017 }
1018
1019 /* still network stream can be read. */
1020 if(len < max) {
1021 if(!len || sock_check_data(netsock->sock,0)) {/* just check there are some data now */
1022 ret = xrecv(netsock->sock,(uint8_t *)buffer + len,max - len);
1023 if(ret < 0) {
1024 return -1;
1025 }
1026 else {
1027 len += ret;
1028 /*
1029 when sock was shut down by server and nothing was in buffer,
1030 len == 0 and ret == 0 so return 0, this is OK.
1031 */
1032 }
1033 }
1034 }
1035 return len;
1036 }
1037
1038
1039
1040 /*
1041 * push data to netsock->buffer so that the data can be read later
1042 */
stream_data_push_back(struct stream_t * stream,void * buffer,int size)1043 int stream_data_push_back(struct stream_t *stream,void *buffer,int size)
1044 {
1045 struct netsock_t *netsock = stream->netsock;
1046
1047 if(netsock->data_len) {
1048 memmove(netsock->buffer + netsock->buffer_pos + size,
1049 netsock->buffer + netsock->buffer_pos,
1050 netsock->data_len);
1051
1052 }
1053 memcpy(netsock->buffer + netsock->buffer_pos,buffer,size);
1054 netsock->data_len += size;
1055
1056 return (netsock->data_len);
1057 }
1058
1059
1060