[uCsimm] HTTP flashloader

From: David Beckemeyer (david@bdt.com)
Date: Sat Mar 10 2001 - 14:02:41 EST


Some people might find the program below handy. This is derived from
flashloader.c in the uCsimm kit. Instead of loading a file, it
obtains the boot image via HTTP. This allows one to install a new
uCsimm flash image from a web server.

It is not a full fledged HTTP client, but good enough for the job.
The arguments are a little goofy since uCsimm doesn't normally have
DNS, so it takes an IP address and server name as separate arguemnts
(this allows it to pull from hostname-based "Virtual" servers).

It is invoked as follows:

  netflash ip name port object

E.g.

  netflash 207.245.32.50 www.uclinux.org 80 /image.bin

The above example would cause the program to retrieve the file
/image.bin from the www.uclinux.org server via HTTP on port 80
(don't really do this). The 'object' argument is the path on the
web server to the image.bin file (tail part of url).

The program checks for a valid HTTP response, but the only validity
check on the object itself today is that it is at least 600K, so use
with caution (make sure you fetch a flash image and not a GCC
tarball). If someone knows a good scheme to validate an image.bin
file before burning into flash, please pass it along.

The object has to be an uncompressed image.bin file exatly like you
would pass to "flashloader" for this to work properly.

Enjoy.

----------------------------------------------------------------

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <bootstd.h>
#include <flash.h>

_bsc2(int,program,void *,a1,int,a2)

void *chain[512];

char spinner[] = { 8, '|' , 8, '\\' , 8, '-', 8, '/'};

char httpcmd[512];
char httpbuf[512];

// normal read arguments

int
readn(int fd, char* ptr, int numbytes)
{
    int nleft, nread;

    nleft = numbytes;
    while (nleft > 0)
    {
        nread = read(fd, ptr, nleft);
        if (nread < 0)
            return(nread); /* error, return < 0 */
        else if (nread == 0)
            break; /* EOF */

        nleft -= nread;
        ptr += nread;
    }
    return(numbytes - nleft); /* return >= 0 */
}

int
readline(fd, ptr, maxlen)
register int fd;
register char *ptr;
register int maxlen;
{
        int n, rc;
        char c;

        for (n = 1; n < maxlen; n++) {
                if ( (rc = read(fd, &c, 1)) == 1) {
                        *ptr++ = c;
                        if (c == '\n')
                                break;
                } else if (rc == 0) {
                        if (n == 1)
                                return(0); /* EOF, no data read */
                        else
                                break; /* EOF, some data was read */
                } else
                        return(-1); /* error */
        }

        *ptr = 0;
        return(n);
}

int
tcp_connect(char *ip, int port)
{
        FILE *fp;
        char buf[512];
        struct sockaddr_in server;
        struct in_addr TargetHostAddr;
        int c;
        char *AddressList[1];
        int sock;
 
        TargetHostAddr.s_addr = inet_addr(ip);
        if (TargetHostAddr.s_addr == -1) {
                perror("inet_addr");
                return(-1);
        }
        sock = socket(AF_INET, SOCK_STREAM, 6);
        if (sock < 0) {
                perror("socket");
                return(-1);
        }
        bcopy((char*)&TargetHostAddr, (char*)&server.sin_addr, sizeof(struct in_addr));
        server.sin_family = AF_INET;
        server.sin_port = port;
        if (connect(sock, (struct sockaddr *)&server, sizeof server)) {
                perror("connect");
                return(-1);
        }
        return(sock);
}

main(int argc, char *argv[])
{
        int fd;

        int count;
        int n;
        int b;
        mnode_t m;
        char *ip, *object, *host, *r;
        int port, ret;

        if (argc != 5) {
                fprintf(stderr, "Usage: %s ip name port object\n",argv[0]);
                exit(1);
        }
        ip = argv[1];
        host = argv[2];
        port = atoi(argv[3]);
        object = argv[4];

        if ((fd = tcp_connect(ip, port)) < 0) {
                fprintf(stderr, "cannot connect to %s:%d\n", ip, port);
                exit(2);
        }
        printf("Connected to %s\n", ip);

        sprintf(httpcmd, "GET %s HTTP/1.0\r\nUser-Agent: AVL-flashloader/1.0 (david@bdt.com)\r\nHost: %s\r\n\r\n", object, host);
        write(fd, httpcmd, strlen(httpcmd));

        printf("Scanning headers...\n");
        b = 0;
        do {
                n = readline(fd, httpbuf, 512);
                if (n < 0) {
                        fprintf(stderr, "error reading HTTP headers\n");
                        exit(2);
                }
                if (n == 0) {
                        fprintf(stderr, "EOF reading HTTP headers\n");
                        exit(2);
                }
                fputs(httpbuf, stdout);
                if (b++ == 0) {
                        if (strncmp(httpbuf, "HTTP/", 5)) {
                                fprintf(stderr, "ill-formed response: %s\n", httpbuf);
                                exit(2);
                        }
                        r = httpbuf;
                        while(*(++r) != ' '); /*skip non-white space*/
                        ret = atoi(r);
                        if (ret != 200) {
                                fprintf(stderr, "HTTP error: %s\n", httpbuf);
                                exit(2);
                        }
                }
                r = httpbuf;
                while (*r && *r <= ' ')
                        r++;
        } while (*r);

        printf("Loading object [%s]\n", object);
        
        for (count = b = 0; n == 4096 || !b ; count += n) {
                chain[b] = malloc(4096);
                n = readn(fd, chain[b++], 4096);
                write(1, &spinner[(b & 3) << 1], 2);
        }
        close(fd);
        printf("Loaded %d bytes\n",count);

        if (count < 600000) {
                fprintf(stderr, "image is too small (%d), aborting\n", count);
                exit(2);
        }

        m.len = count;
        m.offset = (void *)chain;

        program(&m, PGM_ERASE_FIRST | PGM_EXEC_AFTER);
        /* not reached, PGM_EXEC_AFTER starts the new kernel */
}
This message resent by the ucsimm@uclinux.com list server http://www.uClinux.com/



This archive was generated by hypermail 2b30 : Sun Apr 07 2002 - 00:01:42 EST