/* TPRX.C (c) 1996 by Oliver Kraus */ #include #include #include #include #include #include #include "cio.h" #include "tprx.h" #include "crc16.h" #include "crc32.h" /* #include "debugmem.h" */ #define TPRX_ID_STR "receiver: " char *tprx_es_ipx_not_found = TPRX_ID_STR "ipx not found"; char *tprx_es_socket_table_full = TPRX_ID_STR "socket table full"; char *tprx_es_socket_open = TPRX_ID_STR "socket already open"; char *tprx_es_out_of_memory = TPRX_ID_STR "out of memory"; /* - - - - - state prototypes - - - - - - - - - - - - - - - - - - - - - - */ void tprx_state_none(tprx_type tprx); void tprx_state_gen_ack_request(tprx_type tprx); void tprx_state_chk_ack_request(tprx_type tprx); void tprx_state_user_check(tprx_type tprx); void tprx_state_gen_file_start(tprx_type tprx); void tprx_state_chk_file_start(tprx_type tprx); void tprx_state_wait_file_start(tprx_type tprx); void tprx_state_gen_ack_file_start(tprx_type tprx); void tprx_state_chk_ack_file_start(tprx_type tprx); void tprx_state_wait_block_start(tprx_type tprx); void tprx_state_gen_ack_block_start(tprx_type tprx); void tprx_state_chk_ack_block_start(tprx_type tprx); void tprx_state_wait_data(tprx_type tprx); void tprx_state_gen_missed_blocks(tprx_type tprx); void tprx_state_chk_missed_blocks(tprx_type tprx); void tprx_state_gen_ack_block_end(tprx_type tprx); void tprx_state_chk_ack_block_end(tprx_type tprx); void tprx_state_gen_ack_file_end(tprx_type tprx); void tprx_state_chk_ack_file_end(tprx_type tprx); void tprx_state_none2(tprx_type tprx); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* allocate pool memory */ int tprx_OpenPool(tprx_type tprx, size_t b_len, int b_cnt) { int i; /* check against 16 bit system */ if ( (long)b_len*(long)b_cnt > 65500 ) return 1; /* assign parameter */ tprx->b_len = b_len; tprx->b_cnt = b_cnt; tprx->rx_cnt = b_cnt+TPRX_RX_ADD; tprx->b_pool_size = b_cnt*b_len; /* data buffers for ipx listen process */ tprx->rx_data = (char **)malloc(tprx->rx_cnt*sizeof(char *)); if ( tprx->rx_data != NULL ) { for( i = 0; i < tprx->rx_cnt; i++ ) tprx->rx_data[i] = (char *)malloc(tprx->b_len+TP_BLK_INFO_SIZE); for( i = 0; i < tprx->rx_cnt; i++ ) if ( tprx->rx_data[i] == NULL ) break; if ( i >= tprx->rx_cnt ) { /* allocate ipx ecb data buffers */ tprx->rx_ecb = (ipx_ecb_struct **)malloc(tprx->rx_cnt*sizeof(ipx_ecb_struct *)); if ( tprx->rx_ecb != NULL ) { for( i = 0; i < tprx->rx_cnt; i++ ) tprx->rx_ecb[i] = (ipx_ecb_struct *)malloc(sizeof(ipx_ecb_struct)); for( i = 0; i < tprx->rx_cnt; i++ ) if ( tprx->rx_ecb[i] == NULL ) break; if ( i >= tprx->rx_cnt ) { /* clear ecb buffers */ for( i = 0; i < tprx->rx_cnt; i++ ) { tprx->rx_ecb[i]->inuse = 0; tprx->rx_ecb[i]->cc = 0; tp_set_blk_id(tprx->rx_data[i], TP_ID_NONE); } /* allocate "block available" array */ tprx->b_is_present = (char *)malloc(tprx->b_cnt*sizeof(char)); if ( tprx->b_is_present != NULL ) { /* allocate memory pool */ tprx->b_pool_ptr = (char *)malloc(tprx->b_pool_size); if ( tprx->b_pool_ptr != NULL ) { /* allocate missed blocks list */ tprx->b_missed_list = (short *)malloc(tprx->b_cnt*sizeof(short)); if ( tprx->b_missed_list != NULL ) { return 1; } /* deallocate everything, if something went wrong */ free(tprx->b_pool_ptr); tprx->b_pool_ptr = NULL; } free(tprx->b_is_present); tprx->b_is_present = NULL; } } for( i = 0; i < tprx->rx_cnt; i++ ) if ( tprx->rx_ecb[i] != NULL ) free(tprx->rx_ecb[i]); free(tprx->rx_ecb); tprx->rx_ecb = NULL; } } for( i = 0; i < tprx->rx_cnt; i++ ) if ( tprx->rx_data[i] != NULL ) free(tprx->rx_data[i]); free(tprx->rx_data); tprx->rx_data = NULL; } return 0; } int tprx_IsOk(tprx_type tprx) { assert(tprx != NULL); assert(tprx->rx_cnt == tprx->b_cnt+TPRX_RX_ADD); assert(tprx->b_cnt*2 < (int)tprx->b_len); return 1; } tprx_type tprx_Open(unsigned short socket) { tprx_type tprx; if ( ipx_init() == 0 ) { fprintf(stderr, tprx_es_ipx_not_found); return NULL; } switch(ipx_open_socket(socket)) { case 0x0fe: fprintf(stderr, tprx_es_socket_table_full); return NULL; case 0x0ff: fprintf(stderr, tprx_es_socket_open); return NULL; } tprx = (tprx_type)malloc(sizeof(tprx_struct)); if ( tprx != NULL ) { tprx->flags = 0; tprx->is_ended = 0; tprx->is_adr_known = 0; tprx->socket = socket; tprx->f_name = NULL; tprx->fp = NULL; tprx->f_len = 0L; tprx->f_pos = 0L; tprx->f_start = (clock_t)0; tprx->small_delay = CLOCKS_PER_SEC/2; tprx->large_delay = CLOCKS_PER_SEC*2; tprx->is_aux = 0; tprx_SetState(tprx, tprx_state_none); if ( tprx_OpenPool(tprx, TPRX_B_LEN, TPRX_B_CNT) != 0 ) { tprx->tx_data = (char *)malloc(tprx->b_len+TP_BLK_INFO_SIZE); if ( tprx->tx_data != NULL ) { tprx->tx_ecb = (ipx_ecb_struct *)malloc(sizeof(ipx_ecb_struct)); if ( tprx->tx_ecb != NULL ) { tprx->tx_ecb->inuse = 0; tprx->tx_ecb->cc = 0; tp_set_blk_id(tprx->tx_data, TP_ID_NONE); tprx_ListenAll(tprx); return tprx; } free(tprx->tx_data); } tprx_ClosePool(tprx); } free(tprx); } ipx_close_socket(socket); return NULL; } void tprx_ClosePool(tprx_type tprx) { int i; assert(tprx != NULL); free(tprx->b_missed_list); tprx->b_missed_list = NULL; free(tprx->b_pool_ptr); tprx->b_pool_ptr = NULL; free(tprx->b_is_present); tprx->b_is_present = NULL; for( i = 0; i < tprx->rx_cnt; i++ ) if ( tprx->rx_ecb[i] != NULL ) { ipx_cancel_ecb(tprx->rx_ecb[i]); free(tprx->rx_ecb[i]); } free(tprx->rx_ecb); tprx->rx_ecb = NULL; for( i = 0; i < tprx->rx_cnt; i++ ) if ( tprx->rx_data[i] != NULL ) free(tprx->rx_data[i]); free(tprx->rx_data); tprx->rx_data = NULL; } void tprx_Close(tprx_type tprx) { assert(tprx != NULL); if ( tprx->f_name != NULL ) free(tprx->f_name); ipx_cancel_ecb(tprx->tx_ecb); free(tprx->tx_ecb); free(tprx->tx_data); tprx_ClosePool(tprx); if ( tprx->fp != NULL ) fclose(tprx->fp); ipx_close_socket(tprx->socket); free(tprx); } void tprx_SetAux(tprx_type tprx, int (*aux)( int msg, void *data )) { if ( tprx_IsOk(tprx) == 0 ) return; tprx->aux = aux; tprx->is_aux = 1; } void tprx_DoAux(tprx_type tprx, int msg, void *data) { if ( tprx_IsOk(tprx) == 0 ) return; if ( tprx->is_aux != 0 ) tprx->aux(msg, data); } void tprx_DoPAux(tprx_type tprx, int msg) { tprx->pdata.total = tprx->f_len; tprx->pdata.curr = tprx->f_pos; tprx->pdata.crc = tprx->f_crc; tprx->pdata.path = tprx->f_name; tprx->pdata.file_start = tprx->f_start; tprx_DoAux(tprx, msg, (void *)&(tprx->pdata)); } void tprx_InitPool(tprx_type tprx, int b_curr_cnt) { int i; tprx->b_curr_cnt = b_curr_cnt; tprx->b_in_cnt = 0; tprx->b_is_any_present = 0; for( i = 0; i < tprx->b_cnt; i++ ) tprx->b_is_present[i] = 0; } void tprx_CopyMemoryToPool(tprx_type tprx, int no, void *adr, size_t len) { assert(no < tprx->b_curr_cnt); if ( tprx->b_is_present[no] == 0 ) { memcpy(tprx->b_pool_ptr+no*tprx->b_len, adr, len); tprx->b_in_cnt++; tprx->b_is_present[no] = 1; tprx->b_is_any_present = 1; } } void tprx_MakeMissedList(tprx_type tprx) { int i; int missed = 0; for( i = 0; i < tprx->b_curr_cnt; i++ ) { if ( tprx->b_is_present[i] == 0 ) { tprx->b_missed_list[missed++] = (short)i; } } tprx->b_missed_cnt = missed; assert(missed == tprx->b_curr_cnt-tprx->b_in_cnt); } void tprx_SetFileName(tprx_type tprx, char *path) { if ( tprx->fp != NULL ) fclose(tprx->fp); tprx->fp = NULL; tprx->f_exist = 0; if ( tprx->f_name != NULL ) free(tprx->f_name); tprx->f_name = (char *)malloc(strlen(path)+1); if ( tprx->f_name == NULL ) return; strcpy(tprx->f_name, path); strupr(tprx->f_name); if ( (tprx->flags & TP_FLAG_IS_DIR) == 0 ) { FILE *fp; tprx->f_exist = 0; fp = fopen(tprx->f_name, "r"); if ( fp != NULL ) { tprx->f_exist = 1; fclose(fp); } } } void tprx_OpenFile(tprx_type tprx) { static char drive[_MAX_DRIVE]; static char dirs[_MAX_DIR]; static char fname[_MAX_FNAME+_MAX_EXT]; static char ext[_MAX_EXT]; static char npath[_MAX_PATH]; tprx->f_is_write_data = 0; tprx->f_pos = 0UL; tprx->f_crc = 0L; tprx->f_start = 0L; if ( (tprx->flags & TP_FLAG_IS_TEST_MODE) == 0 ) { char *cwd; tprx->fp = NULL; if ( (tprx->flags & TP_FLAG_IS_DIR) != 0 ) { /* remember current path */ cwd = c_getcwd(); if ( cwd == NULL ) { printf("can not get current working directory\n"); return; } /* create directory */ if ( c_create_path(tprx->f_name) != 0 ) { printf("can not create directory '%s'\n", tprx->f_name); return; } /* restore directory */ if ( c_set_path(cwd) != 0 ) { printf("can not change to path '%s'\n", cwd); return; } } else { /* in the next few lines, the current dir will be stored */ /* and restored... this is probably useless, because */ /* the directory is already created by the lines above */ /* But: It does not slow down the transfer process */ _splitpath( tprx->f_name, drive, dirs, fname, ext ); /* strcpy(npath, drive); */ strcpy(npath, ""); strcat(npath, dirs); strcat(fname, ext); /* create the path, if it does not exist directory */ cwd = c_getcwd(); if ( cwd == NULL ) { printf("can not get current working directory\n"); return; } /* printf("cwd: %s\n", cwd); */ if ( c_create_path(npath) != 0 ) { printf("can not create path '%s'\n", npath); return; } /* printf("destpath: %s\n", npath); */ if ( c_set_path(cwd) != 0 ) { printf("can not change to path '%s'\n", cwd); return; } /* create the file */ tprx->fp = fopen(tprx->f_name, "wb"); if ( tprx->fp == NULL ) { printf("can not create '%s'\n", tprx->f_name); } } } else { printf("test mode: file/dir '%s' is not written to disk.\n", tprx->f_name); } tprx->f_start = clock(); } void tprx_Error(tprx_type tprx, char *s) { fprintf(stderr, "\n"); fprintf(stderr, TPRX_ID_STR "%s\n", s); tprx->is_ended = 1; tprx_SetState(tprx, tprx_state_none); if ( tprx->is_adr_known != 0 ) { clock_t c1 = clock() + CLOCKS_PER_SEC; long cnt = 4L; while ( clock() < c1 && cnt > 0L ) { clock_t c2; ipx_dispatch(); if ( tprx->tx_ecb->inuse == 0 ) { tp_set_blk_id(tprx->tx_data, TP_ID_ERROR); tp_set_blk_ver(tprx->tx_data, TP_VERSION); strcpy(tp_get_blk_data_adr(tprx->tx_data), s); ipx_fill_send_ecb( tprx->tx_ecb, ipx_get_header(&(tprx->adr), tprx->socket, tprx->socket), tprx->tx_data, tprx->b_len+TP_BLK_INFO_SIZE); ipx_send_ecb(tprx->tx_ecb); cnt--; } c2 = clock() + CLOCKS_PER_SEC/8; while ( clock() < c2 ) ; } } } size_t tprx_GetWriteSize(tprx_type tprx) { size_t elen; if ( tprx->f_len-tprx->f_pos >= (long)tprx->b_pool_size ) elen = tprx->b_pool_size; else elen = (size_t)(tprx->f_len-tprx->f_pos); return elen; } int tprx_Write(tprx_type tprx) { size_t len, i; len = tprx_GetWriteSize(tprx); if ( (tprx->flags & TP_FLAG_IS_DISABLE_CRC) == 0 ) { if ( (tprx->flags & TP_FLAG_IS_CRC32) == 0 ) { for( i = 0; i < len; i += 1024 ) { ipx_dispatch(); tprx->f_crc = (unsigned long)crc16((unsigned short)tprx->f_crc, (unsigned char *)tprx->b_pool_ptr+(size_t)i, (len > i+1024) ? 1024 : len-i); } } else { for( i = 0; i < len; i += 1024 ) { ipx_dispatch(); tprx->f_crc = crc32(tprx->f_crc, (unsigned char *)tprx->b_pool_ptr+(size_t)i, (len > i+1024) ? 1024 : len-i); } } if ( tprx->f_crc != tprx->f_remote_crc ) { tprx_Error(tprx, "crc error"); return 0; } /* tprx->f_crc = crc32(tprx->f_crc, (unsigned char *)tprx->b_pool_ptr, len); */ } if ( (tprx->flags & TP_FLAG_IS_TEST_MODE) == 0 ) { if ( tprx->f_is_write_data != 0 && tprx->fp != NULL ) { if ( len > 0 ) { if ( fwrite(tprx->b_pool_ptr, len, 1, tprx->fp) != 1 ) { tprx_Error(tprx, "write error"); return 0; } } } } tprx->f_pos += (long)len; tprx->f_is_write_data = 0; return 1; } void tprx_CloseFile(tprx_type tprx) { if ( (tprx->flags & TP_FLAG_IS_TEST_MODE) == 0 ) { if ( tprx->fp != NULL ) { int handle; fclose(tprx->fp); tprx->fp = NULL; _dos_setfileattr( tprx->f_name, (tprx->f_attr) ); _dos_open( tprx->f_name, _O_RDONLY, &handle ); _dos_setftime( handle, tprx->f_date, tprx->f_time ); _dos_close( handle ); } } } int tprx_ListenECB(tprx_type tprx, int i) { if ( tprx->rx_ecb[i]->inuse != 0 ) { return 1; } if ( ipx_fill_receive_ecb( tprx->rx_ecb[i], tprx->socket, tprx->rx_data[i], tprx->b_len+TP_BLK_INFO_SIZE) == NULL ) { tprx_Error(tprx, "cannot fill receive ecb"); return 0; } if ( ipx_listen_ecb(tprx->rx_ecb[i]) == 0 ) { tprx_Error(tprx, "cannot listen to ecb"); return 0; } return 1; } int tprx_ListenAll(tprx_type tprx) { int i; for( i = 0; i < tprx->rx_cnt; i++ ) { if ( tprx_ListenECB(tprx, i) == 0 ) return 0; } return 1; } int tprx_ListenExcept(tprx_type tprx, int id1, int id2) { int i; for( i = 0; i < tprx->rx_cnt; i++ ) { if ( tprx->rx_ecb[i]->inuse == 0 ) { if ( tprx->rx_ecb[i]->cc == 0 ) { if ( tp_ecb_get_id(tprx->rx_ecb[i]) == TP_ID_ERROR ) { static char s[80]; sprintf(s, "remote error: '%s'", tp_ecb_get_data_adr(tprx->rx_ecb[i])); tprx_Error(tprx, s); return 0; } if (tp_ecb_get_id(tprx->rx_ecb[i]) != id1 && tp_ecb_get_id(tprx->rx_ecb[i]) != id2) { if ( tprx_ListenECB(tprx, i) == 0 ) return 0; } } else { printf( TPRX_ID_STR "receiver warning: %s\n", ipx_get_ecb_cc_string(tprx->rx_ecb[i])); if ( tprx_ListenECB(tprx, i) == 0 ) return 0; } } } return 1; } /* search for a received block with identifier id return index to rx_ecb array or -1, if id not found */ int tprx_SearchId(tprx_type tprx, short id) { int i; assert(tprx != NULL); for( i = 0; i < tprx->rx_cnt; i++ ) { if ( tprx->rx_ecb[i]->inuse == 0 ) { if ( tprx->rx_ecb[i]->cc != 0 ) { tprx_Error(tprx, ipx_get_ecb_cc_string(tprx->rx_ecb[i])); tprx_ListenECB(tprx, i); } else if (tp_ecb_get_id(tprx->rx_ecb[i]) == id) { if ( tp_ecb_get_ver(tprx->rx_ecb[i]) != TP_VERSION ) { tprx_Error(tprx, "wrong version"); } else { return i; } } } } return -1; } int tprx_ListenAndSearch(tprx_type tprx, int id) { tprx_ListenExcept(tprx, id, TP_ID_NONE); return tprx_SearchId(tprx, id); } void tprx_SendECB(tprx_type tprx) { tp_set_blk_ver(tprx->tx_data, TP_VERSION); ipx_fill_send_ecb( tprx->tx_ecb, ipx_get_header(&(tprx->adr), tprx->socket, tprx->socket), tprx->tx_data, tprx->b_len+TP_BLK_INFO_SIZE); if ( ipx_send_ecb(tprx->tx_ecb) == 0 ) { static char s[80]; sprintf(s, "cannot send msg %d", tp_get_blk_id(tprx->tx_data) ); tprx_Error(tprx, s); } } void tprx_WaitSend(tprx_type tprx, void (*next_state)(tprx_type tprx), void (*repeated_state)(tprx_type tprx), clock_t delay) { if ( tprx->tx_ecb->inuse == 0 ) { if ( tprx->tx_ecb->cc != 0 ) { tprx_Error(tprx, ipx_get_ecb_cc_string(tprx->tx_ecb)); } else { tprx->clock_dest = clock()+delay; tprx_SetRepeatedState(tprx, repeated_state); tprx_SetState(tprx, next_state); } } } int tprx_CheckTime(tprx_type tprx) { if ( tprx->clock_dest < clock() ) { tprx_SetState(tprx, tprx_GetRepeatedState(tprx)); return 0; } return 1; } int tprx_Dispatch(tprx_type tprx) { ipx_dispatch(); if( tprx->is_ended != 0 ) return 1; tprx->state_fn(tprx); if ( tprx->state_fn != tprx_state_user_check ) { if ( kbhit() != 0 ) { if ( getch() == 27 ) { tprx_Error(tprx, "user break"); } } } return tprx->is_ended; } /* - - - - - state functions - - - - - - - - - - - - - - - - - - - - - - - */ void tprx_state_none(tprx_type tprx) { int pos; pos = tprx_ListenAndSearch(tprx, TP_ID_REQUEST); if ( pos >= 0 ) { tp_request request; request = (tp_request)tp_ecb_get_data_adr(tprx->rx_ecb[pos]); tprx->adr = request->adr; tprx->is_adr_known = 1; tprx->f_len = request->file_size; tprx->flags = request->flags; tprx->f_attr = request->attr; tprx->f_time = request->time; tprx->f_date = request->date; tprx_SetFileName(tprx, tp_ecb_get_data_adr(tprx->rx_ecb[pos])+sizeof(tp_request_struct)); tprx_ListenECB(tprx, pos); tprx_SetState(tprx, tprx_state_gen_ack_request); if ( tprx->f_exist != 0 && (tprx->flags&TP_FLAG_IS_NO_USER_CHECK) == 0 ) { printf("local file '%s' exists, overwrite (y,n,a)? ", tprx->f_name); fflush(stdout); } } } void tprx_state_gen_ack_request(tprx_type tprx) { tp_ack_request ack_request; tp_debug_out("tprx_state_gen_ack_request"); ack_request = (tp_ack_request)tp_get_blk_data_adr(tprx->tx_data); ack_request->adr = *ipx_get_local_net_number(); ack_request->exist = tprx->f_exist; tp_set_blk_id(tprx->tx_data, TP_ID_ACK_REQUEST); tprx_SendECB(tprx); tprx_SetState(tprx, tprx_state_chk_ack_request); } void tprx_state_chk_ack_request(tprx_type tprx) { tp_debug_out("tprx_state_chk_ack_request"); if ( tprx->f_exist != 0 && (tprx->flags&TP_FLAG_IS_NO_USER_CHECK) == 0 ) { tprx_WaitSend(tprx, tprx_state_user_check, tprx_state_gen_ack_request, tprx->large_delay); } else { tprx_WaitSend(tprx, tprx_state_wait_file_start, tprx_state_gen_ack_request, tprx->large_delay); } } void tprx_state_user_check(tprx_type tprx) { int pos; if ( tprx_CheckTime(tprx) == 0 ) return; tprx->f_is_skip = 0; if ( kbhit() != 0 ) { int c = getch(); switch(c) { case 'n': case 'N': printf("%c\n", c); tprx->f_is_skip = 1; tprx_SetState(tprx, tprx_state_gen_file_start); return; case 'a': case 'A': printf("%c\n", c); tprx_SetFlag(tprx, TP_FLAG_IS_NO_USER_CHECK); tprx_DoPAux(tprx, TP_MSG_PSTART); tprx_SetState(tprx, tprx_state_gen_file_start); return; case 'y': case 'Y': case 'j': case 'J': printf("%c\n", c); tprx_DoPAux(tprx, TP_MSG_PSTART); tprx_SetState(tprx, tprx_state_gen_file_start); return; case 27: tprx_Error(tprx, "user escape"); return; } } tprx_ListenExcept(tprx, TP_ID_FILE_START, TP_ID_FILE_END); pos = tprx_SearchId(tprx, TP_ID_FILE_START); if ( pos >= 0 ) { printf("y/a\n"); /* tprx_ListenECB(tprx, pos); */ tprx_DoPAux(tprx, TP_MSG_PSTART); tprx_SetState(tprx, tprx_state_wait_file_start); return; } pos = tprx_SearchId(tprx, TP_ID_FILE_END); if ( pos >= 0 ) { printf("n\n"); tprx_SetState(tprx, tprx_state_gen_ack_file_end); tprx_ListenECB(tprx, pos); return; } } void tprx_state_gen_file_start(tprx_type tprx) { tp_file_start file_start; tp_debug_out("tprx_state_gen_file_start"); file_start = (tp_file_start)tp_get_blk_data_adr(tprx->tx_data); file_start->is_skip_file = tprx->f_is_skip; file_start->flags = tprx->flags; tp_set_blk_id(tprx->tx_data, TP_ID_FILE_START); tprx_SendECB(tprx); tprx_SetState(tprx, tprx_state_chk_file_start); } void tprx_state_chk_file_start(tprx_type tprx) { tp_debug_out("tprx_state_chk_file_start"); tprx_WaitSend(tprx, tprx_state_wait_file_start, tprx_state_gen_file_start, tprx->small_delay); } void tprx_state_wait_file_start(tprx_type tprx) { int pos; /* tp_debug_out("tprx_state_wait_file_start"); */ tprx_ListenExcept(tprx, TP_ID_FILE_START, TP_ID_FILE_END); pos = tprx_SearchId(tprx, TP_ID_FILE_START); if ( pos >= 0 ) { tp_file_start file_start; file_start = (tp_file_start)tp_ecb_get_data_adr(tprx->rx_ecb[pos]); if ( file_start->is_skip_file != 0 ) { tprx_SetState(tprx, tprx_state_none); } else { tprx_OpenFile(tprx); tprx_DoPAux(tprx, TP_MSG_PSTART); tprx_SetState(tprx, tprx_state_gen_ack_file_start); tprx->f_start = clock(); } tprx_ListenECB(tprx, pos); return; } pos = tprx_SearchId(tprx, TP_ID_FILE_END); if ( pos >= 0 ) { tprx_SetState(tprx, tprx_state_gen_ack_file_end); tprx_ListenECB(tprx, pos); return; } /* user may jump here... so time check is at the end */ if ( tprx_CheckTime(tprx) == 0 ) return; } void tprx_state_gen_ack_file_start(tprx_type tprx) { tp_debug_out("tprx_state_gen_ack_file_start"); tp_set_blk_id(tprx->tx_data, TP_ID_ACK_FILE_START); tprx_SendECB(tprx); tprx_SetState(tprx, tprx_state_chk_ack_file_start); } void tprx_state_chk_ack_file_start(tprx_type tprx) { tp_debug_out("tprx_state_chk_ack_file_start"); tprx_WaitSend(tprx, tprx_state_wait_block_start, tprx_state_gen_ack_file_start, tprx->large_delay); } void tprx_state_wait_block_start(tprx_type tprx) { int pos; tp_debug_out("tprx_state_wait_block_start"); if ( tprx_CheckTime(tprx) == 0 ) return; tprx_ListenExcept(tprx, TP_ID_BLOCK_START, TP_ID_FILE_END); pos = tprx_SearchId(tprx, TP_ID_BLOCK_START); if ( pos >= 0 ) { tp_block_start block_start; block_start = (tp_block_start)tp_ecb_get_data_adr(tprx->rx_ecb[pos]); tprx_DoPAux(tprx, TP_MSG_PDATA); tprx_InitPool(tprx, (int)block_start->cnt); tprx_SetState(tprx, tprx_state_gen_ack_block_start); tprx_ListenECB(tprx, pos); } pos = tprx_SearchId(tprx, TP_ID_FILE_END); if ( pos >= 0 ) { if ( tprx->f_is_write_data != 0 ) tprx_Write(tprx); tprx_DoPAux(tprx, TP_MSG_PDATA); tprx_DoPAux(tprx, TP_MSG_PEND); tprx_CloseFile(tprx); tprx_SetState(tprx, tprx_state_gen_ack_file_end); tprx_ListenECB(tprx, pos); } } void tprx_state_gen_ack_block_start(tprx_type tprx) { tp_debug_out("tprx_state_gen_ack_block_start"); tp_set_blk_id(tprx->tx_data, TP_ID_ACK_BLOCK_START); tprx_SendECB(tprx); tprx_SetState(tprx, tprx_state_chk_ack_block_start); } void tprx_state_chk_ack_block_start(tprx_type tprx) { tp_debug_out("tprx_state_chk_ack_block_start"); tprx_WaitSend(tprx, tprx_state_wait_data, tprx_state_gen_ack_block_start, tprx->small_delay); } void tprx_state_wait_data(tprx_type tprx) { int pos; /* tp_debug_out("tprx_state_wait_data"); */ if ( tprx->f_is_write_data != 0 ) tprx_Write(tprx); if ( tprx_IsAnyPresent(tprx) == 0 ) if ( tprx_CheckTime(tprx) == 0 ) return; /* tprx_ListenExcept(tprx, TP_ID_DATA, TP_ID_BLOCK_END); */ pos = tprx_SearchId(tprx, TP_ID_ERROR); if ( pos >= 0 ) { static char s[80]; sprintf(s, "remote error: '%s'", tp_ecb_get_data_adr(tprx->rx_ecb[pos])); tprx_Error(tprx, s); return; } pos = tprx_SearchId(tprx, TP_ID_DATA); if ( pos >= 0 ) { tp_data d; d = (tp_data)tp_ecb_get_data_adr(tprx->rx_ecb[pos]); tprx_CopyMemoryToPool(tprx, d->no, tp_ecb_get_data_adr(tprx->rx_ecb[pos])+sizeof(tp_data_struct), (size_t)(d->len)); /* printf("(%d,%d/%d)", (int)d->no, tprx->b_in_cnt, tprx->b_curr_cnt); */ tprx_ListenECB(tprx, pos); } else { pos = tprx_SearchId(tprx, TP_ID_BLOCK_END); if ( pos >= 0 ) { /* printf("TP_ID_BLOCK_END at pos %d found, missed cnt: %d\n", pos, tprx->b_curr_cnt-tprx->b_in_cnt); */ tprx_ListenECB(tprx, pos); if ( tprx->b_curr_cnt == tprx->b_in_cnt ) { tp_block_end block_end; block_end = (tp_block_end)tp_ecb_get_data_adr(tprx->rx_ecb[pos]); tprx->f_remote_crc = block_end->crc; tprx->f_is_write_data = 1; tprx_SetState(tprx, tprx_state_gen_ack_block_end); } else { tprx_MakeMissedList(tprx); tprx_SetState(tprx, tprx_state_gen_missed_blocks); } } } } void tprx_state_gen_missed_blocks(tprx_type tprx) { tp_missed_blocks missed_blocks; tp_debug_out("tprx_state_gen_missed_blocks"); /* printf("missed: %d\n", (int)tprx->b_missed_cnt); */ missed_blocks = (tp_missed_blocks)tp_get_blk_data_adr(tprx->tx_data); missed_blocks->cnt = tprx->b_missed_cnt; memcpy( tp_get_blk_data_adr(tprx->tx_data)+sizeof(tp_missed_blocks_struct), tprx->b_missed_list, tprx->b_missed_cnt*sizeof(short)); tp_set_blk_id(tprx->tx_data, TP_ID_MISSED_BLOCKS); tprx_SendECB(tprx); tprx_SetState(tprx, tprx_state_chk_missed_blocks); } void tprx_state_chk_missed_blocks(tprx_type tprx) { tp_debug_out("tprx_state_chk_missed_blocks"); tprx_WaitSend(tprx, tprx_state_wait_data, tprx_state_gen_missed_blocks, tprx->small_delay); } void tprx_state_gen_ack_block_end(tprx_type tprx) { tp_debug_out("tprx_state_gen_ack_block_end"); tp_set_blk_id(tprx->tx_data, TP_ID_ACK_BLOCK_END); tprx_SendECB(tprx); tprx_SetState(tprx, tprx_state_chk_ack_block_end); } void tprx_state_chk_ack_block_end(tprx_type tprx) { tp_debug_out("tprx_state_chk_ack_block_end"); tprx_WaitSend(tprx, tprx_state_wait_block_start, tprx_state_gen_ack_block_end, tprx->small_delay); } void tprx_state_gen_ack_file_end(tprx_type tprx) { tp_debug_out("tprx_state_gen_ack_file_end"); tp_set_blk_id(tprx->tx_data, TP_ID_ACK_FILE_END); tprx_SendECB(tprx); tprx_SetState(tprx, tprx_state_chk_ack_file_end); } void tprx_state_chk_ack_file_end(tprx_type tprx) { tp_debug_out("tprx_state_chk_ack_file_end"); tprx_WaitSend(tprx, tprx_state_none2, tprx_state_gen_ack_file_end, tprx->large_delay); } void tprx_state_none2(tprx_type tprx) { int pos; /* tp_debug_out("tprx_state_none2"); */ if ( tprx_CheckTime(tprx) == 0 ) return; pos = tprx_ListenAndSearch(tprx, TP_ID_REQUEST); if ( pos >= 0 ) { tprx_SetState(tprx, tprx_state_none); } }