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

📄 tftpd.c

📁 TFTP Deamon Process code
💻 C
📖 第 1 页 / 共 3 页
字号:
          close(data->sockfd);  
     }  
  
     /* update stats */  
     stats_thread_usage_locked();  
  
     /* Remove the thread_data structure from the list, if it as been 
        added. */  
     if (!abort)  
          tftpd_list_remove(data);  
  
     /* Free memory. */  
     free(data->data_buffer);  
     free(data->ack_buffer);  
     free(data->tftp_options);  
  
     /* Three things may append with client_info: 
        1- We have only one client (probably not multicast) 
        2- We do not have any client anymore, we transfered it to an other 
        server 
        3- We do not have any client, they are all done. 
     */  
     tftpd_clientlist_free(data->client_info);  
     free(data);  
       
     logger(LOG_INFO, "Server thread exiting");  
     pthread_exit(NULL);  
}  
  
/* 
 * If we receive signals, we must exit in a clean way. This means 
 * sending an ERROR packet to all clients to terminate the connection. 
 */  
void signal_handler(int signal)  
{  
     switch (signal)  
     {  
     case SIGINT:  
     case SIGTERM:  
          logger(LOG_ERR, "SIGINT received, stopping threads and exiting.");  
          /* Send cancellation message */  
          tftpd_cancel = 1;  
          break;  
     case SIGKILL:  
          logger(LOG_ERR, "SIGKILL received, aborting.");  
          exit(ERR);  
          break;  
     default:  
          logger(LOG_WARNING, "Signal %d received, ignoring.", signal);  
          break;  
     }  
}  
  
/* 
 * Parse the command line using the standard getopt function. 
 */  
int tftpd_cmd_line_options(int argc, char **argv)  
{  
     int c;  
  
     static struct option options[] = {  
          { "help", 0, NULL, 'h' },  
          { "tftpd-timeout", 1, NULL, 't' },  
          { "retry-timeout", 1, NULL, 'r' },  
          { "verbose", 2, NULL, 'v' },  
          { "maxthread", 1, NULL, 'm' },  
          { "no-timeout", 0, NULL, 'T' },  
          { "no-tsize", 0, NULL, 'S' },  
          { "no-blksize", 0, NULL, 'B' },  
          { "no-multicast", 0, NULL, 'M' },  
          { "logfile", 1, NULL, 'L' },  
          { "daemon", 0, NULL, 'D' },  
          { "port", 1, NULL, 'P' },  
          { "help", 0, NULL, 'h' },  
          { "version", 0, NULL, 'V' },  
          { 0, 0, 0, 0 }  
     };  
            
     while ((c = getopt_long(argc, argv, "Vht:r:v::m:",  
                             options, NULL)) != EOF)  
     {  
          switch (c)  
          {  
          case 't':  
               tftpd_timeout = atoi(optarg);  
               break;  
          case 'r':  
               retry_timeout = atoi(optarg);  
               break;  
          case 'm':  
               tftpd_max_thread = atoi(optarg);  
               break;  
          case 'v':  
               if (optarg)  
                    logging_level = atoi(optarg);  
               else  
                    logging_level++;  
               break;  
          case 'T':  
               tftp_default_options[OPT_TIMEOUT].enabled = 0;  
               break;  
          case 'S':  
               tftp_default_options[OPT_TSIZE].enabled = 0;  
               break;  
          case 'B':  
               tftp_default_options[OPT_BLKSIZE].enabled = 0;  
               break;  
          case 'M':  
               tftp_default_options[OPT_MULTICAST].enabled = 0;  
               break;  
          case 'L':  
               log_file = strdup(optarg);  
               break;  
          case 'D':  
               tftpd_daemon = 1;  
               break;  
          case 'P':  
               tftpd_port = (short)atoi(optarg);  
               break;  
          case 'V':  
               printf("atftp-%s (server)\n", VERSION);  
               exit(0);  
          case 'h':  
               tftpd_usage();  
               exit(0);  
          case '?':  
               exit(1);  
               break;  
          }  
     }  
  
     /* verify that only one arguement is left */  
     if (optind < argc)  
          strncpy(directory, argv[optind], MAXLEN);  
     /* make sure the last caracter is a / */  
     if (directory[strlen(directory)] != '/')  
          strcat(directory, "/");  
  
     return OK;  
}  
  
/* 
 * Output option to the syslog. 
 */  
void tftpd_log_options(void)  
{  
     if (tftpd_daemon == 1)  
          logger(LOG_INFO, "  running in daemon mode on port %d", tftpd_port);  
     else  
          logger(LOG_INFO, "  started by inetd");  
     logger(LOG_INFO, "  logging level: %d", logging_level);  
     logger(LOG_INFO, "  directory: %s", directory);  
     logger(LOG_INFO, "  log file: %s", (log_file==NULL) ? "syslog":log_file);  
     if (tftpd_daemon == 1)  
          logger(LOG_INFO, "  server timeout: Not used");  
     else  
          logger(LOG_INFO, "  server timeout: %d", tftpd_timeout);  
     logger(LOG_INFO, "  tftp retry timeout: %d", retry_timeout);  
     logger(LOG_INFO, "  maximum number of thread: %d", tftpd_max_thread);  
     logger(LOG_INFO, "  option timeout:   %s",  
            tftp_default_options[OPT_TIMEOUT].enabled ? "enabled":"disabled");  
     logger(LOG_INFO, "  option tzise:     %s",  
            tftp_default_options[OPT_TSIZE].enabled ? "enabled":"disabled");  
     logger(LOG_INFO, "  option blksize:   %s",  
            tftp_default_options[OPT_BLKSIZE].enabled ? "enabled":"disabled");  
     logger(LOG_INFO, "  option multicast: %s",  
            tftp_default_options[OPT_MULTICAST].enabled ? "enabled":"disabled");  
}  
  
/* 
 * Show a nice usage... 
 */  
void tftpd_usage(void)  
{  
     printf("*** tftpd must be called by inetd ***\n"  
            "Usage: tftpd [options] [directory]\n"  
            " [options] may be:\n"  
            "  -t, --tftpd-timeout <VALUE>: number of second of inactivity"  
            " before exiting\n"  
            "  -r, --retry-timeout <VALUE>: time to wait a reply before"  
            " retransmition\n"  
            "  -m, --maxthread <VALUE>    : number of concurrent thread"  
            " allowed\n"  
            "  -v, --verbose [value]      : increase or set the level of"  
            " output messages\n"  
            "  --no-timeout               : disable 'timeout' from RFC2349\n"  
            "  --no-tisize                : disable 'tsize' from RFC2349\n"  
            "  --no-blksize               : disable 'blksize' from RFC2348\n"  
            "  --no-multicast             : disable 'multicast' from RFC2090\n"  
            "  --logfile                  : logfile to log logs to ;-)\n"  
            "  --daemon                   : run atftpd standalone (no inetd)\n"  
            "  --port                     : port the server will listen\n"  
            "  -h, --help                 : print this help\n"  
            "  -V, --version              : print version information\n"  
            "\n"  
            " [directories] must be a world readable/writable directories.\n"  
            " By default /tftpboot is assumed."  
            "\n");  
}  

/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */
/*
 * tftpd.c
 *    main server file
 *
 * $Id: tftpd.c,v 1.25 2001/07/08 17:45:46 jp Exp $
 *
 * Copyright (c) 2000 Jean-Pierre Lefebvre 
 *                and Remi Lefebvre 
 *
 * atftp is free software; you can redistribute them and/or modify them
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 */

#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#include 
#include 
#include 
#include 
#include "tftpd.h"
#include "tftp_io.h"
#include "tftp_def.h"
#include "logger.h"
#include "options.h"
#include "stats.h"

/*
 * Global variables set by main when starting. Read-only for threads
 */
int tftpd_max_thread = 100;     /* number of concurent thread allowed */
int tftpd_timeout = 300;        /* number of second of inactivity
                               before exiting */
char directory[MAXLEN] = "/tftpboot/";
int retry_timeout = S_TIMEOUT;

int tftpd_daemon = 0;           /* By default we are started by inetd */
short tftpd_port = 0;

int tftpd_cancel = 0;                 /* When true, thread must exit. */

/*
 * "logging level" is the maximum error level that will get logged.
 *  This can be increased with the -v switch.
 */
int logging_level = LOG_NOTICE;
char *log_file = NULL;
 
/*
 * We need a lock on stdin from the time we notice fresh data coming from
 * stdin to the time the freshly created server thread as read it.
 */
pthread_mutex_t stdin_mutex = PTHREAD_MUTEX_INITIALIZER;

/*
 * Function defined in this file
 */
void *tftpd_receive_request(void *);
void signal_handler(int signal);
int tftpd_cmd_line_options(int argc, char **argv);
void tftpd_log_options(void);
void tftpd_usage(void);

/*
 * Main thread. Do required initialisation and then go through a loop
 * listening for client requests. When a request arrives, we allocate
 * memory for a thread data structure and start a thread to serve the
 * new client. If theres no activity for more than 'tftpd_timeout'
 * seconds, we exit and tftpd must be respawned by inetd.
 */
int main(int argc, char **argv)
{
     fd_set rfds;               /* for select */
     struct timeval tv;         /* for select */
     int run = 1;               /* while (run) loop */
     struct thread_data *new;   /* for allocation of new thread_data */
     int sockfd;                /* used in daemon mode */
     struct sockaddr_in sa;     /* used in daemon mode */
     struct servent *serv;
     struct passwd *user;
     struct group *group;

     /*
      * Parse command line options. We parse before verifying
      * if we are running on a tty or not to make it possible to
      * verify the command line arguments
      */
     if (tftpd_cmd_line_options(argc, argv) == ERR)
          exit(1);

     /*
      * Can't be started from the prompt without explicitely specifying 
      * the --daemon option.
      */
     if (isatty(0) && !(tftpd_daemon))
     {
          tftpd_usage();
          exit(1);
     }

     /*
      * In tftpd is run in daemon mode ...
      */
     if (tftpd_daemon)
     {
          /* daemonize here */
          if (daemon(0, 0) == -1)
               exit(2);

          /* find the port */
          if (tftpd_port == 0)
          {
               if ((serv = getservbyname("tftp", "udp")) == NULL)
               {
                    logger(LOG_ERR, "atftpd: udp/tftp, unknown service");
                    exit(1);
               }
               tftpd_port = ntohs(serv->s_port);
          }
          /* initialise sockaddr_in structure */
          memset(&sa, 0, sizeof(sa));
          sa.sin_family = AF_INET;
          sa.sin_addr.s_addr = htonl(INADDR_ANY);
          sa.sin_port = htons(tftpd_port);
          /* open the socket */
          if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == 0)
          {
               logger(LOG_ERR, "atftpd: can't open socket");
               exit(1);
          }
          /* bind the socket to the tftp port  */
          if (bind(sockfd, (struct sockaddr*)&sa, sizeof(sa)) < 0)
          {
               logger(LOG_ERR, "atftpd: can't bind port");
               exit(1);
          }
          /* dup sockfd on 0,1,2 */
          dup2(sockfd, 0);
          dup2(sockfd, 1);
          dup2(sockfd, 2);
          close(sockfd);

          /* release priviliedge */
          user = getpwnam("nobody");
          group = getgrnam("nogroup");
          setgid(group->gr_gid);
          setuid(user->pw_uid);
     }

     /* Register signal handler. */
     signal(SIGINT, signal_handler);
     signal(SIGTERM, signal_handler);
     signal(SIGKILL, signal_handler);

     /* Using syslog facilties through a wrapper. This call divert logs
      * to a file as specified or do nothing
      */
     open_logger("tftpd", log_file, logging_level);
     logger(LOG_NOTICE, "Trivial FTP server started (%s)", VERSION);

     /* print summary of options */
     tftpd_log_options();

     /* start collecting stats */
     stats_start();

     /* Wait for read or write request and exit if timeout. */
     while (run)
     {
          /*
           * inetd dups the socket file descriptor to 0, 1 and 2 so we can
           * use any of those as the socket fd. We use 0. stdout and stderr
           * may not be used to print messages.
           */
          FD_ZERO(&rfds);
          FD_SET(0, &rfds);
          tv.tv_sec = tftpd_timeout;
          tv.tv_usec = 0;

          /* We need to lock stdin, and release it when the thread
             is done reading the request. */
          pthread_mutex_lock(&stdin_mutex);
          
          /* A timeout of 0 is interpreted as infinity */
          if (!tftpd_cancel)
          {
               if ((tftpd_timeout == 0) || (tftpd_daemon))
                    select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
               else
                    select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
          }

          if (FD_ISSET(0, &rfds) && (!tftpd_cancel))
          {
               /* Allocate memory for thread_data structure. */
               if ((new = malloc(sizeof(struct thread_data))) == NULL)
               {

⌨️ 快捷键说明

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