Пример #1
0
/* The purpose of this function is to provide a version of connect()
 * that does not ignore timeouts... */
static int do_connect(const struct addrinfo *addrinfo,
	struct timeval *timeout)
{
	int ret, error;
	socklen_t len;
	fd_set set;
	int fd;

	fd = socket(addrinfo->ai_family, addrinfo->ai_socktype | SOCK_CLOEXEC, 0);
	if (fd < 0)
		return -errno;

	FD_ZERO(&set);
	FD_SET(fd, &set);

	ret = set_blocking_mode(fd, false);
	if (ret < 0) {
		close(fd);
		return ret;
	}

	ret = connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen);
	if (ret < 0 && errno != EINPROGRESS) {
		ret = -errno;
		goto end;
	}

	ret = select(fd + 1, &set, &set, NULL, timeout);
	if (ret < 0) {
		ret = -errno;
		goto end;
	}
	if (ret == 0) {
		ret = -ETIMEDOUT;
		goto end;
	}

	/* Verify that we don't have an error */
	len = sizeof(error);
	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
	if(ret < 0) {
		ret = -errno;
		goto end;
	}
	if (error) {
		ret = -error;
		goto end;
	}

end:
	/* Restore blocking mode */
	set_blocking_mode(fd, true);
	if (ret < 0) {
		close(fd);
		return ret;
	}

	return fd;
}
Пример #2
0
/* The purpose of this function is to provide a version of connect()
 * that does not ignore timeouts... */
static int do_connect(int fd, const struct sockaddr *addr,
		socklen_t addrlen, struct timeval *timeout)
{
	int ret, error;
	socklen_t len;
	fd_set set;

	FD_ZERO(&set);
	FD_SET(fd, &set);

	ret = set_blocking_mode(fd, false);
	if (ret < 0)
		return ret;

	ret = connect(fd, addr, addrlen);
	if (ret < 0 && errno != EINPROGRESS) {
		ret = -errno;
		goto end;
	}

	ret = select(fd + 1, &set, &set, NULL, timeout);
	if (ret < 0) {
		ret = -errno;
		goto end;
	}
	if (ret == 0) {
		ret = -ETIMEDOUT;
		goto end;
	}

	/* Verify that we don't have an error */
	len = sizeof(error);
	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
	if(ret < 0) {
		ret = -errno;
		goto end;
	}
	if (error) {
		ret = -error;
		goto end;
	}

end:
	/* Restore blocking mode */
	set_blocking_mode(fd, true);
	return ret;
}
Пример #3
0
static int next_file(int *in_fd_p, JOINT_FILE_INFO_T *joint_file_info_p)
{
	off_t	ret;

	if (in_fd_p && joint_file_info_p)
	{
		// 読み終わったファイルをCLOSE()
		debug_log_output("[%02d] '%s' close()", joint_file_info_p->current_file_num, joint_file_info_p->file[joint_file_info_p->current_file_num].name);
		close(*in_fd_p);

		// 次のファイルがあるか?
		joint_file_info_p->current_file_num++;
		if ( joint_file_info_p->current_file_num >= joint_file_info_p->file_num )
		{
			debug_log_output("EOF Detect.");
			//printf("EOF Detect.");
			return 1;		// これで終了
		}

		// 次のファイルをOPEN()
		debug_log_output("[%02d] '%s' open(), start_pos %lld\n", joint_file_info_p->current_file_num, joint_file_info_p->file[joint_file_info_p->current_file_num].name, joint_file_info_p->file[joint_file_info_p->current_file_num].start_pos);
		//printf("[%02d] '%s' open(), start_pos %lld, size %lld\n",
		//	joint_file_info_p->current_file_num,
		//	joint_file_info_p->file[joint_file_info_p->current_file_num].name,
		//	joint_file_info_p->file[joint_file_info_p->current_file_num].start_pos,
		//	joint_file_info_p->file[joint_file_info_p->current_file_num].size
		//	);

		*in_fd_p = open(joint_file_info_p->file[joint_file_info_p->current_file_num].name, O_RDONLY);
		if ( *in_fd_p < 0 )
		{
			debug_log_output("errno = %s\n", strerror(errno));
			debug_log_output("open() error. '%s'", joint_file_info_p->file[joint_file_info_p->current_file_num].name);
			return ( -1 );
		}

		ret = lseek(*in_fd_p, joint_file_info_p->file[joint_file_info_p->current_file_num].start_pos, SEEK_SET);

		debug_log_output("seek to %lld returned %lld\n", joint_file_info_p->file[joint_file_info_p->current_file_num].start_pos, ret);
		//printf("seek to %lld returned %lld\n", joint_file_info_p->file[joint_file_info_p->current_file_num].start_pos, ret);

		// ブロックモードの設定
		set_blocking_mode(*in_fd_p, 0);	/* blocking */

		return 0;		// 次のファイルの準備完了
	} else {
		// パラメータがNULLの場合には1ファイルのみの処理とする
		return 1;		// これで終了
	}
}
Пример #4
0
off_t copy_descriptors(int in_fd, int out_fd, off_t content_length, JOINT_FILE_INFO_T *joint_file_info_p)
{
	int i;
	struct _buff {
		int inuse;
		int pos;
		int len;
		unsigned char *p;
	} *buff;
	unsigned char *p;
	int read_idx = 0;
	int write_idx = 0;
	int idx_count = 0;
	off_t read_cnt = 0;

	off_t			total_read_size = 0;
	size_t			target_read_size;
	int				len;

	int flag_finish = 0;
	int flag_first_time = 0;
	int flag_verbose = 0;
	time_t first_timeout = 0;
	off_t written = 0;
	
	struct timeb marker1,marker2; //,marker3;
	int marker_count;

	if(global_param.buffer_size < 1) global_param.buffer_size = 1;
	if(global_param.stream_chunk_size < 512) global_param.stream_chunk_size = 512;

	ssize_t blocks_read = 0;
	int offset = 0;
	if (joint_file_info_p) offset = joint_file_info_p->iso_seek;
	
	// ======================
	// 送信バッファを確保
	// ======================

	debug_log_output("Allocating %d buffers of %d bytes each\n", global_param.buffer_size, global_param.stream_chunk_size);

	buff = malloc(global_param.buffer_size * sizeof(struct _buff));
	if ( buff == NULL )
	{
		debug_log_output("malloc() error.\n");
		return (-1 );
	}
	p = malloc(global_param.buffer_size * global_param.stream_chunk_size);
	if ( p == NULL )
	{
		debug_log_output("malloc() error.\n");
		return ( 0 );
	}
	for (i=0; i<global_param.buffer_size; i++) {
		buff[i].pos = 0;
		buff[i].inuse = 0;
		buff[i].len = 0;
		buff[i].p = p + i*global_param.stream_chunk_size;
	}

	// ブロックモードの設定
	//set_blocking_mode(in_fd, 0);	/* blocking */
	set_blocking_mode(out_fd, (global_param.buffer_size>1));	/* non-blocking if multiple buffers */
	//debug_log_output("set non-blocking mode");

	// Do the calculation this way so global_param.buffer_size<4 always gets flag_first_time
	//No, don't force this!!!  :  if (content_length < global_param.stream_chunk_size * (global_param.buffer_size>>2)) flag_first_time = 1;
	if (global_param.buffer_size < 4) flag_first_time = 1;
	// If only one buffer, then we work the same as the http_simple_file_send()
	if (global_param.buffer_size == 1) global_param.flag_buffer_send_asap = 1;

	ftime(&marker1);
	marker_count = 0;

	first_timeout = time(NULL);
	// ================
	// 実体転送開始
	// ================
	while ( flag_finish < 2 )
	{
		struct timeval tv;
		fd_set writefds;

		if (flag_first_time == 0 && first_timeout + 13 <= time(NULL)) {
				debug_log_output( 
				   "****************************************************\n"
				   "**  Low bandwidth? send it anyway...              **\n"
				   "****************************************************");
				flag_first_time = 1;
		}
		if (flag_finish || flag_first_time || (idx_count >= (global_param.buffer_size-2))) 
		{
			if (flag_first_time == 0) {
				debug_log_output( 
				   "*********************************************************\n"
				   "**                    CACHE FILLED!                    **\n"
				   "*********************************************************");
				flag_first_time = 1;
			}
			while(buff[write_idx].inuse) {
				// If there is nothing more to read, concentrate on writing
				FD_ZERO(&writefds);
				FD_SET(out_fd, &writefds);
				tv.tv_sec = 0;
				if (flag_finish == 0 && !buff[read_idx].inuse) {
					// Don't wait for the select because we have room to read
					tv.tv_usec = 0;
				} else {
					tv.tv_usec = 100000; // 100msec maximum wait = 10Hz polling rate
				}
//ftime(&marker2);
				i = select(FD_SETSIZE, NULL, &writefds, NULL, &tv);
//ftime(&marker3);
//len = (marker3.time-marker2.time)*1000 + (marker3.millitm-marker2.millitm);
//if(len>9) fputc('0'+len/10, stderr);
				if (i < 0) {
					// Select returned an error - socket must be closed
					debug_log_output("select failed. err = %s", strerror(errno));
					flag_finish = 2;
					break;
				} else if(i > 0) {
//ftime(&marker2);
					len = write(out_fd, buff[write_idx].p + buff[write_idx].pos,
						(buff[write_idx].len < global_param.socket_chunk_size) ? buff[write_idx].len : global_param.socket_chunk_size );
//ftime(&marker3);
//i = (marker3.time-marker2.time)*1000 + (marker3.millitm-marker2.millitm);
//if(i>9) fputc('a'+i/10, stderr);
					if(len > 0) {
//fputc('.', stderr);
						written += len;
						buff[write_idx].len -= len;

						marker_count += len;
						if(!global_param.flag_daemon && (marker_count > 2000000)) {
							// Display the network transfer rate
							double rate;
							ftime(&marker2);
							rate = (marker2.time-marker1.time) + 0.001*(marker2.millitm-marker1.millitm);
							if(rate > 0) {
								rate = 8e-6 * marker_count / rate;
								/* fprintf(stderr, "%g Mbps\n", rate); */
							}
							marker1 = marker2;
							marker_count = 0;
						}

						if (flag_verbose) {
							debug_log_output("sent: len =%6d, idx = %4d, idxcount = %4d", len, write_idx, idx_count);
						} else if(0 && !global_param.flag_daemon) {
							show_progress(idx_count * 100 / global_param.buffer_size, idx_count);
						}
						if (buff[write_idx].len <= 0) {
							buff[write_idx].inuse = 0;
							buff[write_idx].len = 0;
							buff[write_idx].pos = 0;
							write_idx = (write_idx + 1) % global_param.buffer_size;
							idx_count --;
						} else {
							buff[write_idx].pos += len;
						}
					} else {
//fputc('-', stderr);
						// Failed to write - end the stream
						if (len < 0) {
							if(errno == EAGAIN) {
								debug_log_output("write would block");
								break;
							}
							debug_log_output("write failed after %d bytes. err = %s (%d)", written, strerror(errno), (int)errno);
						} else {
							debug_log_output("socket closed by player");
						}
						flag_finish = 2;
						break;
					}
				} else {
					// Not ready to write, exit from the loop to do a read
//if (flag_finish == 0 && !buff[read_idx].inuse) {
//	fputc(',', stderr);
//} else {
//	fputc('o', stderr);
//}
					break;
				}
			}
			if((flag_finish==1) && !buff[write_idx].inuse) {
				flag_finish = 2;
				debug_log_output(
				   "*********************************************************\n"
				   "**                    SEND FINISHED!                   **\n"
				   "*********************************************************");
			}
		}
		// Always attempt a read if we have a buffer available
		//if (FD_ISSET(in_fd, &readfds)) {
		if(flag_finish == 0 && !buff[read_idx].inuse) {
			// target_read_size = (content_length - total_read_size) > 1024 ? 1024 : (content_length - total_read_size);
			target_read_size = global_param.stream_chunk_size - buff[read_idx].len;
/*
			if (buff[read_idx].p == NULL) {
				debug_log_output("error! idx: %d", read_idx);
			}
*/
ftime(&marker2);
			if ((joint_file_info_p!=NULL) && (joint_file_info_p->dvd_file != NULL)) {
				blocks_read = DVDReadBlocks(joint_file_info_p->dvd_file, offset, target_read_size/2048, buff[read_idx].p + buff[read_idx].len); 
				len = (off_t)blocks_read*2048;
				offset += blocks_read;
			} else if (joint_file_info_p && read_cnt >= joint_file_info_p->file[joint_file_info_p->current_file_num].size) {
				len = 0;
				read_cnt = 0;
				debug_log_output("finished file chunk %d\n", joint_file_info_p->current_file_num);
				//printf("finished file chunk %d\n", joint_file_info_p->current_file_num);
			} else {
				if (joint_file_info_p && target_read_size + read_cnt > joint_file_info_p->file[joint_file_info_p->current_file_num].size) {
					target_read_size = joint_file_info_p->file[joint_file_info_p->current_file_num].size - read_cnt;
					debug_log_output("finishing last block of %d\n", joint_file_info_p->current_file_num);
					//printf("finishing last block of %d\n", joint_file_info_p->current_file_num);
				}

				len = read(in_fd, buff[read_idx].p + buff[read_idx].len, target_read_size);
				read_cnt += len;
			}
//ftime(&marker3);
//i = (marker3.time-marker2.time)*1000 + (marker3.millitm-marker2.millitm);
//if(i>9) fputc('A'+i/10, stderr);
			if(len == 0) {
				if(    (joint_file_info_p==NULL)
					|| (joint_file_info_p->dvd_file != NULL)
					|| next_file(&in_fd, joint_file_info_p)) {
					// 読み込み終わり
					flag_finish = 1;
					if (flag_verbose) {
						debug_log_output("recv: len = %d, idx = %d finish!", len, read_idx);
					} else {
						debug_log_output(
					   "*********************************************************\n"
					   "**                    RECV FINISHED!                   **\n"
					   "*********************************************************");
					}
					if (buff[read_idx].len > 0) {
						buff[read_idx].inuse = 1;
						buff[read_idx].pos = 0;
					}
				} else {
					// 次のファイルに続く(ここでは何もしない)
				}
			} else if (len > 0) {
//fputc(':', stderr);
				if (flag_verbose) {
					debug_log_output("recv: len =%6d, idx = %4d, idxcount = %4d", len, read_idx, idx_count);
				} else if(0 && !global_param.flag_daemon) {
					show_progress(idx_count * 100 / global_param.buffer_size, idx_count);
				}
				buff[read_idx].len += len;
				total_read_size += len;

				if (global_param.flag_buffer_send_asap == TRUE
				|| buff[read_idx].len >= global_param.stream_chunk_size) {
					buff[read_idx].inuse = 1;
					buff[read_idx].pos = 0;
					idx_count ++;
					read_idx = (read_idx + 1) % global_param.buffer_size;
				}
/*
				if (content_length - total_read_size <= 0) {
					flag_finish = 1;
				}
*/
			} else {
				flag_finish = 1;
				if (flag_verbose) {
					debug_log_output("read err?: len = %d, idx = %d, err: %s", len, read_idx, strerror(errno));
				} else {
					debug_log_output(
				   "*********************************************************\n"
				   "**                    RECV FINISHED!(ret = %d)          **\n"
				   "*********************************************************", len);
				}
			}
		}
	}

	free(p);
	free(buff);	// Memory Free.
	debug_log_output("copy descriptors end.");

	// 正常終了
	return written;
}