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