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

📄 tftpc.c

📁 TFTP server and client source code
💻 C
📖 第 1 页 / 共 2 页
字号:
/**********************************************************Date: 		NOV 28th, 2006Project :	TFTP ClientProgramers:	Jonathan FelskeAndrew Fullard Craig HolmesReza Rahmanian Adam Tomalty File:		TFTP Client (main)Purpose:	A TFTP client that will request a connections from		the server and transefet files.Notes:		Here we are using the sendto and recvfrom		functions so the server and client can exchange data.***********************************************************/#include "tftp.h"/*a function to print the Help menu*/void help (char *);/*a function to create the request packet, read or write*/int req_packet (int opcode, char *filename, char *mode, char buf[]);/*a function to creat an ACK packet*/int ack_packet (int block, char buf[]);/*a function to create the Error packets*/int err_packet (int err_code, char *err_msg, char buf[]);/*a function that will print the ip:port pair of the server or client, plus data sent or recieved*/void ip_port (struct sockaddr_in host);/*a function to send a file to the server*/void tsend (char *pFilename, struct sockaddr_in server, char *pMode,	    int sock);/*a function to get a file from the server*/void tget (char *pFilename, struct sockaddr_in server, char *pMode, int sock);/* default values which can be controlled by command line */char path[64] = "/tmp/";int port = 69;unsigned short int ackfreq = 1;int datasize = 512;int debug = 0, w_size = 1, p_length = 512;intmain (int argc, char **argv){  /*local variables */  extern char *optarg;  int sock, server_len, len, opt;	//,n;  char opcode, filename[196], mode[12] = "octet";  struct hostent *host;		/*for host information */  struct sockaddr_in server;	//, client; /*the address structure for both the server and client */  FILE *fp;			/*a pointer to a file that the client will send or get from the server */  if (argc < 2)    {      help (argv[0]);      return 0;    }  if (!(host = gethostbyname (argv[1])))    {      perror ("Client could not get host address information");      exit (2);    }/* All of the following deals with command line switches */  while ((opt = getopt (argc, argv, "dnoh:P:p:g:l:w:")) != -1)	/* this function is handy */    {      switch (opt)	{	case 'd':		/* debug mode (no opts) */	  debug = 1;	  break;	case 'P':		/* Port (opt required) */	  port = atoi (optarg);	  if (debug)	    {	      printf ("Client: The port number is: %d\n", port);	    }	  break;	case 'p':		/* put a file on the server */	  strncpy (filename, optarg, sizeof (filename) - 1);	  opcode = WRQ;	  fp = fopen (filename, "r");	/*opened the file for reading */	  if (fp == NULL)	    {	      printf ("Client: file could not be opened\n");	      return 0;	    }	  if (debug)	    {	      printf ("Client: The file name is: %s and can be read",		      filename);	    }	  fclose (fp);	  break;	case 'g':		/*get a file from the server */	  strncpy (filename, optarg, sizeof (filename) - 1);	  opcode = RRQ;	  fp = fopen (filename, "w");	/*opened the file for writting */	  if (fp == NULL)	    {	      printf ("Client: file could not be created\n");	      return 0;	    }	  if (debug)	    {	      printf ("Client: The file name is: %s and it has been created",		      filename);	    }	  fclose (fp);	  break;	case 'w':		/* Get the window size */	  ackfreq = atoi (optarg);	  if (debug)	    {	      printf ("Client: Window size is: %i\n", ackfreq);	    }	  //ackfreq = atoi (optarg);	  if (ackfreq > MAXACKFREQ)	    {	      printf		("Client: Sorry, you specified an ack frequency higher than the maximum allowed (Requested: %d Max: %d)\n",		 ackfreq, MAXACKFREQ);	      return 0;	    }	  else if (w_size == 0)	    {	      printf ("Client: Sorry, you have to ack sometime.\n");	      return 0;	    }	  break;	case 'l':		/* packet length */	  datasize = atoi (optarg);	  if (debug)	    {	      printf ("Client: Packet length is: %i bytes\n", datasize);	    }	  if (datasize > MAXDATASIZE)	    {	      printf		("Client: Sorry, you specified a data size higher than the maximum allowed (Requested: %d Max: %d)\n",		 datasize, MAXDATASIZE);	      return 0;	    }	  break;	case 'h':		/* Help (no opts) */	  help (argv[0]);	  return (0);	  break;	case 'o':	  strncpy (mode, "octet", sizeof (mode) - 1);	  if (debug)	    {	      printf ("Client: The mode is set to octet\n");	    }	  break;	case 'n':	  strncpy (mode, "netascii", sizeof (mode) - 1);	  if (debug)	    {	      printf ("Client: The mode is set to netascii\n");	    }	  break;	default:		/* everything else */	  help (argv[0]);	  return (0);	  break;	}			//end of switch    }				//end of while loop/*check for valid input*/  if (argc < 5 || argc > 12)    {      printf ("Client: wrong number of arguments: %d\n", argc);      help (argv[0]);      exit (ERROR);    }/* Done dealing with switches and the command line*/  /*Create the socket, a -1 will show us an error */  if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)    {      printf ("Client: Socket could not be created");      return 0;    }/*set the address values for the server */  memset (&server, 0, sizeof (server));	/*Clear the structure */  server.sin_family = AF_INET;	/*address family for TCP and UDP */  memcpy (&server.sin_addr, host->h_addr, host->h_length);	/*set address of server taken from gethostbyname function */  //server.sin_addr.s_addr = htonl (INADDR_ANY); /*use any address */  server.sin_port = htons (port);	/*pick a free port */  server_len = sizeof (server);	/*get the length of the server address */  if (debug)    printf ("Client: size of server_address is : %d bytes\n", server_len);  memset (buf, 0, BUFSIZ);	/*clear the buffer */  /* this is the first request message */  len = req_packet (opcode, filename, mode, buf);  if (debug)    printf ("Client: The request packt's length is: %d bytes\n", len);  if (sendto (sock, buf, len, 0, (struct sockaddr *) &server, server_len) !=      len)    {      perror ("Client: sendto has returend an error");      exit (ERROR);    }  if (debug)    ip_port (server);  switch (opcode)    {    case RRQ:			/*read from the server, download */      tget (filename, server, mode, sock);      break;    case WRQ:			/*write to the server, upload */      tsend (filename, server, mode, sock);      break;    default:      printf ("Invalid opcode detected. Ignoring packet.");    }  close (sock);			/* close the socket */  return 1;}				//end of main/******************************************************************		Function deffinitions*******************************************************************//*usage of the command:./tftpc server -P port# -g(get file)|-p(put file) <filename> -w (window size) -l (packetlength)if windowsize and packet length are not chosen then a default value of 1, for thewindow size and 512 bytes for the packet length will be set.*//* a function to display the help menu*/voidhelp (char *app){  printf    ("Usage:\n%s server [-h] [-d] [-P port] [-g] | [-p] [file-name] [-w size] [-l length] [-o] [-n]\n",     app);  printf    ("Options:\n-h (help; this message)\n-d (Debug mode)\n-P port(Port number default is 69)\n-g (get a file from the server)\n-p (send a file to the server)\n");  printf    ("-w size (set window size, default is 1)\n-l len (set max packet length, default is 512 bytes)\n");  printf    ("-o for octet file transfer (default).\n-n for netascii file transfer\n");}/* A function that will create a request packet*//*I'm not sure if I need the last 0x00 because sprintf will end the string with \0*/intreq_packet (int opcode, char *filename, char *mode, char buf[]){  int len;  len =    sprintf (buf, "%c%c%s%c%s%c", 0x00, opcode, filename, 0x00, mode, 0x00);  if (len == 0)    {      printf ("Error in creating the request packet\n");	/*could not print to the client buffer */      exit (ERROR);    }  if (debug)    {      printf ("I am creating the request packet.\n");    }  return len;}/* A function that will create an ACK packet*//*problem that we will have here is that we can only get up to 255 blocks*/intack_packet (int block, char buf[]){  int len;  len = sprintf (buf, "%c%c%c%c", 0x00, ACK, 0x00, 0x00);  buf[2] = (block & 0xFF00) >> 8;  buf[3] = (block & 0x00FF);  if (len == 0)    {      printf ("Error in creating the ACK packet\n");	/*could not print to the client buffer */      exit (ERROR);    }  if (debug)    {      printf ("I am creating the ACK packet.\n");    }  return len;}/* A function that will create an error packet based on the error code*/interr_packet (int err_code, char *err_msg, char buf[]){  int len;  memset (buf, 0, sizeof (buf));  len =    sprintf (buf, "%c%c%c%c%s%c", 0x00, ERR, 0x00, err_code, err_msg, 0x00);  if (len == 0)    {      printf ("Error in creating the ACK packet\n");	/*could not print to the client buffer */      exit (ERROR);    }  if (debug)    {      printf ("I am creating an ERROR packet.\n");    }  return len;}/* A function used for debuging to show the port numbers used*/voidip_port (struct sockaddr_in host){  printf ("The IP port pair for the host is: IP:%s Port:%d \n",	  inet_ntoa (host.sin_addr), ntohs (host.sin_port));}/**This function is called when the client would like to upload a file to the server.*/voidtsend (char *pFilename, struct sockaddr_in server, char *pMode, int sock){  int len, server_len, opcode, ssize = 0, n, i, j, bcount = 0, tid;  unsigned short int count = 0, rcount = 0, acked = 0;  unsigned char filebuf[MAXDATASIZE + 1];  unsigned char packetbuf[MAXACKFREQ][MAXDATASIZE + 12],    recvbuf[MAXDATASIZE + 12];  char filename[128], mode[12], *bufindex;	//fullpath[196],  struct sockaddr_in ack;  FILE *fp;			/* pointer to the file we will be sending */  strcpy (filename, pFilename);	//copy the pointer to the filename into a real array  strcpy (mode, pMode);		//same as above  if (debug)    printf ("Client: branched to file send function\n");/*At this point I have to wait to recieve an ACK from the server before I start sending the file*/  /*open the file to read */  fp = fopen (filename, "r");  if (fp == NULL)    {				//if the pointer is null then the file can't be opened - Bad perms OR no such file      if (debug)	printf ("Client: sending bad file: file not found (%s)\n", filename);      return;    }  else    {      if (debug)	printf ("Client: Sending file... (source: %s)\n", filename);    }//get ACK for WRQ/* The following 'for' loop is used to recieve/timeout ACKs */  for (j = 0; j < RETRIES - 2; j++)    {      server_len = sizeof (ack);      errno = EAGAIN;      n = -1;      for (i = 0; errno == EAGAIN && i <= TIMEOUT && n < 0; i++)	{	  n = recvfrom (sock, recvbuf, sizeof (recvbuf), MSG_DONTWAIT,			(struct sockaddr *) &ack, (socklen_t *) & server_len);	  usleep (1000);	}      /* if(debug)         ip_port (ack);    print the vlaue recived from the server */      tid = ntohs (ack.sin_port);	//get the tid of the server.      server.sin_port = htons (tid);	//set the tid for rest of the transfer      if (n < 0 && errno != EAGAIN)	{	  if (debug)	    printf	      ("Client: could not receive from the server (errno: %d n: %d)\n",	       errno, n);	  //resend packet	}      else if (n < 0 && errno == EAGAIN)	{	  if (debug)	    printf ("Client: Timeout waiting for ack (errno: %d n: %d)\n",		    errno, n);	  //resend packet	}      else	{			/*changed client to server here */	  if (server.sin_addr.s_addr != ack.sin_addr.s_addr)	/* checks to ensure send to ip is same from ACK IP */	    {	      if (debug)		printf		  ("Client: Error recieving ACK (ACK from invalid address)\n");	      j--;		/* in this case someone else connected to our port. Ignore this fact and retry getting the ack */	      continue;	    }	  if (tid != ntohs (server.sin_port))	/* checks to ensure get from the correct TID */	    {	      if (debug)		printf		  ("Client: Error recieving file (data from invalid tid)\n");	      len = err_packet (5, err_msg[5], buf);	      if (sendto (sock, buf, len, 0, (struct sockaddr *) &server, sizeof (server)) != len)	/* send the data packet */		{		  printf		    ("Client: Mismatch in number of sent bytes while trying to send mode error packet\n");		}	      /* if (debug)	         ip_port(server); */	      j--;	      continue;		/* we aren't going to let another connection spoil our first connection */	    }/* this formatting code is just like the code in the main function */	  bufindex = (char *) recvbuf;	//start our pointer going	  if (bufindex++[0] != 0x00)	    printf ("Client: bad first nullbyte!\n");	  opcode = *bufindex++;	  rcount = *bufindex++ << 8;	  rcount &= 0xff00;	  rcount += (*bufindex++ & 0x00ff);	  if (opcode != 4 || rcount != count)	/* ack packet should have code 4 (ack) and should be acking the packet we just sent */	    {	      if (debug)		printf		  ("Client: Remote host failed to ACK proper data packet # %d (got OP: %d Block: %d)\n",		   count, opcode, rcount);/* sending error message */	      if (opcode > 5)		{		  len = err_packet (4, err_msg[4], buf);		  if (sendto (sock, buf, len, 0, (struct sockaddr *) &server, sizeof (server)) != len)	/* send the data packet */		    {		      printf			("Client: Mismatch in number of sent bytes while trying to send mode error packet\n");		    }		}	      /* from here we will loop back and resend */	      /* if (debug)

⌨️ 快捷键说明

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