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

📄 tftpdriver.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
    /*     * Reject it if it's not read-only or write-only.     */    flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;    if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )        rtems_set_errno_and_return_minus_one( EINVAL );    return 0;}/* * The routine which does most of the work for the IMFS open handler */static int rtems_tftp_open_worker(    rtems_libio_t *iop,    char          *full_path_name,    unsigned32     flags,    unsigned32     mode){    struct tftpStream    *tp;    int                  retryCount;    struct in_addr       farAddress;    int                  s;    int                  len;    char                 *cp1;    char                 *cp2;    char                 *remoteFilename;    rtems_interval       now;    rtems_status_code    sc;    char                 *hostname;    /*     * Extract the host name component     */    cp2 = full_path_name;    while (*cp2 == '/')        cp2++;    hostname = cp2;    while (*cp2 != '/') {        if (*cp2 == '\0')            return ENOENT;        cp2++;    }    *cp2++ = '\0';    /*     * Convert hostname to Internet address     */    if (strcmp (hostname, "BOOTP_HOST") == 0)        farAddress = rtems_bsdnet_bootp_server_address;    else        farAddress.s_addr = inet_addr (hostname);    if ((farAddress.s_addr == 0) || (farAddress.s_addr == ~0))        return ENOENT;    /*     * Extract file pathname component     */    while (*cp2 == '/')         cp2++;    if (strcmp (cp2, "BOOTP_FILE") == 0) {        cp2 = rtems_bsdnet_bootp_boot_file_name;        while (*cp2 == '/')             cp2++;    }    if (*cp2 == '\0')        return ENOENT;    remoteFilename = cp2;    if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))        return ENOENT;            /*     * Find a free stream     */    sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);    if (sc != RTEMS_SUCCESSFUL)        return EBUSY;    for (s = 0 ; s < nStreams ; s++) {        if (tftpStreams[s] == NULL)        break;    }    if (s == nStreams) {        /*         * Reallocate stream pointers         * Guard against the case where realloc() returns NULL.         */        struct tftpStream **np;        np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);        if (np == NULL) {            rtems_semaphore_release (tftp_mutex);            return ENOMEM;        }        tftpStreams = np;    }    tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));    rtems_semaphore_release (tftp_mutex);    if (tp == NULL)        return ENOMEM;    iop->data0 = s;    iop->data1 = tp;    /*     * Create the socket     */    if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {        releaseStream (s);        return ENOMEM;    }    /*     * Bind the socket to a local address     */    retryCount = 0;    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);    for (;;) {        int try = (now + retryCount) % 10;        tp->myAddress.sin_family = AF_INET;        tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + s);        tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);        if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)            break;        if (++retryCount == 10) {            close (tp->socket);            releaseStream (s);            return EBUSY;        }    }    /*     * Set the UDP destination to the TFTP server     * port on the remote machine.     */    tp->farAddress.sin_family = AF_INET;    tp->farAddress.sin_addr = farAddress;    tp->farAddress.sin_port = htons (69);    /*     * Start the transfer     */    tp->firstReply = 1;    retryCount = 0;    for (;;) {        /*         * Create the request         */        if ((flags & O_ACCMODE) == O_RDONLY) {            tp->writing = 0;            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);        }        else {            tp->writing = 1;            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_WRQ);        }        cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;        cp2 = (char *) remoteFilename;        while ((*cp1++ = *cp2++) != '\0')            continue;        cp2 = "octet";        while ((*cp1++ = *cp2++) != '\0')            continue;        len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;        /*         * Send the request         */        if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,                     (struct sockaddr *)&tp->farAddress,                    sizeof tp->farAddress) < 0) {            close (tp->socket);            releaseStream (s);            return EIO;        }        /*         * Get reply         */        len = getPacket (tp, retryCount);        if (len >= (int) sizeof tp->pkbuf.tftpACK) {            int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);            if (!tp->writing             && (opcode == TFTP_OPCODE_DATA)             && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {                tp->nused = 0;                tp->blocknum = 1;                tp->nleft = len - 2 * sizeof (rtems_unsigned16);                tp->eof = (tp->nleft < TFTP_BUFSIZE);                if (sendAck (tp) != 0) {                    close (tp->socket);                    releaseStream (s);                    return EIO;                }                break;            }            if (tp->writing             && (opcode == TFTP_OPCODE_ACK)             && (ntohs (tp->pkbuf.tftpACK.blocknum) == 0)) {                tp->nused = 0;                tp->blocknum = 1;                break;            }            if (opcode == TFTP_OPCODE_ERROR) {                int e = tftpErrno (tp);                close (tp->socket);                releaseStream (s);                return e;            }        }        /*         * Keep trying         */        if (++retryCount >= OPEN_RETRY_LIMIT) {            close (tp->socket);            releaseStream (s);            return EIO;        }    }    return 0;}/* * The IMFS open handler */static int rtems_tftp_open(    rtems_libio_t *iop,    const char    *new_name,    unsigned32     flags,    unsigned32     mode){    char *full_path_name;    char *s1;    int err;    /*     * Tack the `current directory' on to relative paths.     * We know that the current directory ends in a / character.     */    if (*new_name == '/') {        /*         * Skip the TFTP filesystem prefix.         */        int len = strlen (TFTP_PATHNAME_PREFIX);        if (strncmp (new_name, TFTP_PATHNAME_PREFIX, len))            return ENOENT;        new_name += len;        s1 = "";    }    else {        s1 = rtems_filesystem_current.node_access;    }    full_path_name = malloc (strlen (s1) + strlen (new_name) + 1);    if (full_path_name == NULL)        return ENOMEM;    strcpy (full_path_name, s1);    strcat (full_path_name, new_name);    fixPath (full_path_name);    err = rtems_tftp_open_worker (iop, full_path_name, flags, mode);    free (full_path_name);    return err;}/* * Read from a TFTP stream */static ssize_t rtems_tftp_read(    rtems_libio_t *iop,    void          *buffer,    unsigned32    count){    char              *bp;    struct tftpStream *tp = iop->data1;    int               retryCount;    int               nwant;    /*     * Read till user request is satisfied or EOF is reached     */    bp = buffer;    nwant = count;    while (nwant) {        if (tp->nleft) {            int ncopy;            if (nwant < tp->nleft)                ncopy = nwant;            else                ncopy = tp->nleft;            memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);            tp->nused += ncopy;            tp->nleft -= ncopy;            bp += ncopy;            nwant -= ncopy;            if (nwant == 0)                break;        }        if (tp->eof)            break;        /*         * Wait for the next packet         */        retryCount = 0;        for (;;) {            int len = getPacket (tp, retryCount);            if (len >= (int)sizeof tp->pkbuf.tftpACK) {                int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);                rtems_unsigned16 nextBlock = tp->blocknum + 1;                if ((opcode == TFTP_OPCODE_DATA)                 && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {                    tp->nused = 0;                    tp->nleft = len - 2 * sizeof (rtems_unsigned16);                    tp->eof = (tp->nleft < TFTP_BUFSIZE);                    tp->blocknum++;                    if (sendAck (tp) != 0)                        rtems_set_errno_and_return_minus_one( EIO );                    break;                }                if (opcode == TFTP_OPCODE_ERROR)                        rtems_set_errno_and_return_minus_one( tftpErrno (tp) );            }            /*             * Keep trying?             */            if (++retryCount == IO_RETRY_LIMIT)                rtems_set_errno_and_return_minus_one( EIO );            if (sendAck (tp) != 0)                rtems_set_errno_and_return_minus_one( EIO );        }    }    return count - nwant;}/* * Flush a write buffer and wait for acknowledgement */static int rtems_tftp_flush ( struct tftpStream *tp ){    int wlen, rlen;    int retryCount = 0;    wlen = tp->nused + 2 * sizeof (rtems_unsigned16);    for (;;) {        tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);        tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);#ifdef RTEMS_TFTP_DRIVER_DEBUG        if (rtems_tftp_driver_debug)            printf ("TFTP: SEND %d (%d)\n", tp->blocknum, tp->nused);#endif        if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,                                         (struct sockaddr *)&tp->farAddress,                                        sizeof tp->farAddress) < 0)            return EIO;        rlen = getPacket (tp, retryCount);        /*         * Our last packet won't necessarily be acknowledged!         */        if ((rlen < 0) && (tp->nused < sizeof tp->pkbuf.tftpDATA.data))                return 0;        if (rlen >= (int)sizeof tp->pkbuf.tftpACK) {            int opcode = ntohs (tp->pkbuf.tftpACK.opcode);            if ((opcode == TFTP_OPCODE_ACK)             && (ntohs (tp->pkbuf.tftpACK.blocknum) == tp->blocknum)) {                tp->nused = 0;                tp->blocknum++;                return 0;            }            if (opcode == TFTP_OPCODE_ERROR)                return tftpErrno (tp);        }        /*         * Keep trying?         */        if (++retryCount == IO_RETRY_LIMIT)            return EIO;    }}/* * Close a TFTP stream */static int rtems_tftp_close(    rtems_libio_t *iop){    struct tftpStream *tp = iop->data1;;    if (tp->writing)        rtems_tftp_flush (tp);    if (!tp->eof && !tp->firstReply) {        /*         * Tell the other end to stop         */        rtems_interval ticksPerSecond;        sendStifle (tp, &tp->farAddress);        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);        rtems_task_wake_after (1 + ticksPerSecond / 10);    }    close (tp->socket);    releaseStream (iop->data0);    return RTEMS_SUCCESSFUL;}static ssize_t rtems_tftp_write(    rtems_libio_t   *iop,    const void      *buffer,    unsigned32      count){    const char        *bp;    struct tftpStream *tp = iop->data1;    int               nleft, nfree, ncopy;    /*     * Bail out if an error has occurred     */    if (!tp->writing)        return EIO;    /*     * Write till user request is satisfied     * Notice that the buffer is flushed as soon as it is filled rather     * than waiting for the next write or a close.  This ensures that     * the flush in close writes a less than full buffer so the far     * end can detect the end-of-file condition.     */    bp = buffer;    nleft = count;    while (nleft) {        nfree = sizeof tp->pkbuf.tftpDATA.data - tp->nused;        if (nleft < nfree)            ncopy = nleft;        else            ncopy = nfree;        memcpy (&tp->pkbuf.tftpDATA.data[tp->nused], bp, ncopy);        tp->nused += ncopy;        nleft -= ncopy;        bp += ncopy;        if (tp->nused == sizeof tp->pkbuf.tftpDATA.data) {            int e = rtems_tftp_flush (tp);            if (e) {                tp->writing = 0;                rtems_set_errno_and_return_minus_one (e);            }        }    }    return count;}/* * Dummy version to let fopen(xxxx,"w") work properly. */static int rtems_tftp_ftruncate(    rtems_libio_t   *iop,    off_t           count){    return 0;}static rtems_filesystem_node_types_t rtems_tftp_node_type(     rtems_filesystem_location_info_t        *pathloc                 /* IN */){    if ((pathloc->node_access == NULL)     || (pathloc->node_access == ROOT_NODE_ACCESS))        return RTEMS_FILESYSTEM_MEMORY_FILE;    return RTEMS_FILESYSTEM_DIRECTORY;}static int rtems_tftp_free_node_info(     rtems_filesystem_location_info_t        *pathloc                 /* IN */){    if (pathloc->node_access && (pathloc->node_access != ROOT_NODE_ACCESS)) {        free (pathloc->node_access);        pathloc->node_access = NULL;    }    return 0;}rtems_filesystem_operations_table  rtems_tftp_ops = {    rtems_tftp_eval_path,            /* eval_path */    rtems_tftp_evaluate_for_make,    /* evaluate_for_make */    NULL,                            /* link */    NULL,                            /* unlink */    rtems_tftp_node_type,            /* node_type */    NULL,                            /* mknod */    NULL,                            /* chown */    rtems_tftp_free_node_info,       /* freenodinfo */    NULL,                            /* mount */    rtems_tftp_mount_me,             /* initialize */    NULL,                            /* unmount */    NULL,                            /* fsunmount */    NULL,                            /* utime, */    NULL,                            /* evaluate_link */    NULL,                            /* symlink */    NULL,                            /* readlin */};  rtems_filesystem_file_handlers_r rtems_tftp_handlers = {    rtems_tftp_open,   /* open */         rtems_tftp_close,  /* close */        rtems_tftp_read,   /* read */         rtems_tftp_write,  /* write */        NULL,              /* ioctl */        NULL,              /* lseek */        NULL,              /* fstat */        NULL,              /* fchmod */       rtems_tftp_ftruncate, /* ftruncate */    NULL,              /* fpathconf */    NULL,              /* fsync */        NULL,              /* fdatasync */    NULL,              /* fcntl */    NULL               /* rmnod */};

⌨️ 快捷键说明

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