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

📄 tftpd.c

📁 能把所有线程的数据和环境记录到文件,方便调试.
💻 C
📖 第 1 页 / 共 2 页
字号:
        char           buf[TFTPHDRSIZE + SEGSIZE];        struct tftphdr *send_tftp = (struct tftphdr *)buf;        char           *ptr       = send_tftp->th_msg;        int            retry;        /* Deal with partial reads, and reblock in units of 512 bytes.       */        count = 0;        while (!ioerr && count < SEGSIZE) {          int rc = read(src, ptr + count, SEGSIZE - count);          if (rc < 0) {            if (errno == EINTR)              continue;            ioerr = errno;            break;          } else if (rc == 0) {            break;          }          count += rc;        }        /* Report any read errors back to the client.                        */        if (count == 0 && ioerr) {          err = ENOTFOUND;          *msg_buf = '\000';          msg = strerror_r(ioerr, msg_buf, sizeof(msg_buf));          goto error;        }        send_tftp->th_opcode = htons(DATA);        send_tftp->th_block  = htons(++block);        /* Transmit a single packet. Retry if necessary.                     */        retry = 10;        for (;;) {          int rc;          /* Terminate entire transfers after too many retries.              */          if (--retry < 0)            goto done;          /* Send one 512 byte packet.                                       */          DBG("send DATA <block=%d, 512 bytes>\n", block);          if (sendto(fd, send_tftp, TFTPHDRSIZE + count, 0,                     (struct sockaddr *)&request->addr, request->len) < 0) {            if (errno == EINTR)              continue;            goto done;          }          /* Wait for response from client.                                  */          do {            fd_set         in_fds;            struct timeval timeout;            FD_ZERO(&in_fds);            FD_SET(fd, &in_fds);            timeout.tv_sec  = 5;            timeout.tv_usec = 0;            rc = select(fd+1, &in_fds, NULL, NULL, &timeout);          } while (rc < 0 && errno == EINTR);          /* If no response received, try sending payload again.             */          if (rc == 0)            continue;          /* Receive actual response.                                        */          rc = recv(fd, tftp, TFTPHDRSIZE + SEGSIZE, MSG_TRUNC);          /* If operation failed, terminate entire transfer.                 */          if (rc < 0) {            if (errno == EINTR)              continue;            goto done;          }          /* Done transmitting this block, after receiving matching ACK      */          if (rc >= TFTPHDRSIZE) {            switch (ntohs(tftp->th_opcode)) {              case ACK:                DBG("received ACK <block=%d>\n", ntohs(tftp->th_block));                break;              case RRQ:                DBG("received RRQ\n");                break;              case WRQ:                DBG("received WRQ\n");                break;              case DATA:                DBG("received DATA\n");                break;              case ERROR:                DBG("received ERROR\n");                break;              default:                DBG("unexpected data, op=%d\n", ntohs(tftp->th_opcode));                break;            }          }          if (rc >= TFTPHDRSIZE &&              ntohs(tftp->th_opcode) == ACK &&              tftp->th_block == send_tftp->th_block)            break;        }      } while (count);    #endif  } else {    #ifdef CAN_WRITE_FILES      /* TODO: Add support for writing files */    #endif  } done:  /* Clean up, close all file handles, and release memory                    */  if (fd >= 0)    close(fd);  if (src >= 0)    close(src);  if (file_name)    free(file_name);  free(request);  return 0;#undef debug}/* This is a very basic TFTP server implementing RFC 1350, but none of the * optional protocol extensions (e.g. no block size negotiation, and no * multicasting). */int main(int argc, char *argv[]) {  static const struct option long_opts[] = {    /* Set file name for "core" snapshot file of running process.            */    { "core",      1, NULL, 'c' },    /* Enable debugging output.                                              */    { "debug",     0, NULL, 'd' },    /* Print usage information for this server.                              */    { "help",      0, NULL, 'h' },    /* Suppress negative acknowledge for non-existant files.                 */    { "noack",     0, NULL, 'n' },    /* Set port number to listen on.                                         */    { "port",      1, NULL, 'p' },    /* Sanitize requests for absolute filenames by prepending the name of the     * first directory specified on the command line. If no directory is     * given, prepend "/tftpboot/".     */    { "sanitize",  0, NULL, 's' },    { NULL,          0, NULL, 0 } };  static const char *opt_string = "c:dhnp:s";  const char        *core_name  = "core";  int               debug       = 0;  int               no_ack      = 0;  int               port        = -1;  int               sanitize    = 0;  char              **dirs      = NULL;  int               server_fd   = 0;  int               id          = 0;  /* Parse command line options.                                             */  for (;;) {    int idx = 0;    int c   = getopt_long(argc, argv, opt_string, long_opts, &idx);    if (c == -1)      break;    switch (c) {    case 'c':      core_name = optarg;      break;    case 'd':      debug = 1;      break;    case 'n':      no_ack = 1;      break;    case 'p':      port = atoi(optarg);      if (port <= 0 || port > 65535) {        fprintf(stderr, "Port out of range: %d\n", port);        exit(1);      }      break;    case 's':      sanitize = 1;      break;    case 'h':    default:      fprintf(stderr,           "Usage: %s --core <name> --debug --help --port <port> --noack "           "--sanitize\n",           argv[0]);      exit(c != 'h');    }  }  /* All remaining command line arguments (if any) list the directories of   * files that this server can access. If no directories are given, then   * only files in "/tftpboot/..." are accessible.   */  dirs = argv + optind;  /* If a port is given on the command line, then listen on. Otherwise,   * assume that stdin is already connected to a server port. This allows   * us to run the server from inetd.   */  if (port >= 0) {    struct sockaddr_in addr;    server_fd = socket(PF_INET, SOCK_DGRAM, 0);    if (server_fd < 0) {      perror("socket");      exit(1);    }    memset(&addr, 0, sizeof(addr));    addr.sin_family      = AF_INET;    addr.sin_port        = htons(port);    addr.sin_addr.s_addr = INADDR_ANY;    if (bind(server_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) <0){      perror("bind");      exit(1);    }  }  /* Server mainloop. Accept incoming connections and spawn threads to   * serve the requests.   */  for (;;) {    const char         *msg;    char               buf[TFTPHDRSIZE + SEGSIZE];    struct tftphdr     *tftp = (struct tftphdr *)buf;    struct sockaddr_in addr;    socklen_t          len;    int                count, type;    Request            *request;    #ifndef NO_THREADS    pthread_t          thread;    #endif    /* Receive next request.                                                 */    len   = sizeof(addr);    count = recvfrom(server_fd, tftp, sizeof(buf), MSG_TRUNC,                     (struct sockaddr *)&addr, &len);    if (count < 0) {      if (errno == EINTR)        continue;      perror("recvfrom");      exit(1);    }    /* If request arrived from unsupported address, just ignore it.          */    if (len < sizeof(struct sockaddr_in))      continue;    /* If request was truncated, report error back to client.                */    if (count < sizeof(tftp)) {      char *ptr;      msg = "Truncated request";    send_error:      /* Send error message to client.                                       */      DBG("%s\n", msg);      ptr = strrchr(strcpy(tftp->th_msg, msg), '\000') + 1;      tftp->th_opcode = htons(ERROR);      tftp->th_code   = htons(EBADOP);      sendto(server_fd, tftp, ptr-buf, 0, (struct sockaddr *)&addr, len);      continue;    }        /* Determine whether this was a read or write request.                   */    type = ntohs(tftp->th_opcode);    if (type != RRQ && type != WRQ) {      msg = "Request must be RRQ or WRQ";      goto send_error;    }    /* Build "Request" data structure with parameters describing connection. */    request            = calloc(sizeof(Request), 1);    request->debug     = debug;    request->id        = id++;    request->fd        = server_fd;    request->tftp      = (struct tftphdr *)&request->buf;    request->count     = count;    request->len       = len;    request->core_name = core_name;    request->dirs      = dirs;    request->no_ack    = no_ack;    request->sanitize  = sanitize;    memcpy(&request->buf,  buf,   count);    memcpy(&request->addr, &addr, len);    /* Hand request off to its own thread.                                   */    #ifdef NO_THREADS    tftp_thread(request);    #else    pthread_create(&thread, NULL, tftp_thread, request);    #endif  }}

⌨️ 快捷键说明

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