/*------------------------------------------------------------------------ * int ttp_open_transfer(ttp_session_t *session); * * Tries to create a new TTP file request object for the given session * by reading the name of a requested file from the client. If we are * able to negotiate the transfer successfully, we return 0. If we * can't negotiate the transfer because of I/O or file errors, we * return a negative vlaue. * * The client is sent a result byte of 0 if the request is accepted * (because the file can be read) and a non-zero result byte otherwise. *------------------------------------------------------------------------*/ int ttp_open_transfer(ttp_session_t *session) { char filename[MAX_FILENAME_LENGTH]; /* the name of the file to transfer */ u_int64_t file_size; /* network-order version of file size */ u_int32_t block_size; /* network-order version of block size */ u_int32_t block_count; /* network-order version of block count */ time_t epoch; int status; ttp_transfer_t *xfer = &session->transfer; ttp_parameter_t *param = session->parameter; #ifdef VSIB_REALTIME /* VLBI/VSIB-related variables */ struct evn_filename *ef; double starttime; struct timeval d; #endif char size[10]; char file_no[10]; char message[20]; u_int16_t i; struct timeval ping_s, ping_e; /* clear out the transfer data */ memset(xfer, 0, sizeof(*xfer)); /* read in the requested filename */ status = read_line(session->client_fd, filename, MAX_FILENAME_LENGTH); if (status < 0) error("Could not read filename from client"); filename[MAX_FILENAME_LENGTH - 1] = '\0'; if(!strcmp(filename, TS_DIRLIST_HACK_CMD)) { /* The client requested listing of files and their sizes (dir command) * Send strings: NNN \0 name1 \0 len1 \0 nameN \0 lenN \0 */ snprintf(file_no, sizeof(file_no), "%u", param->total_files); full_write(session->client_fd, file_no, strlen(file_no)+1); for(i=0; i<param->total_files; i++) { full_write(session->client_fd, param->file_names[i], strlen(param->file_names[i])+1); snprintf(message, sizeof(message), "%Lu", (ull_t)(param->file_sizes[i])); full_write(session->client_fd, message, strlen(message)+1); } full_read(session->client_fd, message, 1); return warn("File list sent!"); } else if(!strcmp(filename,"*")) { if(param->allhook != 0) { /* execute the provided program on server side to see what files * should be gotten */ const int MaxFileListLength = 32768; char fileList[MaxFileListLength]; const char *fl; int nFile = 0; int length = 0; int l; FILE *p; fprintf(stderr, "Using allhook program: %s\n", param->allhook); p = popen((char *)(param->allhook), "r"); if(p) { memset(fileList, 0, MaxFileListLength); while(1) { if(fgets(message, sizeof(message), p) == 0) break; /* get lenght of string and strip non printable chars */ for(l = 0; message[l] >= ' '; ++l) {} message[l] = 0; fprintf(stdout, " '%s'\n", message); if(l + length >= MaxFileListLength) break; strncpy(fileList + length, message, l); length += l + 1; ++nFile; } } pclose(p); memset(size, 0, sizeof(size)); snprintf(size, sizeof(size), "%u", length); full_write(session->client_fd, size, 10); memset(file_no, 0, sizeof(file_no)); snprintf(file_no, sizeof(file_no), "%u", nFile); full_write(session->client_fd, file_no, 10); printf("\nSent multi-GET filename count and array size to client\n"); memset(message, 0, sizeof(message)); full_read(session->client_fd, message, 8); printf("Client response: %s\n", message); fl = fileList; if(nFile > 0) { for(i=0; i<nFile; i++) { l = strlen(fl); full_write(session->client_fd, fl, l+1); fl += l+1; } memset(message, 0, sizeof(message)); full_read(session->client_fd, message, 8); printf("Sent file list, client response: %s\n", message); status = read_line(session->client_fd, filename, MAX_FILENAME_LENGTH); if (status < 0) error("Could not read filename from client"); } } else { /* A multiple file request - sent the file names first, * and next the client requests a download of each in turn (get * command) */ memset(size, 0, sizeof(size)); snprintf(size, sizeof(size), "%u", param->file_name_size); full_write(session->client_fd, size, 10); memset(file_no, 0, sizeof(file_no)); snprintf(file_no, sizeof(file_no), "%u", param->total_files); full_write(session->client_fd, file_no, 10); printf("\nSent multi-GET filename count and array size to client\n"); memset(message, 0, sizeof(message)); full_read(session->client_fd, message, 8); printf("Client response: %s\n", message); for(i=0; i<param->total_files; i++) full_write(session->client_fd, param->file_names[i], strlen(param->file_names[i])+1); memset(message, 0, sizeof(message)); full_read(session->client_fd, message, 8); printf("Sent file list, client response: %s\n", message); status = read_line(session->client_fd, filename, MAX_FILENAME_LENGTH); if (status < 0) error("Could not read filename from client"); } } /* store the filename in the transfer object */ xfer->filename = strdup(filename); if (xfer->filename == NULL) return warn("Memory allocation error"); /* make a note of the request */ if (param->verbose_yn) printf("Request for file: '%s'\n", filename); #ifndef VSIB_REALTIME /* try to open the file for reading */ xfer->file = fopen(filename, "r"); if (xfer->file == NULL) { sprintf(g_error, "File '%s' does not exist or cannot be read", filename); /* signal failure to the client */ status = full_write(session->client_fd, "\x008", 1); if (status < 0) warn("Could not signal request failure to client"); return warn(g_error); } #else /* get starting time (UTC) and detect whether local disk copy is wanted */ if (strrchr(filename,'/') == NULL) { ef = parse_evn_filename(filename); /* attempt to parse */ param->fileout = 0; } else { ef = parse_evn_filename(strrchr(filename, '/')+1); /* attempt to parse */ param->fileout = 1; } if (!ef->valid) { fprintf(stderr, "Warning: EVN filename parsing failed, '%s' not following EVN File Naming Convention?\n", filename); } /* get time multiplexing info from EVN filename (currently these are all unused) */ if (get_aux_entry("sl",ef->auxinfo, ef->nr_auxinfo) == 0) param->totalslots= 1; /* default to 1 */ else sscanf(get_aux_entry("sl",ef->auxinfo, ef->nr_auxinfo), "%d", &(param->totalslots)); if (get_aux_entry("sn",ef->auxinfo, ef->nr_auxinfo) == 0) param->slotnumber= 1; /* default to 1 */ else sscanf(get_aux_entry("sn",ef->auxinfo, ef->nr_auxinfo), "%d", ¶m->slotnumber); if (get_aux_entry("sr",ef->auxinfo, ef->nr_auxinfo) == 0) param->samplerate= 512; /* default to 512 Msamples/s */ else sscanf(get_aux_entry("sr",ef->auxinfo, ef->nr_auxinfo), "%d", ¶m->samplerate); /* try to open the vsib for reading */ xfer->vsib = fopen("/dev/vsib", "r"); if (xfer->vsib == NULL) { sprintf(g_error, "VSIB board does not exist in /dev/vsib or it cannot be read"); status = full_write(session->client_fd, "\002", 1); if (status < 0) { warn("Could not signal request failure to client"); } return warn(g_error); } /* try to open the local disk copy file for writing */ if (param->fileout) { xfer->file = fopen(filename, "wb"); if (xfer->file == NULL) { sprintf(g_error, "Could not open local file '%s' for writing", filename); status = full_write(session->client_fd, "\x010", 1); if (status < 0) { warn("Could not signal request failure to client"); } fclose(xfer->vsib); return warn(g_error); } } /* Start half a second before full UTC seconds change. If EVN filename date/time parse failed, start immediately. */ if (!(NULL == ef->data_start_time_ascii || ef->data_start_time <= 1.0)) { u_int64_t timedelta_usec; starttime = ef->data_start_time - 0.5; assert( gettimeofday(&d, NULL) == 0 ); timedelta_usec = (unsigned long)((starttime - (double)d.tv_sec)* 1000000.0) - (double)d.tv_usec; fprintf(stderr, "Sleeping until specified time (%s) for %Lu usec...\n", ef->data_start_time_ascii, (ull_t)timedelta_usec); usleep_that_works(timedelta_usec); } /* Check if the client is still connected after the long(?) wait */ //if(recv(session->client_fd, &status, 1, MSG_PEEK)<0) { // // connection has terminated, exit // fclose(xfer->vsib); // return warn("The client disconnected while server was sleeping."); //} /* start at next 1PPS pulse */ start_vsib(session); #endif // end of VSIB_REALTIME section /* begin round trip time estimation */ gettimeofday(&ping_s,NULL); /* try to signal success to the client */ status = full_write(session->client_fd, "\000", 1); if (status < 0) return warn("Could not signal request approval to client"); /* read in the block size, target bitrate, and error rate */ if (full_read(session->client_fd, ¶m->block_size, 4) < 0) return warn("Could not read block size"); param->block_size = ntohl(param->block_size); if (full_read(session->client_fd, ¶m->target_rate, 4) < 0) return warn("Could not read target bitrate"); param->target_rate = ntohl(param->target_rate); if (full_read(session->client_fd, ¶m->error_rate, 4) < 0) return warn("Could not read error rate"); param->error_rate = ntohl(param->error_rate); /* end round trip time estimation */ gettimeofday(&ping_e,NULL); /* read in the slowdown and speedup factors */ if (full_read(session->client_fd, ¶m->slower_num, 2) < 0) return warn("Could not read slowdown numerator"); param->slower_num = ntohs(param->slower_num); if (full_read(session->client_fd, ¶m->slower_den, 2) < 0) return warn("Could not read slowdown denominator"); param->slower_den = ntohs(param->slower_den); if (full_read(session->client_fd, ¶m->faster_num, 2) < 0) return warn("Could not read speedup numerator"); param->faster_num = ntohs(param->faster_num); if (full_read(session->client_fd, ¶m->faster_den, 2) < 0) return warn("Could not read speedup denominator"); param->faster_den = ntohs(param->faster_den); #ifndef VSIB_REALTIME /* try to find the file statistics */ fseeko(xfer->file, 0, SEEK_END); param->file_size = ftello(xfer->file); fseeko(xfer->file, 0, SEEK_SET); #else /* get length of recording in bytes from filename */ if (get_aux_entry("flen", ef->auxinfo, ef->nr_auxinfo) != 0) { sscanf(get_aux_entry("flen", ef->auxinfo, ef->nr_auxinfo), "%" SCNu64, (u_int64_t*) &(param->file_size)); } else if (get_aux_entry("dl", ef->auxinfo, ef->nr_auxinfo) != 0) { sscanf(get_aux_entry("dl", ef->auxinfo, ef->nr_auxinfo), "%" SCNu64, (u_int64_t*) &(param->file_size)); } else { param->file_size = 60LL * 512000000LL * 4LL / 8; /* default to amount of bytes equivalent to 4 minutes at 512Mbps */ } fprintf(stderr, "Realtime file length in bytes: %Lu\n", (ull_t)param->file_size); #endif param->block_count = (param->file_size / param->block_size) + ((param->file_size % param->block_size) != 0); param->epoch = time(NULL); /* reply with the length, block size, number of blocks, and run epoch */ file_size = tsunami_htonll(param->file_size); if (full_write(session->client_fd, &file_size, 8) < 0) return warn("Could not submit file size"); block_size = htonl (param->block_size); if (full_write(session->client_fd, &block_size, 4) < 0) return warn("Could not submit block size"); block_count = htonl (param->block_count); if (full_write(session->client_fd, &block_count, 4) < 0) return warn("Could not submit block count"); epoch = htonl (param->epoch); if (full_write(session->client_fd, &epoch, 4) < 0) return warn("Could not submit run epoch"); /*calculate and convert RTT to u_sec*/ session->parameter->wait_u_sec=(ping_e.tv_sec - ping_s.tv_sec)*1000000+(ping_e.tv_usec-ping_s.tv_usec); /*add a 10% safety margin*/ session->parameter->wait_u_sec = session->parameter->wait_u_sec + ((int)(session->parameter->wait_u_sec* 0.1)); /* and store the inter-packet delay */ param->ipd_time = (u_int32_t) ((1000000LL * 8 * param->block_size) / param->target_rate); xfer->ipd_current = param->ipd_time * 3; /* if we're doing a transcript */ if (param->transcript_yn) xscript_open(session); /* we succeeded! */ return 0; }
/*------------------------------------------------------------------------ * int ttp_open_transfer(ttp_session_t *session, * const char *remote_filename, * const char *local_filename); * * Tries to create a new TTP file request object for the given session * by submitting a file request to the server (which is waiting for * the name of a file to transfer). If the request is accepted, we * retrieve the file parameters, open the file for writing, and return * 0 for success. If anything goes wrong, we return a non-zero value. *------------------------------------------------------------------------*/ int ttp_open_transfer(ttp_session_t *session, const char *remote_filename, const char *local_filename) { u_char result; /* the result byte from the server */ u_int32_t temp; /* used for transmitting 32-bit values */ u_int16_t temp16; /* used for transmitting 16-bit values */ int status; ttp_transfer_t *xfer = &session->transfer; ttp_parameter_t *param = session->parameter; /* submit the transfer request */ status = fprintf(session->server, "%s\n", remote_filename); if ((status <= 0) || fflush(session->server)) return warn("Could not request file"); /* see if the request was successful */ status = fread(&result, 1, 1, session->server); if (status < 1) return warn("Could not read response to file request"); /* make sure the result was a good one */ if (result != 0) return warn("Server: File does not exist or cannot be transmitted"); /* Submit the block size, target bitrate, and maximum error rate */ temp = htonl(param->block_size); if (fwrite(&temp, 4, 1, session->server) < 1) return warn("Could not submit block size"); temp = htonl(param->target_rate); if (fwrite(&temp, 4, 1, session->server) < 1) return warn("Could not submit target rate"); temp = htonl(param->error_rate); if (fwrite(&temp, 4, 1, session->server) < 1) return warn("Could not submit error rate"); if (fflush(session->server)) return warn("Could not flush control channel"); /* submit the slower and faster factors */ temp16 = htons(param->slower_num); if (fwrite(&temp16, 2, 1, session->server) < 1) return warn("Could not submit slowdown numerator"); temp16 = htons(param->slower_den); if (fwrite(&temp16, 2, 1, session->server) < 1) return warn("Could not submit slowdown denominator"); temp16 = htons(param->faster_num); if (fwrite(&temp16, 2, 1, session->server) < 1) return warn("Could not submit speedup numerator"); temp16 = htons(param->faster_den); if (fwrite(&temp16, 2, 1, session->server) < 1) return warn("Could not submit speedup denominator"); if (fflush(session->server)) return warn("Could not flush control channel"); /* populate the fields of the transfer object */ memset(xfer, 0, sizeof(*xfer)); xfer->remote_filename = remote_filename; xfer->local_filename = local_filename; /* read in the file length, block size, block count, and run epoch */ if (fread(&xfer->file_size, 8, 1, session->server) < 1) return warn("Could not read file size"); xfer->file_size = ntohll(xfer->file_size); if (fread(&temp, 4, 1, session->server) < 1) return warn("Could not read block size"); if (htonl(temp) != param->block_size) return warn("Block size disagreement"); if (fread(&xfer->block_count, 4, 1, session->server) < 1) return warn("Could not read number of blocks"); xfer->block_count = ntohl (xfer->block_count); if (fread(&xfer->epoch, 4, 1, session->server) < 1) return warn("Could not read run epoch"); xfer->epoch = ntohl (xfer->epoch); /* we start out with every block yet to transfer */ xfer->blocks_left = xfer->block_count; /* try to open the local file for writing */ if (!access(xfer->local_filename, F_OK)) printf("Warning: overwriting existing file '%s'\n", local_filename); xfer->file = fopen(xfer->local_filename, "wb"); if (xfer->file == NULL) { char * trimmed = rindex(xfer->local_filename, '/'); if ((trimmed != NULL) && (strlen(trimmed)>1)) { printf("Warning: could not open file %s for writing, trying local directory instead.\n", xfer->local_filename); xfer->local_filename = trimmed + 1; if (!access(xfer->local_filename, F_OK)) printf("Warning: overwriting existing file '%s'\n", xfer->local_filename); xfer->file = fopen(xfer->local_filename, "wb"); } if(xfer->file == NULL) { return warn("Could not open local file for writing"); } } #ifdef VSIB_REALTIME /* try to open the vsib for output */ xfer->vsib = fopen("/dev/vsib", "wb"); if (xfer->vsib == NULL) return warn("VSIB board does not exist in /dev/vsib or it cannot be read"); /* pre-reserve the ring buffer */ param->ringbuf = malloc(param->block_size * RINGBUF_BLOCKS); if (param->ringbuf == NULL) return warn("Could not reserve space for ring buffer"); #endif /* make crude estimate of blocks on the wire if RTT delay is 500ms */ xfer->on_wire_estimate = (u_int32_t)(0.5 * param->target_rate/(8*param->block_size)); xfer->on_wire_estimate = min(xfer->block_count, xfer->on_wire_estimate); /* if we're doing a transcript */ if (param->transcript_yn) xscript_open(session); /* indicate success */ return 0; }