Exemple #1
0
uint_32 TFTP_open
   (
      pointer  ft_data
         /* [IN] the address and filename of the bootimage */
   )
{ /* Body */
   TFTP_DATA_STRUCT_PTR    tftp;
   sockaddr_in             local_addr;
   char_ptr                str_ptr;
   uchar_ptr               packet;
   uint_32                 sock;
   uint_32                 error;
   uint_32                 fn_len, fm_len;
   uint_32                 pkt_len;

   tftp = (TFTP_DATA_STRUCT_PTR) ft_data;

   /* Get a socket */
   sock = socket(AF_INET, SOCK_DGRAM, 0);
   if (sock == RTCS_SOCKET_ERROR) {
      return RTCSERR_TFTP_SOCKET;
   } /* Endif */

   /* Must be initialized in order for TFTP_close to be able to release socket and memory */
   TFTP_config.SOCK = sock;  
   TFTP_config.RRQ_PTR = NULL;  

   /* Bind it */
   local_addr.sin_family      = AF_INET;
   local_addr.sin_port        = 0;
   local_addr.sin_addr.s_addr = INADDR_ANY;
   error = bind(sock, &local_addr, sizeof(local_addr));
   if (error != RTCS_OK) {
      TFTP_close();
      return error;
   } /* Endif */

   if ( (tftp->FILENAME == NULL) || (tftp->FILEMODE == NULL) ){      
      TFTP_close();
      return TFTPERR_FILE_NOT_FOUND;
   } /* Endif */

   /* Prepare a read request (RRQ) */
   str_ptr = tftp->FILENAME;
   while (*str_ptr++) {};
   fn_len = str_ptr - tftp->FILENAME;
   str_ptr = tftp->FILEMODE;
   while (*str_ptr++) {};
   fm_len = str_ptr - tftp->FILEMODE;
   pkt_len = 2 + fn_len + fm_len;
   packet = RTCS_mem_alloc(pkt_len);
   if (packet == NULL) {
      TFTP_close();
      return RTCSERR_TFTP_RRQ_ALLOC;
   } /* Endif */
   _mem_set_type(packet, MEM_TYPE_TFTP_PACKET);
   TFTP_config.RRQ_PTR = packet;  
   htons(packet, TFTPOP_RRQ);
   _mem_copy(tftp->FILENAME, &packet[       2], fn_len);
   _mem_copy(tftp->FILEMODE, &packet[fn_len+2], fm_len);

   /* Send the RRQ */
   TFTP_config.SOCK = sock;
   TFTP_config.SADDR.sin_family      = AF_INET;
   TFTP_config.SADDR.sin_port        = IPPORT_TFTP;
   TFTP_config.SADDR.sin_addr.s_addr = tftp->SERVER;
   TFTP_timeout_init(&TFTP_config.TIMEOUT);
   error = sendto(sock, packet, pkt_len, 0,
                  &TFTP_config.SADDR, sizeof(TFTP_config.SADDR));
   if (error != pkt_len) {
      TFTP_close();
      return RTCSERR_TFTP_RRQ_SEND;
   } /* Endif */

   /* Initialize the TFTP client */
   TFTP_config.RRQ_PTR = packet;
   TFTP_config.RRQ_LEN = pkt_len;
   TFTP_config.LAST    = FALSE;
   htons(TFTP_config.ACK.OP,    TFTPOP_ACK);
   htons(TFTP_config.ACK.BLOCK, 0);
   return RTCS_OK;

} /* 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 */