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

📄 tftpd.c

📁 THIS IS HTTP CURL Example
💻 C
📖 第 1 页 / 共 2 页
字号:
/*************************************************************************** *                                  _   _ ____  _ *  Project                     ___| | | |  _ \| | *                             / __| | | | |_) | | *                            | (__| |_| |  _ <| |___ *                             \___|\___/|_| \_\_____| * * $Id: tftpd.c,v 1.30 2007-11-15 13:20:18 yangtse Exp $ * * Trivial file transfer protocol server. * * This code includes many modifications by Jim Guyton <guyton@rand-unix> * * This source file was started based on netkit-tftpd 0.17 * Heavily modified for curl's test suite *//* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *      This product includes software developed by the University of *      California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "setup.h" /* portability help from the lib directory */#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#include <signal.h>#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef HAVE_ARPA_TFTP_H#include <arpa/tftp.h>#else#include "tftp.h"#endif#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef HAVE_SYS_FILIO_H/* FIONREAD on Solaris 7 */#include <sys/filio.h>#endif#include <setjmp.h>#include <stdio.h>#include <errno.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#ifdef HAVE_PWD_H#include <pwd.h>#endif#define ENABLE_CURLX_PRINTF/* make the curlx header define all printf() functions to use the curlx_*   versions instead */#include "curlx.h" /* from the private lib dir */#include "getpart.h"#include "util.h"/* include memdebug.h last */#include "memdebug.h"struct testcase {  char *buffer;   /* holds the file data to send to the client */  size_t bufsize; /* size of the data in buffer */  char *rptr;     /* read pointer into the buffer */  size_t rcount;  /* amount of data left to read of the file */  long num;       /* test case number */  int ofile;      /* file descriptor for output file when uploading to us */};static int synchnet(curl_socket_t);static struct tftphdr *r_init(void);static struct tftphdr *w_init(void);static int readit(struct testcase *test, struct tftphdr **dpp, int convert);static int writeit(struct testcase *test, struct tftphdr **dpp, int ct,                   int convert);static void mysignal(int, void (*func)(int));#define TIMEOUT         5#define PKTSIZE SEGSIZE+4struct formats;static int tftp(struct testcase *test, struct tftphdr *tp, int size);static void nak(int error);static void sendtftp(struct testcase *test, struct formats *pf);static void recvtftp(struct testcase *test, struct formats *pf);static int validate_access(struct testcase *test, const char *, int);static curl_socket_t peer;static int rexmtval = TIMEOUT;static int maxtimeout = 5*TIMEOUT;static char buf[PKTSIZE];static char ackbuf[PKTSIZE];static struct sockaddr_in from;static socklen_t fromlen;struct bf {  int counter;            /* size of data in buffer, or flag */  char buf[PKTSIZE];      /* room for data packet */} bfs[2];                                /* Values for bf.counter  */#define BF_ALLOC -3             /* alloc'd but not yet filled */#define BF_FREE  -2             /* free *//* [-1 .. SEGSIZE] = size of data in the data buffer */static int nextone;     /* index of next buffer to use */static int current;     /* index of buffer in use */                        /* control flags for crlf conversions */int newline = 0;        /* fillbuf: in middle of newline expansion */int prevchar = -1;      /* putbuf: previous char (cr check) */static void read_ahead(struct testcase *test,                       int convert /* if true, convert to ascii */);static ssize_t write_behind(struct testcase *test, int convert);static struct tftphdr *rw_init(int);static struct tftphdr *w_init(void) { return rw_init(0); } /* write-behind */static struct tftphdr *r_init(void) { return rw_init(1); } /* read-ahead */static struct tftphdr *rw_init(int x)              /* init for either read-ahead or write-behind */{                           /* zero for write-behind, one for read-head */  newline = 0;            /* init crlf flag */  prevchar = -1;  bfs[0].counter =  BF_ALLOC;     /* pass out the first buffer */  current = 0;  bfs[1].counter = BF_FREE;  nextone = x;                    /* ahead or behind? */  return (struct tftphdr *)bfs[0].buf;}/* Have emptied current buffer by sending to net and getting ack.   Free it and return next buffer filled with data. */static int readit(struct testcase *test, struct tftphdr **dpp,           int convert /* if true, convert to ascii */){  struct bf *b;  bfs[current].counter = BF_FREE; /* free old one */  current = !current;             /* "incr" current */  b = &bfs[current];              /* look at new buffer */  if (b->counter == BF_FREE)      /* if it's empty */    read_ahead(test, convert);      /* fill it */  *dpp = (struct tftphdr *)b->buf;        /* set caller's ptr */  return b->counter;}#undef MIN /* some systems have this defined already, some don't */#define MIN(x,y) ((x)<(y)?(x):(y));/* * fill the input buffer, doing ascii conversions if requested * conversions are  lf -> cr,lf  and cr -> cr, nul */static void read_ahead(struct testcase *test,                       int convert /* if true, convert to ascii */){  int i;  char *p;  int c;  struct bf *b;  struct tftphdr *dp;  b = &bfs[nextone];              /* look at "next" buffer */  if (b->counter != BF_FREE)      /* nop if not free */    return;  nextone = !nextone;             /* "incr" next buffer ptr */  dp = (struct tftphdr *)b->buf;  if (convert == 0) {    /* The former file reading code did this:       b->counter = read(fileno(file), dp->th_data, SEGSIZE); */    size_t copy_n = MIN(SEGSIZE, test->rcount);    memcpy(dp->th_data, test->rptr, copy_n);    /* decrease amount, advance pointer */    test->rcount -= copy_n;    test->rptr += copy_n;    b->counter = (int)copy_n;    return;  }  p = dp->th_data;  for (i = 0 ; i < SEGSIZE; i++) {    if (newline) {      if (prevchar == '\n')        c = '\n';       /* lf to cr,lf */      else        c = '\0';       /* cr to cr,nul */      newline = 0;    }    else {      if(test->rcount) {        c=test->rptr[0];        test->rptr++;        test->rcount--;      }      else        break;      if (c == '\n' || c == '\r') {        prevchar = c;        c = '\r';        newline = 1;      }    }    *p++ = (char)c;  }  b->counter = (int)(p - dp->th_data);}/* Update count associated with the buffer, get new buffer from the queue.   Calls write_behind only if next buffer not available. */static int writeit(struct testcase *test, struct tftphdr **dpp,                   int ct, int convert){  bfs[current].counter = ct;      /* set size of data to write */  current = !current;             /* switch to other buffer */  if (bfs[current].counter != BF_FREE)     /* if not free */    write_behind(test, convert);     /* flush it */  bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */  *dpp =  (struct tftphdr *)bfs[current].buf;  return ct;                      /* this is a lie of course */}/* * Output a buffer to a file, converting from netascii if requested. * CR,NUL -> CR  and CR,LF => LF. * Note spec is undefined if we get CR as last byte of file or a * CR followed by anything else.  In this case we leave it alone. */static ssize_t write_behind(struct testcase *test, int convert){  char *writebuf;  int count;  int ct;  char *p;  int c;                          /* current character */  struct bf *b;  struct tftphdr *dp;  b = &bfs[nextone];  if (b->counter < -1)            /* anything to flush? */    return 0;                     /* just nop if nothing to do */  if(!test->ofile) {    char outfile[256];    snprintf(outfile, sizeof(outfile), "log/upload.%ld", test->num);    test->ofile=open(outfile, O_CREAT|O_RDWR, 0777);    if(test->ofile == -1) {      logmsg("Couldn't create and/or open file %s for upload!", outfile);      return -1; /* failure! */    }  }  count = b->counter;             /* remember byte count */  b->counter = BF_FREE;           /* reset flag */  dp = (struct tftphdr *)b->buf;  nextone = !nextone;             /* incr for next time */  writebuf = dp->th_data;  if (count <= 0)    return -1;                    /* nak logic? */  if (convert == 0)    return write(test->ofile, writebuf, count);  p = writebuf;  ct = count;  while (ct--) {                  /* loop over the buffer */    c = *p++;                     /* pick up a character */    if (prevchar == '\r') {       /* if prev char was cr */      if (c == '\n')              /* if have cr,lf then just */        lseek(test->ofile, -1, SEEK_CUR); /* smash lf on top of the cr */      else        if (c == '\0')            /* if have cr,nul then */          goto skipit;            /* just skip over the putc */      /* else just fall through and allow it */    }    /* formerly       putc(c, file); */    write(test->ofile, &c, 1);    skipit:    prevchar = c;  }  return count;}/* When an error has occurred, it is possible that the two sides are out of * synch.  Ie: that what I think is the other side's response to packet N is * really their response to packet N-1. * * So, to try to prevent that, we flush all the input queued up for us on the * network connection on our host. * * We return the number of packets we flushed (mostly for reporting when trace * is active). */static int synchnet(curl_socket_t f /* socket to flush */){#if defined(HAVE_IOCTLSOCKET)  unsigned long i;#else  int i;#endif  int j = 0;  char rbuf[PKTSIZE];  struct sockaddr_in fromaddr;  socklen_t fromaddrlen;  while (1) {#if defined(HAVE_IOCTLSOCKET)    (void) ioctlsocket(f, FIONREAD, &i);#else    (void) ioctl(f, FIONREAD, &i);#endif    if (i) {      j++;      fromaddrlen = sizeof fromaddr;      (void) recvfrom(f, rbuf, sizeof (rbuf), 0,                      (struct sockaddr *)&fromaddr, &fromaddrlen);    }    else      break;  }  return j;}#if defined(HAVE_ALARM) && defined(SIGALRM)/* * Like signal(), but with well-defined semantics. */static void mysignal(int sig, void (*handler)(int)){  struct sigaction sa;  memset(&sa, 0, sizeof(sa));  sa.sa_handler = handler;  sigaction(sig, &sa, NULL);}#endif#ifndef DEFAULT_LOGFILE#define DEFAULT_LOGFILE "log/tftpd.log"#endif#define DEFAULT_PORT 8999 /* UDP */const char *serverlogfile = DEFAULT_LOGFILE;#define REQUEST_DUMP  "log/server.input"char use_ipv6=FALSE;int main(int argc, char **argv){  struct sockaddr_in me;#ifdef ENABLE_IPV6  struct sockaddr_in6 me6;#endif /* ENABLE_IPV6 */  struct tftphdr *tp;  int n = 0;  int arg = 1;  FILE *pidfile;  char *pidname= (char *)".tftpd.pid";  unsigned short port = DEFAULT_PORT;  curl_socket_t sock;  int flag;  int rc;  int error;  struct testcase test;  while(argc>arg) {    if(!strcmp("--version", argv[arg])) {      printf("tftpd IPv4%s\n",#ifdef ENABLE_IPV6             "/IPv6"#else             ""#endif             );      return 0;    }    else if(!strcmp("--pidfile", argv[arg])) {      arg++;      if(argc>arg)        pidname = argv[arg++];    }    else if(!strcmp("--ipv6", argv[arg])) {#ifdef ENABLE_IPV6      use_ipv6=TRUE;#endif      arg++;    }    else if(argc>arg) {      if(atoi(argv[arg]))        port = (unsigned short)atoi(argv[arg++]);      if(argc>arg)        path = argv[arg++];    }  }#ifdef WIN32  win32_init();  atexit(win32_cleanup);#endif#ifdef ENABLE_IPV6  if(!use_ipv6)#endif    sock = socket(AF_INET, SOCK_DGRAM, 0);#ifdef ENABLE_IPV6  else    sock = socket(AF_INET6, SOCK_DGRAM, 0);#endif  if (sock < 0) {    perror("opening stream socket");    logmsg("Error opening socket");    return 1;  }  flag = 1;  if (setsockopt

⌨️ 快捷键说明

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