/* 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; }
/* 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; }
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; // これで終了 } }
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; }