uint32_t TFTPSRV_service_timer ( TFTPSRV_STATE_STRUCT_PTR tftpsrv_ptr /* [IN/OUT] The TFTP Server state */ ) { /* Body */ TFTP_TRANS_STRUCT_PTR trans_ptr; uint32_t time; bool expired; while (tftpsrv_ptr->EVENT_HEAD) { trans_ptr = tftpsrv_ptr->EVENT_HEAD; time = TFTP_timeout_left(&trans_ptr->XMIT_TIMER, &expired); if (!expired) { trans_ptr->TIME = time; return time; } /* Endif */ RTCS_DLIST_DEL(tftpsrv_ptr->EVENT_HEAD, trans_ptr); if (trans_ptr->EXIT) { TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); continue; } /* Endif */ #if TFTPSRV_TIMEOUT_RETRIES != TFTPSRV_INFINITE_RETRIES if (++trans_ptr->NUM_RETRIES > TFTPSRV_TIMEOUT_RETRIES) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_to, trans_ptr->ADDR); TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); continue; } /* Endif */ #endif TFTPSRV_send(trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, time); } /* Endwhile */ /* Nothing in the event queue */ return 0; } /* Endbody */
uchar_ptr TFTP_read ( uint_32_ptr size /* [OUT] number of bytes read, or error code */ ) { /* Body */ uint_32 sock; sockaddr_in remote_addr; uint_16 remote_size; uint_16 ack_block; uint_16 pkt_op, pkt_block; uint_32 pkt_size; uint_32 time_left; boolean expired; #if TFTP_TIMEOUT_RETRIES uint_32 retries = 0; #endif ack_block = ntohs(TFTP_config.ACK.BLOCK); TFTP_timeout_restart(&TFTP_config.TIMEOUT); for (;;) { /* Check for timeout */ time_left = TFTP_timeout_left(&TFTP_config.TIMEOUT, &expired); if (expired) { #if TFTP_TIMEOUT_RETRIES retries++; if (retries > TFTP_TIMEOUT_RETRIES) { *size = RTCSERR_TFTP_TIMEOUT; TFTP_close(); return NULL; } /* Endif */ #endif /* Retransmit the last packet */ TFTP_RESEND(); } /* Endif */ /* Wait for a packet */ sock = TFTP_WAIT(time_left); /* Timeout -- retransmit last packet */ if (sock != TFTP_config.SOCK) { continue; } /* Endif */ remote_size = sizeof(remote_addr); pkt_size = TFTP_RECV(TFTP_config.PACKET); pkt_op = ntohs(TFTP_config.PACKET.HEAD.OP); pkt_block = ntohs(TFTP_config.PACKET.HEAD.BLOCK); /* Check source address of received packet */ if (remote_addr.sin_addr.s_addr != TFTP_config.SADDR.sin_addr.s_addr) { continue; } /* Endif */ /* Validate source port */ if (ack_block && remote_addr.sin_port != TFTP_config.SADDR.sin_port) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_tid, remote_addr); continue; } /* Endif */ /* Check size of received packet */ if (pkt_size < sizeof(TFTP_HEADER)) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for error packet */ if (pkt_op == TFTPOP_ERROR) { *size = RTCSERR_TFTP_ERROR + pkt_block; TFTP_close(); return NULL; } /* Endif */ /* Check for data packet */ if ((pkt_op != TFTPOP_DATA) || (pkt_size > sizeof(TFTP_PACKET)) || (pkt_block < ack_block) || (pkt_block > ack_block+1)) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for retransmitted packet */ if (pkt_block == ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); continue; } /* Endif */ /* We have the next packet */ break; } /* Endfor */ /* Update the adaptive timeout */ TFTP_timeout_update(&TFTP_config.TIMEOUT); /* Free the original RRQ */ if (!ack_block) { TFTP_config.SADDR.sin_port = remote_addr.sin_port; _mem_free(TFTP_config.RRQ_PTR); TFTP_config.RRQ_PTR = NULL; } /* Endif */ /* ACK it */ ack_block++; htons(TFTP_config.ACK.BLOCK, ack_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); TFTP_config.LAST = (pkt_size < sizeof(TFTP_PACKET)); /* Return the data */ *size = pkt_size - sizeof(TFTP_HEADER); return TFTP_config.PACKET.DATA; } /* Endbody */
void TFTPSRV_service_request ( TFTPSRV_STATE_STRUCT_PTR tftpsrv_ptr /* [IN/OUT] The TFTP Server state */ ) { /* Body */ TFTP_TRANS_STRUCT_PTR trans_ptr; sockaddr_in sockaddr_t; int32_t pkt_len, i; uint32_t error; char *filename, *filemode; uint16_t sockaddrlen, pkt_op; /* receive the datagram */ sockaddrlen = sizeof(sockaddr_t); pkt_len = recvfrom(tftpsrv_ptr->SRV_SOCK, tftpsrv_ptr->BUFFER, TFTP_MAX_MESSAGE_SIZE, 0, (sockaddr *)&sockaddr_t, &sockaddrlen); if (pkt_len == RTCS_ERROR) { return; } /* Endif */ /* limit the number of concurrent transactions */ if (tftpsrv_ptr->NUM_TRANSACTIONS >= TFTPSRV_MAX_TRANSACTIONS) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_busy, sockaddr_t); return; } /* Endif */ /* parse the request; extract op, filename and filemode */ i = 2; filename = (char *)tftpsrv_ptr->BUFFER + i; for (; i<pkt_len; i++) { if (tftpsrv_ptr->BUFFER[i] == '\0') break; } /* Endfor */ i++; filemode = (char *)tftpsrv_ptr->BUFFER + i; for (; i<pkt_len; i++) { if (tftpsrv_ptr->BUFFER[i] == '\0') break; } /* Endfor */ if (i >= pkt_len) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_op, sockaddr_t); return; } /* Endif */ pkt_op = mqx_ntohs(tftpsrv_ptr->BUFFER); /* allocate state for the new transaction */ trans_ptr = RTCS_mem_alloc_zero(sizeof(TFTP_TRANS_STRUCT)); if (trans_ptr == NULL) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); return; } /* Endif */ _mem_set_type(trans_ptr, MEM_TYPE_TFTP_TRANS_STRUCT); /* validate the requested operation */ switch (pkt_op) { case TFTPOP_RRQ: trans_ptr->RECV_OP = TFTPOP_ACK; trans_ptr->SEND_OP = TFTPOP_DATA; break; case TFTPOP_WRQ: trans_ptr->RECV_OP = TFTPOP_DATA; trans_ptr->SEND_OP = TFTPOP_ACK; break; default: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_op, sockaddr_t); _mem_free(trans_ptr); return; } /* Endswitch */ /* open the requested file */ error = TFTPSRV_open_device(pkt_op, filename, filemode, &trans_ptr->TRANS_FILE_PTR); if (error) { switch (error) { case RTCS_EACCES: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_accvio, sockaddr_t); break; case RTCS_ENOENT: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_nofile, sockaddr_t); break; case RTCS_EEXIST: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_exists, sockaddr_t); break; default: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); break; } /* Endswitch */ _mem_free(trans_ptr); return; } /* Endif */ /* create a socket for the new transaction */ trans_ptr->SOCK = socket(PF_INET, SOCK_DGRAM, 0); if (trans_ptr->SOCK == RTCS_SOCKET_ERROR) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ trans_ptr->ADDR.sin_family = sockaddr_t.sin_family; trans_ptr->ADDR.sin_port = sockaddr_t.sin_port; trans_ptr->ADDR.sin_addr.s_addr = sockaddr_t.sin_addr.s_addr; sockaddr_t.sin_family = AF_INET; sockaddr_t.sin_port = 0; sockaddr_t.sin_addr.s_addr = INADDR_ANY; error = bind(trans_ptr->SOCK, (const sockaddr *)&sockaddr_t, sizeof(sockaddr_t)); if (error != RTCS_OK) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); shutdown(trans_ptr->SOCK, 0); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ /* build the first packet */ trans_ptr->BLOCK = 0; switch (trans_ptr->SEND_OP) { case TFTPOP_DATA: TFTPSRV_build_DATA(trans_ptr); break; case TFTPOP_ACK: TFTPSRV_build_ACK(trans_ptr); trans_ptr->EXIT = FALSE; break; } /* Endswitch */ if (trans_ptr->SEND_SIZE < sizeof(TFTP_HEADER)) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); shutdown(trans_ptr->SOCK, 0); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ /* send the first packet */ TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_init(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); tftpsrv_ptr->SOCKETS[tftpsrv_ptr->NUM_TRANSACTIONS] = trans_ptr->SOCK; tftpsrv_ptr->TRANS_PTRS[tftpsrv_ptr->NUM_TRANSACTIONS] = trans_ptr; tftpsrv_ptr->NUM_TRANSACTIONS++; } /* Endbody */
void TFTPSRV_service_transaction ( TFTPSRV_STATE_STRUCT_PTR tftpsrv_ptr, /* [IN/OUT] The TFTP Server state */ TFTP_TRANS_STRUCT_PTR trans_ptr /* [IN/OUT] The transaction state */ ) { /* Body */ sockaddr_in sockaddr_tftp; uint32_t block_num; int32_t pkt_len, write_len; uint16_t sockaddrlen, pkt_op; /* receive the datagram */ sockaddrlen = sizeof(sockaddr_tftp); pkt_len = recvfrom(trans_ptr->SOCK, tftpsrv_ptr->BUFFER, TFTP_MAX_MESSAGE_SIZE, 0,(sockaddr *)&sockaddr_tftp, &sockaddrlen); if (pkt_len == RTCS_ERROR) { return; } /* Endif */ /* verify the sender's address and port */ if ((trans_ptr->ADDR.sin_port != sockaddr_tftp.sin_port) || (trans_ptr->ADDR.sin_addr.s_addr != sockaddr_tftp.sin_addr.s_addr)) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_tid, sockaddr_tftp); return; } /* Endif */ /* get op and block number */ if (pkt_len < sizeof(TFTP_HEADER)) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_tid, sockaddr_tftp); return; } /* Endif */ pkt_op = mqx_ntohs(tftpsrv_ptr->BUFFER); block_num = mqx_ntohs(tftpsrv_ptr->BUFFER + 2); /* verify the requested operation */ if (pkt_op != trans_ptr->RECV_OP) { if (pkt_op != TFTPOP_ERROR) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_op, sockaddr_tftp); } /* Endif */ TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ switch (pkt_op) { case TFTPOP_DATA: /* We are servicing a write request from a TFTP Client here */ if (block_num == trans_ptr->BLOCK) { pkt_len -= sizeof(TFTP_HEADER); write_len = RTCS_io_write(trans_ptr->TRANS_FILE_PTR, tftpsrv_ptr->BUFFER + sizeof(TFTP_HEADER), pkt_len); fflush(trans_ptr->TRANS_FILE_PTR); if (write_len != pkt_len) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_srv, trans_ptr->ADDR); TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_build_ACK(trans_ptr); trans_ptr->EXIT = (write_len < sizeof(TFTP_PACKET) - sizeof(TFTP_HEADER)); TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_update(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } else if (block_num == trans_ptr->BLOCK - 1) { TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_restart(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } /* Endif */ break; case TFTPOP_ACK: /* We are servicing a read request */ if (block_num == trans_ptr->BLOCK) { if (trans_ptr->EXIT) { /* We've received the last ACK, exit */ TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_build_DATA(trans_ptr); if (trans_ptr->SEND_SIZE < sizeof(TFTP_HEADER)) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_srv, sockaddr_tftp); TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_update(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } /* Endif */ break; } /* Endswitch */ } /* Endbody */
unsigned char *TFTP_read ( uint32_t *size /* [OUT] number of bytes read, or error code */ ) { /* Body */ uint32_t sock; sockaddr_in remote_addr; uint16_t remote_size; uint16_t ack_block; uint16_t pkt_op, pkt_block; uint32_t pkt_size; uint32_t time_left; bool expired; #if TFTP_TIMEOUT_RETRIES uint32_t retries = 0; #endif ack_block = mqx_ntohs(TFTP_config.ACK.BLOCK); TFTP_timeout_restart(&TFTP_config.TIMEOUT); for (;;) { /* Check for timeout */ time_left = TFTP_timeout_left(&TFTP_config.TIMEOUT, &expired); if (expired) { #if TFTP_TIMEOUT_RETRIES retries++; if (retries > TFTP_TIMEOUT_RETRIES) { *size = RTCSERR_TFTP_TIMEOUT; TFTP_close(); return NULL; } /* Endif */ #endif /* Retransmit the last packet */ TFTP_RESEND(); } /* Endif */ /* Wait for a packet */ sock = TFTP_WAIT(time_left); /* Timeout -- retransmit last packet */ if (sock != TFTP_config.SOCK) { continue; } /* Endif */ remote_size = sizeof(remote_addr); pkt_size = TFTP_RECV(TFTP_config.PACKET); pkt_op = mqx_ntohs(TFTP_config.PACKET.HEAD.OP); pkt_block = mqx_ntohs(TFTP_config.PACKET.HEAD.BLOCK); /* Check source address of received packet */ if (remote_addr.sin_addr.s_addr != TFTP_config.SADDR.sin_addr.s_addr) { continue; } /* Endif */ /* Validate source port */ if (ack_block && remote_addr.sin_port != TFTP_config.SADDR.sin_port) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_tid, remote_addr); continue; } /* Endif */ /* Check size of received packet */ if (pkt_size < sizeof(TFTP_HEADER)) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for error packet */ if (pkt_op == TFTPOP_ERROR) { *size = RTCSERR_TFTP_ERROR + pkt_block; TFTP_close(); return NULL; } /* Endif */ /* Check for data packet */ if ((pkt_op != TFTPOP_DATA) || (pkt_size > sizeof(TFTP_PACKET))) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for retransmitted packet */ if (pkt_block == ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); continue; } /* Endif */ /* Aknowledge also packets with lower id, some servers do retransmit them until they get an ack */ if (pkt_block < ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); mqx_htons(TFTP_config.ACK.BLOCK, pkt_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); mqx_htons(TFTP_config.ACK.BLOCK, ack_block); /* Restore id of last acknowledged packet */ continue; } /* Endif */ /* Drop unexpected packets */ if (pkt_block > ack_block+1) { /* Some server do send more than one packet at a time, these will eventually retransmitted */ continue; } /* We have the next packet */ break; } /* Endfor */ /* Update the adaptive timeout */ TFTP_timeout_update(&TFTP_config.TIMEOUT); /* Free the original RRQ */ if (!ack_block) { TFTP_config.SADDR.sin_port = remote_addr.sin_port; _mem_free(TFTP_config.RRQ_PTR); TFTP_config.RRQ_PTR = NULL; } /* Endif */ /* ACK it */ ack_block++; mqx_htons(TFTP_config.ACK.BLOCK, ack_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); TFTP_config.LAST = (pkt_size < sizeof(TFTP_PACKET)); /* Return the data */ *size = pkt_size - sizeof(TFTP_HEADER); return TFTP_config.PACKET.DATA; } /* Endbody */