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

📄 tftpd.c

📁 TFTP server and client source code
💻 C
📖 第 1 页 / 共 2 页
字号:
/**********************************************************Date: 		OCT 28th, 2006Project :	NET4900 Project: tftpd.c TFTP ServerProgramers:	Craig HolmesReza Rahmanian File:		TFTP Server (main)Purpose:	A TFTP server that will accept a connections from		a client and transefet files.Notes:		Here we are using the sendto and recvfrom		functions so the server and client can exchange data.***********************************************************************//* Include our header which contains libaries and defines */#include "tftp.h"/* Function prototypes */void tsend (char *, struct sockaddr_in, char *, int);void tget (char *, struct sockaddr_in, char *, int);int isnotvaliddir (char *);void usage (void);/* default values which can be controlled by command line */int debug = 0;char path[64] = "/tmp/";int port = 69;unsigned short int ackfreq = 1;int datasize = 512;intmain (int argc, char **argv){  /*local variables */  extern char *optarg;  int sock, n, client_len, pid, status, opt, tid;  char opcode, *bufindex, filename[196], mode[12];  struct sockaddr_in server, client;	/*the address structure for both the server and client *//* All of the following deals with command line switches */  while ((opt = getopt (argc, argv, "dh:p:P:a:s:")) != -1)	/* this function is handy */    {      switch (opt)	{	case 'p':		/* path (opt required) */	  if (!isnotvaliddir (optarg))	    {	      printf		("Sorry, you specified an invalid/non-existant directory. Make sure the directory exists.\n");	      return 0;	    }	  strncpy (path, optarg, sizeof (path) - 1);	  break;	case 'd':		/* debug mode (no opts) */	  debug = 1;	  break;	case 'P':		/* Port (opt required) */	  port = atoi (optarg);	  break;	case 'a':		/* ack frequency (opt required) */	  ackfreq = atoi (optarg);	  if (ackfreq > MAXACKFREQ)	    {	      printf		("Sorry, you specified an ack frequency higher than the maximum allowed (Requested: %d Max: %d)\n",		 ackfreq, MAXACKFREQ);	      return 0;	    }	  else if (ackfreq == 0)	    {	      printf ("Sorry, you have to ack sometime.\n");	      return 0;	    }	  break;	case 's':		/* File chunk size (opt required) */	  datasize = atoi (optarg);	  if (datasize > MAXDATASIZE)	    {	      printf		("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) */	  usage ();	  return (0);	  break;	default:		/* everything else */	  usage ();	  return (0);	  break;	}    }/* Done dealing with switches */  /*Create the socket, a -1 will show us an error */  if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)    {      printf ("Server Socket could not be created");      return 0;    }  /*set the address values for the server */  server.sin_family = AF_INET;	/*address family for TCP and UDP */  server.sin_addr.s_addr = htonl (INADDR_ANY);	/*use any address */  server.sin_port = htons (port);	/*pick a free port */  /*Bind the socket */  if (bind (sock, (struct sockaddr *) &server, sizeof (server)) < 0)    {      printf	("Server bind failed. Server already running? Proper permissions?\n");      return (2);    }  if (!debug)    {      pid = fork ();      if (pid != 0)		/* if pid != 0 then we are the parent */	{	  if (pid == -1)	    {	      printf ("Error: Fork failed!\n");	      return 0;	    }	  else	    {	      printf ("Daemon Successfully forked (pid: %d)\n", pid);	      return 1;	    }	}    }  else    {      printf	("tftpd server is running in debug mode and will not fork. \nMulti-threaded mode disabled.\nServer is bound to port %d and awaiting connections\nfile path: %s\n",	 ntohs (server.sin_port), path);    }  /*endless loop to get connections from the client */  while (1)    {      client_len = sizeof (client);	/*get the length of the client */      memset (buf, 0, BUFSIZ);	/*clear the buffer */      /*the fs message */      n = 0;      while (errno == EAGAIN || n == 0)	/* This loop is required because on linux we have to acknowledge complete children with waitpid. Ugh. */	{	  waitpid (-1, &status, WNOHANG);	  n =	    recvfrom (sock, buf, BUFSIZ, MSG_DONTWAIT,		      (struct sockaddr *) &client,		      (socklen_t *) & client_len);	  if (n < 0 && errno != EAGAIN)	    {	      printf ("The server could not receive from the client");	      return 0;	    }	  usleep (1000);	}      if (debug)	printf ("Connection from %s, port %d\n",		inet_ntoa (client.sin_addr), ntohs (client.sin_port));      bufindex = buf;		//start our pointer going      if (bufindex++[0] != 0x00)	{			//first TFTP packet byte needs to be null. Once the value is taken increment it.	  if (debug)	    printf ("Malformed tftp packet.\n");	  return 0;	}      tid = ntohs (client.sin_port);	/* record the tid */      opcode = *bufindex++;	//opcode is in the second byte.      if (opcode == 1 || opcode == 2)	// RRQ or WRQ. The only two really valid packets on port 69	{	  strncpy (filename, bufindex, sizeof (filename) - 1);	/* Our pointer has been nudged along the recieved string so the first char is the beginning of the filename. This filename is null deliimited so we can use the str family of functions */	  bufindex += strlen (filename) + 1;	/* move the pointer to after the filename + null byte in the string */	  strncpy (mode, bufindex, sizeof (mode) - 1);	/* like the filename, we are at the beginning of the null delimited mode */	  bufindex += strlen (mode) + 1;	/* move pointer... */	  if (debug)	    printf ("opcode: %x filename: %s packet size: %d mode: %s\n", opcode, filename, n, mode);	/*show the message to the server */	}      else	{	  if (debug)	    printf ("opcode: %x size: %d \n", opcode, sizeof (n));	/*show the message to the server */	}      switch (opcode)		/* case one and two are valid on port 69 or server port... no other codes are */	{	case 1:	  if (debug)	    {	      printf ("Opcode indicates file read request\n");	      tsend (filename, client, mode, tid);	    }	  else	    {	      pid = fork ();	      if (pid == 0)		{		/* if we are pid != 0 then we are the parent */		  tsend (filename, client, mode, tid);		  exit (1);		}	    }	  break;	case 2:	  if (debug)	    {	      printf ("Opcode indicates file write request\n");	      tget (filename, client, mode, tid);	    }	  else	    {	      pid = fork ();	      if (pid == 0)	/* if we are pid != 0 then we are the parent */		{		  tget (filename, client, mode, tid);		  exit (1);		}	    }	  break;	default:	  if (debug)	    printf ("Invalid opcode detected. Ignoring packet.");	  break;	}			//end of while    }}voidtget (char *pFilename, struct sockaddr_in client, char *pMode, int tid){  /* local variables */  int sock, len, client_len, opcode, i, j, n, flag = 1;  unsigned short int count = 0, rcount = 0;  unsigned char filebuf[MAXDATASIZE + 1];  unsigned char packetbuf[MAXDATASIZE + 12];  extern int errno;  char filename[128], mode[12], fullpath[196], *bufindex, ackbuf[512];  struct sockaddr_in data;  FILE *fp;			/* pointer to the file we will be getting */  strcpy (filename, pFilename);	//copy the pointer to the filename into a real array  strcpy (mode, pMode);		//same as above  if (debug)    printf ("branched to file receive function\n");  if ((sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)	//startup a socket    {      printf ("Server reconnect for getting did not work correctly\n");      return;    }  if (!strncasecmp (mode, "octet", 5) && !strncasecmp (mode, "netascii", 8))	/* these two are the only modes we accept */    {      if (!strncasecmp (mode, "mail", 4))	len = sprintf ((char *) packetbuf,		       "%c%c%c%cThis tftp server will not operate as a mail relay%c",		       0x00, 0x05, 0x00, 0x04, 0x00);      else	len = sprintf ((char *) packetbuf,		       "%c%c%c%cUnrecognized mode (%s)%c",		       0x00, 0x05, 0x00, 0x04, mode, 0x00);      if (sendto (sock, packetbuf, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)	/* send the data packet */	{	  printf	    ("Mismatch in number of sent bytes while trying to send mode error packet\n");	}      return;    }  if (strchr (filename, 0x5C) || strchr (filename, 0x2F))	//look for illegal characters in the filename string these are \ and /    {      if (debug)	printf ("Client requested to upload bad file: forbidden name\n");      len =	sprintf ((char *) packetbuf,		 "%c%c%c%cIllegal filename.(%s) You may not attempt to descend or ascend directories.%c",		 0x00, 0x05, 0x00, 0x00, filename, 0x00);      if (sendto (sock, packetbuf, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)	/* send the data packet */	{	  printf	    ("Mismatch in number of sent bytes while trying to send error packet\n");	}      return;    }  strcpy (fullpath, path);  strncat (fullpath, filename, sizeof (fullpath) - 1);	//build the full file path by appending filename to path  fp = fopen (fullpath, "w");	/* open the file for writing */  if (fp == NULL)    {				//if the pointer is null then the file can't be opened - Bad perms       if (debug)	printf ("Server requested bad file: cannot open for writing (%s)\n",		fullpath);      len =	sprintf ((char *) packetbuf,		 "%c%c%c%cFile cannot be opened for writing (%s)%c", 0x00,		 0x05, 0x00, 0x02, fullpath, 0x00);      if (sendto (sock, packetbuf, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)	/* send the data packet */	{	  printf	    ("Mismatch in number of sent bytes while trying to send error packet\n");	}      return;    }  else				/* everything worked fine */    {      if (debug)	printf ("Getting file... (destination: %s) \n", fullpath);    }  /* zero the buffer before we begin */  memset (filebuf, 0, sizeof (filebuf));  n = datasize + 4;  do    {      /* zero buffers so if there are any errors only NULLs will be exposed */      memset (packetbuf, 0, sizeof (packetbuf));      memset (ackbuf, 0, sizeof (ackbuf));      if (debug)	printf ("== just entered do-while count: %d  n: %d\n", count, n);      if (count == 0 || (count % ackfreq) == 0 || n != (datasize + 4))	/* ack the first packet, count % ackfreq will make it so we only ACK everyone ackfreq ACKs, ack the last packet */	{	  len = sprintf (ackbuf, "%c%c%c%c", 0x00, 0x04, 0x00, 0x00);	  ackbuf[2] = (count & 0xFF00) >> 8;	//fill in the count (top number first)	  ackbuf[3] = (count & 0x00FF);	//fill in the lower part of the count	  if (debug)	    printf ("Sending ack # %04d (length: %d)\n", count, len);	  if (sendto	      (sock, ackbuf, len, 0, (struct sockaddr *) &client,	       sizeof (client)) != len)	    {	      if (debug)		printf ("Mismatch in number of sent bytes\n");	      return;	    }	}      else if (debug)	{	  printf ("No ack required on packet count %d\n", count);	}      if (n != (datasize + 4))	/* remember if our datasize is less than a full packet this was the last packet to be received */	{	  if (debug)	    printf	      ("Last chunk detected (file chunk size: %d). exiting while loop\n",	       n - 4);	  goto done;		/* gotos are not optimal, but a good solution when exiting a multi-layer loop */	}      memset (filebuf, 0, sizeof (filebuf));      count++;      for (j = 0; j < RETRIES; j++)	/* this allows us to loop until we either break out by getting the correct ack OR time out because we've looped more than RETRIES times */	{	  client_len = sizeof (data);	  errno = EAGAIN;	/* this allows us to enter the loop */	  n = -1;	  for (i = 0; errno == EAGAIN && i <= TIMEOUT && n < 0; i++)	/* this for loop will just keep checking the non-blocking socket until timeout */	    {	      n =		recvfrom (sock, packetbuf, sizeof (packetbuf) - 1,			  MSG_DONTWAIT, (struct sockaddr *) &data,			  (socklen_t *) & client_len);	      /*if (debug)	         printf ("The value recieved is n: %d\n",n); */	      usleep (1000);	    }	  if (n < 0 && errno != EAGAIN)	/* this will be true when there is an error that isn't the WOULD BLOCK error */	    {	      if (debug)		printf		  ("The server could not receive from the client (errno: %d n: %d)\n",		   errno, n);	      //resend packet	    }	  else if (n < 0 && errno == EAGAIN)	/* this is true when the error IS would block. This means we timed out */	    {	      if (debug)		printf ("Timeout waiting for data (errno: %d == %d n: %d)\n",			errno, EAGAIN, n);	      //resend packet	    }	  else	    {	      if (client.sin_addr.s_addr != data.sin_addr.s_addr)	/* checks to ensure get from ip is same from ACK IP */		{

⌨️ 快捷键说明

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