tftp_client.c

来自「eCos操作系统源码」· C语言 代码 · 共 573 行 · 第 1/2 页

C
573
字号
    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.inttftp_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.//inttftp_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 + =
减小字号Ctrl + -
显示快捷键?