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

📄 tftpdriver.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * vim: set expandtab tabstop=4 shiftwidth=4 ai : *  * Trivial File Transfer Protocol (RFC 1350) * * Transfer file to/from remote host * * W. Eric Norum * Saskatchewan Accelerator Laboratory * University of Saskatchewan * Saskatoon, Saskatchewan, CANADA * eric@skatter.usask.ca * *  $Id: tftpDriver.c,v 1.21 2002/10/28 13:55:58 joel Exp $ * */#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <malloc.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <rtems.h>#include <rtems/libio.h>#include <rtems/libio_.h>#include <rtems/seterr.h>#include <rtems/rtems_bsdnet.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#ifdef RTEMS_TFTP_DRIVER_DEBUGint rtems_tftp_driver_debug = 1;#endif/* * Range of UDP ports to try */#define UDP_PORT_BASE        3180/* * Pathname prefix */#define TFTP_PATHNAME_PREFIX "/TFTP/"/* * Root node_access value * By using the address of a local static variable * we ensure a unique value for this identifier. */#define ROOT_NODE_ACCESS    (&tftp_mutex)/* * Default limits */#define PACKET_FIRST_TIMEOUT_MILLISECONDS  400#define PACKET_TIMEOUT_MILLISECONDS        6000#define OPEN_RETRY_LIMIT                   10#define IO_RETRY_LIMIT                     10/* * TFTP opcodes */#define TFTP_OPCODE_RRQ     1#define TFTP_OPCODE_WRQ     2#define TFTP_OPCODE_DATA    3#define TFTP_OPCODE_ACK     4#define TFTP_OPCODE_ERROR   5/* * Largest data transfer */#define TFTP_BUFSIZE        512/* * Packets transferred between machines */union tftpPacket {    /*     * RRQ/WRQ packet     */    struct tftpRWRQ {        rtems_unsigned16    opcode;        char                filename_mode[TFTP_BUFSIZE];    } tftpRWRQ;    /*     * DATA packet     */    struct tftpDATA {        rtems_unsigned16    opcode;        rtems_unsigned16    blocknum;        rtems_unsigned8     data[TFTP_BUFSIZE];    } tftpDATA;    /*     * ACK packet     */    struct tftpACK {        rtems_unsigned16    opcode;        rtems_unsigned16    blocknum;    } tftpACK;    /*     * ERROR packet     */    struct tftpERROR {        rtems_unsigned16    opcode;        rtems_unsigned16    errorCode;        char                errorMessage[TFTP_BUFSIZE];    } tftpERROR;};/* * State of each TFTP stream */struct tftpStream {    /*     * Buffer for storing most recently-received packet     */    union tftpPacket    pkbuf;    /*     * Last block number transferred     */    rtems_unsigned16    blocknum;    /*     * Data transfer socket     */    int                 socket;    struct sockaddr_in  myAddress;    struct sockaddr_in  farAddress;    /*     * Indices into buffer     */    int     nleft;    int     nused;    /*     * Flags     */    int     firstReply;    int     eof;    int     writing;};/* * Number of streams open at the same time */static rtems_id tftp_mutex;static int nStreams;static struct tftpStream ** volatile tftpStreams;typedef const char *tftp_node;extern rtems_filesystem_operations_table  rtems_tftp_ops;extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;/* *  Direct copy from the IMFS.  Look at this. */rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {   5,   /* link_max */   6,   /* max_canon */   7,   /* max_input */   255, /* name_max */   255, /* path_max */   2,   /* pipe_buf */   1,   /* posix_async_io */   2,   /* posix_chown_restrictions */   3,   /* posix_no_trunc */   4,   /* posix_prio_io */   5,   /* posix_sync_io */   6    /* posix_vdisable */};static int rtems_tftp_mount_me(  rtems_filesystem_mount_table_entry_t *temp_mt_entry){  rtems_status_code  sc;  temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;  temp_mt_entry->mt_fs_root.ops      = &rtems_tftp_ops;  /*   *   We have no tftp filesystem specific data to maintain.  This   *   filesystem may only be mounted ONCE.   *   *   And we maintain no real filesystem nodes, so there is no real root.   */  temp_mt_entry->fs_info                = NULL;  temp_mt_entry->mt_fs_root.node_access = ROOT_NODE_ACCESS;  /*   *  These need to be looked at for full POSIX semantics.   */  temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;   /*   *  Now allocate a semaphore for mutual exclusion.   *   *  NOTE:  This could be in an fsinfo for this filesystem type.   */    sc = rtems_semaphore_create (    rtems_build_name('T', 'F', 'T', 'P'),    1,    RTEMS_FIFO |    RTEMS_BINARY_SEMAPHORE |    RTEMS_NO_INHERIT_PRIORITY |    RTEMS_NO_PRIORITY_CEILING |    RTEMS_LOCAL,    0,    &tftp_mutex  );  if (sc != RTEMS_SUCCESSFUL)    rtems_set_errno_and_return_minus_one( ENOMEM );   return 0;}/* * Initialize the TFTP driver */int rtems_bsdnet_initialize_tftp_filesystem () {    int                                   status;    rtems_filesystem_mount_table_entry_t *entry;    status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );    if ( status == -1 )        return status;     status = mount(             &entry,            &rtems_tftp_ops,            RTEMS_FILESYSTEM_READ_WRITE,            NULL,            TFTP_PATHNAME_PREFIX    );    if ( status )        perror( "TFTP mount failed" );    return status;}/* * Map error message */static inttftpErrno (struct tftpStream *tp){    unsigned int tftpError;    static const int errorMap[] = {        EINVAL,        ENOENT,        EPERM,        ENOSPC,        EINVAL,        ENXIO,        EEXIST,        ESRCH,    };    tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);    if (tftpError < (sizeof errorMap / sizeof errorMap[0]))        return errorMap[tftpError];    else        return 1000 + tftpError;}/* * Send a message to make the other end shut up */static voidsendStifle (struct tftpStream *tp, struct sockaddr_in *to){    int len;    struct {        rtems_unsigned16    opcode;        rtems_unsigned16    errorCode;        char                errorMessage[12];    } msg;    /*     * Create the error packet (Unknown transfer ID).     */    msg.opcode = htons (TFTP_OPCODE_ERROR);    msg.errorCode = htons (5);    len = sizeof msg.opcode + sizeof msg.errorCode + 1;    len += sprintf (msg.errorMessage, "GO AWAY");     /*     * Send it     */    sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);}/* * Wait for a data packet */static intgetPacket (struct tftpStream *tp, int retryCount){    int len;    struct timeval tv;    if (retryCount == 0) {        tv.tv_sec = PACKET_FIRST_TIMEOUT_MILLISECONDS / 1000;        tv.tv_usec = (PACKET_FIRST_TIMEOUT_MILLISECONDS % 1000) * 1000;    }    else {        tv.tv_sec = PACKET_TIMEOUT_MILLISECONDS / 1000;        tv.tv_usec = (PACKET_TIMEOUT_MILLISECONDS % 1000) * 1000;    }    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);    for (;;) {        union {            struct sockaddr s;            struct sockaddr_in i;        } from;        int fromlen = sizeof from;        len = recvfrom (tp->socket, (char *)&tp->pkbuf,                                                    sizeof tp->pkbuf, 0,                                                    &from.s, &fromlen);        if (len < 0)            break;        if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {            if (tp->firstReply) {                tp->firstReply = 0;                tp->farAddress.sin_port = from.i.sin_port;            }            if (tp->farAddress.sin_port == from.i.sin_port)                 break;        }        /*         * Packet is from someone with whom we are         * not interested.  Tell them to go away.         */        sendStifle (tp, &from.i);    }    tv.tv_sec = 0;    tv.tv_usec = 0;    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);#ifdef RTEMS_TFTP_DRIVER_DEBUG    if (rtems_tftp_driver_debug) {        if (len >= (int) sizeof tp->pkbuf.tftpACK) {            int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);            switch (opcode) {            default:                printf ("TFTP: OPCODE %d\n", opcode);                break;            case TFTP_OPCODE_DATA:                printf ("TFTP: RECV %d\n", ntohs (tp->pkbuf.tftpDATA.blocknum));                break;            case TFTP_OPCODE_ACK:                printf ("TFTP: GOT ACK %d\n", ntohs (tp->pkbuf.tftpACK.blocknum));                break;            }        }        else {            printf ("TFTP: %d-byte packet\n", len);        }    }#endif    return len;}/* * Send an acknowledgement */static intsendAck (struct tftpStream *tp){#ifdef RTEMS_TFTP_DRIVER_DEBUG    if (rtems_tftp_driver_debug)        printf ("TFTP: ACK %d\n", tp->blocknum);#endif    /*     * Create the acknowledgement     */    tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);    tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);    /*     * Send it     */    if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,                                    (struct sockaddr *)&tp->farAddress,                                    sizeof tp->farAddress) < 0)        return errno;    return 0;}/* * Release a stream and clear the pointer to it */static voidreleaseStream (int s){    rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);    free (tftpStreams[s]);    tftpStreams[s] = NULL;    rtems_semaphore_release (tftp_mutex);}static int rtems_tftp_evaluate_for_make(   const char                         *path,       /* IN     */   rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */   const char                        **name        /* OUT    */){    pathloc->node_access = NULL;  rtems_set_errno_and_return_minus_one( EIO );    }/* * Convert a path to canonical form */static voidfixPath (char *path){    char *inp, *outp, *base;    outp = inp = path;    base = NULL;    for (;;) {        if (inp[0] == '.') {            if (inp[1] == '\0')                break;            if (inp[1] == '/') {                inp += 2;                continue;            }            if (inp[1] == '.') {                if (inp[2] == '\0') {                    if ((base != NULL) && (outp > base)) {                        outp--;                        while ((outp > base) && (outp[-1] != '/'))                            outp--;                    }                    break;                }                if (inp[2] == '/') {                    inp += 3;                    if (base == NULL)                        continue;                    if (outp > base) {                        outp--;                        while ((outp > base) && (outp[-1] != '/'))                            outp--;                    }                    continue;                }            }        }        if (base == NULL)            base = inp;        while (inp[0] != '/') {            if ((*outp++ = *inp++) == '\0')                return;        }        *outp++ = '/';        while (inp[0] == '/')            inp++;    }    *outp = '\0';    return;}static int rtems_tftp_eval_path(    const char                        *pathname,     /* IN     */  int                                flags,        /* IN     */  rtems_filesystem_location_info_t  *pathloc       /* IN/OUT */){    pathloc->handlers    = &rtems_tftp_handlers;    /*     * Hack to provide the illusion of directories inside the TFTP file system.     * Paths ending in a / are assumed to be directories.     */    if (pathname[strlen(pathname)-1] == '/') {        int isRelative = (pathloc->node_access != ROOT_NODE_ACCESS);        char *cp;                /*         * Reject attempts to open() directories         */        if (flags & RTEMS_LIBIO_PERMS_RDWR)            rtems_set_errno_and_return_minus_one( EISDIR );        if (isRelative) {            cp = malloc (strlen(pathloc->node_access)+strlen(pathname)+1);            if (cp == NULL)                rtems_set_errno_and_return_minus_one( ENOMEM );            strcpy (cp, pathloc->node_access);            strcat (cp, pathname);        }        else {            cp = strdup (pathname);            if (cp == NULL)                rtems_set_errno_and_return_minus_one( ENOMEM );        }        fixPath (cp);        pathloc->node_access = cp;        return 0;    }    if (pathloc->node_access != ROOT_NODE_ACCESS)        pathloc->node_access = 0;

⌨️ 快捷键说明

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