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

📄 tftp_server.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================////      lib/tftp_server.c////      TFTP server support////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2003 Andrew Lunn//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    gthomas// Contributors: gthomas, hmt, andrew.lunn@ascom.ch (Andrew Lunn)// Date:         2000-04-06// Purpose:      // Description:  //              ////####DESCRIPTIONEND####////==========================================================================// TFTP server support#include <network.h>          // Basic networking support#include <arpa/tftp.h>        // TFTP protocol definitions#include <tftp_support.h>     // TFTPD structures#include <cyg/kernel/kapi.h>#include <stdlib.h>           // For malloc#include <fcntl.h>#define nCYGOPT_NET_TFTP_SERVER_INSTRUMENT#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENTstruct subinfo {    int rx;    int rx_repeat;    int rx_skip;    int send;    int resend;};struct info {    struct subinfo ack, data;    int err_send;    int total_transactions;};static struct info tftp_server_instrument = {    { 0,0,0,0,0 },    { 0,0,0,0,0 },    0, 0,};#endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT#ifdef CYGSEM_NET_TFTPD_MULTITHREADEDstruct tftpd_sem {  int port;  cyg_sem_t sem;};static struct tftpd_sem tftpd_sems[CYGNUM_NET_TFTPD_MULTITHREADED_PORTS];#endif //CYGSEM_NET_TFTPD_MULTITHREADED#define STACK_SIZE (((CYGNUM_HAL_STACK_SIZE_TYPICAL+(3*(SEGSIZE+sizeof(struct tftphdr)))) + CYGARC_ALIGNMENT-1) & ~(CYGARC_ALIGNMENT-1))static char *TFTP_tag = "TFTPD";#define CYGNUM_NET_MAX_INET_PROTOS 2struct tftp_server {    char                 *tag;    char                  stack[STACK_SIZE];    cyg_thread            thread_data;    cyg_handle_t          thread_handle;    int                   port;    struct tftpd_fileops *ops;    int s[CYGNUM_NET_MAX_INET_PROTOS], num_s;    struct addrinfo      *res;};static char * errmsg[] = {  "Undefined error code",               // 0 nothing defined  "File not found",                     // 1 TFTP_ENOTFOUND   "Access violation",                   // 2 TFTP_EACCESS     "Disk full or allocation exceeded",   // 3 TFTP_ENOSPACE    "Illegal TFTP operation",             // 4 TFTP_EBADOP      "Unknown transfer ID",                // 5 TFTP_EBADID      "File already exists",                // 6 TFTP_EEXISTS     "No such user",                       // 7 TFTP_ENOUSER   };// Little helper function to set the port number in an address static void set_port(struct sockaddr * address, int port) {  switch (address->sa_family) {  case AF_INET:{    struct sockaddr_in *addr = (struct sockaddr_in *)address;    addr->sin_port = ntohs(port);    break;  }#ifdef CYGPKG_NET_INET6  case AF_INET6:    {      struct sockaddr_in6 *addr = (struct sockaddr_in6 *)address;      addr->sin6_port = ntohs(port);      break;    }#endif  default:    break;  }}#ifdef CYGSEM_NET_TFTPD_MULTITHREADED// Allocate a semaphore for a given port number if one is not already// allocated.static void sem_alloc(int port) {  int i;  CYG_ASSERT(port != 0, "Invalid port number");  cyg_scheduler_lock(); // Avoid race with other tftpd's  for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) {    if (tftpd_sems[i].port == port) {      cyg_scheduler_unlock();      return;    }    if (tftpd_sems[i].port == 0) {      tftpd_sems[i].port = port;      cyg_semaphore_init(&tftpd_sems[i].sem,1);      cyg_scheduler_unlock();      return ;    }  }  cyg_scheduler_unlock();  diag_printf("TFTPD: Unable to allocate a semaphore for port %d\n",port);}  // Wait on the semaphore for a given port number.static void sem_wait(int port) {  int i;  CYG_ASSERT(port != 0, "Invalid port number");    for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) {    if (tftpd_sems[i].port == port) {      cyg_semaphore_wait(&tftpd_sems[i].sem);      return;    }  }  diag_printf("TFTPD: No semaphore for port %d\n",port);}// Release the semaphore for a given port number.static void sem_post(int port) {  int i;  CYG_ASSERT(port != 0, "Invalid port number");    for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) {    if (tftpd_sems[i].port == port) {      cyg_semaphore_post(&tftpd_sems[i].sem);      return;    }  }  diag_printf("TFTPD: No semaphore for port %d\n",port);}#endif/* Send an error packet to the client */static void tftpd_send_error(int s, struct tftphdr * reply, int err,		 struct sockaddr *from_addr, int from_len){    CYG_ASSERT( 0 <= err, "err underflow" );    CYG_ASSERT( sizeof(errmsg)/sizeof(errmsg[0]) > err, "err overflow" );    reply->th_opcode = htons(ERROR);    reply->th_code = htons(err);    if ( (0 > err) || (sizeof(errmsg)/sizeof(errmsg[0]) <= err) )        err = 0; // Do not copy a random string from hyperspace    strcpy(reply->th_msg, errmsg[err]);    sendto(s, reply, 4+strlen(reply->th_msg)+1, 0, 	   from_addr, from_len);}//// Receive a file from the client//static voidtftpd_write_file(struct tftp_server *server,                 struct tftphdr *hdr,                  struct sockaddr *from_addr, int from_len){    char data_out[SEGSIZE+sizeof(struct tftphdr)];    char data_in[SEGSIZE+sizeof(struct tftphdr)];    struct tftphdr *reply = (struct tftphdr *)data_out;    struct tftphdr *response = (struct tftphdr *)data_in;    int fd, len, ok, tries, closed, data_len, s;    unsigned short block;    struct timeval timeout;    fd_set fds;    int total_timeouts = 0;    struct sockaddr client_addr;    struct addrinfo hints;    struct addrinfo *res;    int client_len;    int error;        memset(&hints,0,sizeof(hints));    hints.ai_family = from_addr->sa_family;    hints.ai_flags = AI_PASSIVE;    error = getaddrinfo(NULL,"tftp",&hints, &res);    if (0 != error) {      diag_printf("TFTPD: can't get a suitable local address: %s\n",		  gai_strerror(error));      return;    }    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);    if (s < 0) {        diag_printf("TFTPD: can't open socket for 'write_file'\n");	freeaddrinfo(res);        return;    }    // We want the stack to pick a free local port number    set_port(res->ai_addr,0);    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {        // Problem setting up my end        diag_printf("TFTPD: can't bind to reply port for 'write_file'\n");        close(s);	freeaddrinfo(res);        return;    }    if ((fd = (server->ops->open)(hdr->th_stuff, O_WRONLY|O_TRUNC|O_CREAT)) < 0) {        tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);        close(s);	freeaddrinfo(res);        return;    }    ok = true;    closed = false;    block = 0;    while (ok) {        // Send ACK telling client he can send data        reply->th_opcode = htons(ACK);        reply->th_block = htons(block++); // postincrement        for (tries = 0;  tries < TFTP_RETRIES_MAX;  tries++) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT            tftp_server_instrument.ack.send++;#endif            sendto(s, reply, 4, 0, from_addr, from_len);        repeat_select:            timeout.tv_sec = TFTP_TIMEOUT_PERIOD;            timeout.tv_usec = 0;            FD_ZERO(&fds);            FD_SET(s, &fds);            if (select(s+1, &fds, 0, 0, &timeout) <= 0) {                if (++total_timeouts > TFTP_TIMEOUT_MAX) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                    tftp_server_instrument.err_send++;#endif                    tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);                    ok = false;                    break;                }#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.ack.resend++;#endif                continue; // retry the send, using up one retry.            }            // Some data has arrived            data_len = sizeof(data_in);            client_len = sizeof(client_addr);            if ((data_len = recvfrom(s, data_in, data_len, 0,                       &client_addr, &client_len)) < 0) {                // What happened?  No data here!#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.ack.resend++;#endif                continue; // retry the send, using up one retry.            }            if (ntohs(response->th_opcode) == DATA &&                ntohs(response->th_block) < block) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.data.rx_repeat++;#endif                // Then it is repeat DATA with an old block; listen again,                // but do not repeat sending the current ack, and do not                // use up a retry count.  (we do re-send the ack if                // subsequently we time out)                goto repeat_select;            }            if (ntohs(response->th_opcode) == DATA &&                ntohs(response->th_block) == block) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.data.rx++;#endif                // Good data - write to file                len = (server->ops->write)(fd, response->th_data, data_len-4);                if (len < (data_len-4)) {                    // File is "full"                    tftpd_send_error(s,reply,TFTP_ENOSPACE,                                     from_addr, from_len);                         ok = false;  // Give up                    break; // out of the retries loop                }                if (data_len < (SEGSIZE+4)) {                    // End of file                    closed = true;                    ok = false;                    if ((server->ops->close)(fd) == -1) {                        tftpd_send_error(s,reply,TFTP_EACCESS,                                         from_addr, from_len);                        break;  // out of the retries loop                    }                    // Exception to the loop structure: we must ACK the last                    // packet, the one that implied EOF:#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                    tftp_server_instrument.ack.send++;#endif                    reply->th_opcode = htons(ACK);                    reply->th_block = htons(block++); // postincrement                    sendto(s, reply, 4, 0, from_addr, from_len);                    break; // out of the retries loop                }                // Happy!  Break out of the retries loop.                break;            }            // Otherwise, we got something we do not understand!  So repeat            // sending the current ACK, and use up a retry count.#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT            if ( (ntohs(response->th_opcode) == DATA) )                tftp_server_instrument.data.rx_skip++;            tftp_server_instrument.ack.resend++;#endif        } // End of the retries loop.        if (TFTP_RETRIES_MAX <= tries) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT            tftp_server_instrument.err_send++;#endif            tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);            ok = false;        }    }    close(s);    freeaddrinfo(res);    if (!closed) {      (server->ops->close)(fd);    }}//// Send a file to the client//static voidtftpd_read_file(struct tftp_server *server,                struct tftphdr *hdr,                 struct sockaddr *from_addr, int from_len){    char data_out[SEGSIZE+sizeof(struct tftphdr)];    char data_in[SEGSIZE+sizeof(struct tftphdr)];    struct tftphdr *reply = (struct tftphdr *)data_out;    struct tftphdr *response = (struct tftphdr *)data_in;    int fd, len, tries, ok, data_len, s;    unsigned short block;    struct timeval timeout;    fd_set fds;    int total_timeouts = 0;    struct sockaddr client_addr;    struct addrinfo hints;    struct addrinfo *res;    int client_len;    int error;

⌨️ 快捷键说明

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