⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tftp_client.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    freeaddrinfo(res);
    return -1;
}
//
// Read a file from a host into a local buffer.  Returns the
// number of bytes actually read, or (-1) if an error occurs.
// On error, *err will hold the reason.
//
// Depreciated. Use tftp_client_get instead.
int
tftp_get(char *filename,
         struct sockaddr_in *server,
         char *buf,
         int len,
         int mode,
         int *err)
{
  char server_name[20];
  char *ret;
  int port;

  ret = inet_ntop(AF_INET, (void *)&server->sin_addr, 
		  server_name, sizeof(server_name));
  if (NULL == ret) {
      *err = TFTP_NETERR;
      return -1;
  }
  port = server->sin_port;

  return tftp_client_get(filename, server_name, port, buf, len, mode, err);
}

//
// Send data to a file on a server via TFTP.
//
int
tftp_put(char *filename,
         struct sockaddr_in *server,
         char *buf,
         int len,
         int mode,
         int *err)
{
  char server_name[20];
  char *ret;
  int port;

  ret = inet_ntop(AF_INET, (void *)&server->sin_addr, 
		  server_name, sizeof(server_name));
  if (NULL == ret) {
      *err = TFTP_NETERR;
      return -1;
  }
  port = server->sin_port;

  return tftp_client_put(filename, server_name, port, buf, len, mode, err);
}

//
// Put a file to a host from a local buffer.  Returns the
// number of bytes actually writen, or (-1) if an error occurs.
// On error, *err will hold the reason.
// This version uses the server name. This can be a name for DNS lookup
// or a dotty or colony number format for IPv4 or IPv6.
int tftp_client_put(char *filename,
		    char *server,
		    int port,
		    char *buf,
		    int len,
		    int mode,
		    int *err) {

    int result = 0;
    int s = -1, actual_len, data_len, recv_len, from_len;
    static int put_port = 7800;
    struct sockaddr local_addr, from_addr;
    char data[SEGSIZE+sizeof(struct tftphdr)];
    struct tftphdr *hdr = (struct tftphdr *)data;
    char *cp, *fp, *sfp;
    struct timeval timeout;
    unsigned short last_good_block = 0;
    fd_set fds;
    int total_timeouts = 0;
    struct addrinfo hints;
    struct addrinfo * addrinfo;
    struct addrinfo * res;
    int error;

    *err = 0;  // Just in case

    memset(&hints,0,sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    error = getaddrinfo(server, "tftp", &hints, &res);
    if (error) {
      *err = TFTP_NETERR;
      return -1;
    }
    
    addrinfo = res;
    while (addrinfo) {
      s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
		 addrinfo->ai_protocol);
      if (s >= 0) {
	memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
	switch(addrinfo->ai_addr->sa_family) {
	case AF_INET: {
	  struct sockaddr_in * saddr = 
	    (struct sockaddr_in *) addrinfo->ai_addr;
	  struct sockaddr_in * laddr = 
	    (struct sockaddr_in *) &local_addr;
	  if (port) {
	    saddr->sin_port = htons(port);
	  }
	  laddr->sin_port = htons(put_port++);
	  laddr->sin_addr.s_addr = INADDR_ANY;
	  break;
	}
#ifdef CYGPKG_NET_INET6
	case AF_INET6: {
	  struct sockaddr_in6 * saddr = 
	    (struct sockaddr_in6 *) addrinfo->ai_addr;
	  struct sockaddr_in6 * laddr = 
	    (struct sockaddr_in6 *) &local_addr;
	  if (port) {
	    saddr->sin6_port = htons(port);
	  }
	  laddr->sin6_port = htons(put_port++);
	  laddr->sin6_addr = in6addr_any;
	  break;
	}
#endif
	default:
	  *err = TFTP_NETERR;
	  goto out;
	}
	if (bind(s, 
		 (struct sockaddr *)&local_addr, 
		 addrinfo->ai_addrlen) < 0) {
	  // Problem setting up my end
	  *err = TFTP_NETERR;
	  goto out;
	}

	while (1) {
	  // Create initial request
	  hdr->th_opcode = htons(WRQ);  // Create/write file
	  cp = (char *)&hdr->th_stuff;
	  fp = filename;
	  while (*fp) *cp++ = *fp++;
	  *cp++ = '\0';
	  if (mode == TFTP_NETASCII) {
            fp = "NETASCII";
	  } else if (mode == TFTP_OCTET) {
            fp = "OCTET";
	  } else {
            *err = TFTP_INVALID;
	    goto out;
	  }
	  while (*fp) *cp++ = *fp++;
	  *cp++ = '\0';
	  // Send request
	  if (sendto(s, data, (int)(cp-data), 0, 
		     addrinfo->ai_addr,
		     addrinfo->ai_addrlen) < 0) {
            // Problem sending request
            *err = TFTP_NETERR;
	    goto nextaddr;
	  }
	  // Wait for ACK
	  timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
	  timeout.tv_usec = 0;
	  FD_ZERO(&fds);
	  FD_SET(s, &fds);
	  if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
            if (++total_timeouts > TFTP_RETRIES_MAX) {
	      // Timeout - no ACK received
	      *err = TFTP_TIMEOUT;
	      goto nextaddr;
            }
	  } else {
            recv_len = sizeof(data);
            from_len = sizeof(from_addr);
            if ((data_len = recvfrom(s, &data, recv_len, 0, 
                                     &from_addr, &from_len)) < 0) {
	      // What happened?
	      *err = TFTP_NETERR;
	      goto out;
            }
            if (ntohs(hdr->th_opcode) == ACK) {
	      // Write request accepted - start sending data
	      break;
            } else 
	      if (ntohs(hdr->th_opcode) == ERROR) {
                *err = ntohs(hdr->th_code);
                goto out;
	      } else {
                // What kind of packet is this?
		goto out;
	      }
	  }
	}
	
	// Send data
	sfp = buf;
	last_good_block = 1;
	while (result < len) {
	  // Build packet of data to send
	  data_len = min(SEGSIZE, len-result);
	  hdr->th_opcode = htons(DATA);
	  hdr->th_block = htons(last_good_block);
	  cp = hdr->th_data;
	  fp = sfp;
	  actual_len = data_len + 4;
	  // FIXME - what about "netascii" data?
	  while (data_len-- > 0) *cp++ = *fp++;
	  // Send data packet
	  if (sendto(s, data, actual_len, 0, 
		     &from_addr, from_len) < 0) {
            // Problem sending request
            *err = TFTP_NETERR;
	    goto out;
	  }
	  // Wait for ACK
	  timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
	  timeout.tv_usec = 0;
	  FD_ZERO(&fds);
	  FD_SET(s, &fds);
	  if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
            if (++total_timeouts > TFTP_TIMEOUT_MAX) {
	      // Timeout - no data received
	      *err = TFTP_TIMEOUT;
	      goto out;
            }
	  } else {
            recv_len = sizeof(data);
            from_len = sizeof(from_addr);
            if ((data_len = recvfrom(s, &data, recv_len, 0, 
                                     &from_addr, &from_len)) < 0) {
	      // What happened?
	      *err = TFTP_NETERR;
	      goto out;
            }
            if (ntohs(hdr->th_opcode) == ACK) {
	      if (ntohs(hdr->th_block) == last_good_block) {
		// Advance pointers, etc
		sfp = fp;
		result += (actual_len - 4);
		last_good_block++;
	      } else {
		diag_printf("Send block #%d, got ACK for #%d\n", 
			    last_good_block, ntohs(hdr->th_block));
	      }
            } else 
	      if (ntohs(hdr->th_opcode) == ERROR) {
                *err = ntohs(hdr->th_code);
                goto out;
	      } else {
                // What kind of packet is this?
                *err = TFTP_PROTOCOL;
		goto out;
	      }
	  }
	}
	close (s);
	return result;
      }

      // If we got here, it means there was a problem connecting to the 
      // server. Try the next address returned by getaddrinfo
    nextaddr:
      if (-1 != s) {
	close(s);
      }
      addrinfo=addrinfo->ai_next;
    }
    // We ran into problems. Cleanup
 out:
    if (-1 != s) {
      close (s);
    }
    freeaddrinfo(res);
    return -1;
}

// EOF tftp_client.c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -