Make your own free website on Tripod.com

nb.c


DownloadHTTPServer



Home

Samples

DownloadHTTPServer

FTP-uploader

HighPerformanceAnonymousFTPServer


/*
    srvdown.c
    
    High perfomance download web-server (Unix-version only). 
    It work without forks or threads and use small amount of memory.
    Stay on port 50080 and wait for incoming http GET, 
    then send appropriate file from www_root_dir.
    
    cc srvdown.c nb.c mlib.c -o srvdown
    ./srvdown www_root_dir
    
    then start your internet bowser (may be IE) and type URL
    http://your.host:50080/any_file_from_www_root_dir
    
    (c) /dev/www (wwwdev@mail.ru), 2006
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>

#include "nb.h"


#define BUF_SIZE        4096
#define PORTON                50080

typedef struct {
    int fd;
    int written;
} CLIENT;

char wwwroot[256];
char odata[BUF_SIZE];

/*
    After server creating. Callback function.
*/
int srv_create(struct nb_server *nbs)
{

    printf("srv_create:\n");

    return 0;
}

/*
    After server closing. Callback function.
*/
int srv_close(struct nb_server *nbs, int status)
{

    printf("srv_close: status %d\n", status);

    return 0;
}

/*
    After accept connection(or close). Callback function.
*/
int srv_conn(struct nb_conn *nbc, int status)
{
    CLIENT *cl;

    printf("srv_conn: status %d, ip %s\n", status, nbc->ip);
    
    if(status == 0){        /* New connection, create client space */
        cl = (CLIENT *)m_alloc(sizeof(CLIENT));
        cl->fd = -1;
        cl->written = 0;
        nbc->private_data = cl;
    }

    return 0;
}


/*
    Send error 404.
*/
int not_found(struct nb_conn *nbc)
{

    sprintf(odata, "HTTP/1.1 404 Not Found\r\n\r\n");
    nb_put_disconnect(nbc, odata, strlen(odata));

    return 0;
}

/*
    Read incoming data from client. Callback function.
*/
int srv_data(struct nb_conn *nbc)
{
    char data[512];
    char fname[256];
    char cdate[64], fdate[64];
    time_t current_time;
    struct stat st;
    int i, n, len, olen, sz;
    CLIENT *cl;

    cl = (CLIENT *)nbc->private_data;
    memset(data, 0, 512);
    n = nb_get(nbc, data, 512);
    if(n){
        printf("srv_data: %s\n", data);
                                        /* We wait for GET only */
        if(data == strstr(data, "GET ")){
            memset(fname, 0, 256);
            strcpy(fname, wwwroot);
            for(i = 4; data[i] && data[i] != ' ' && data[i] != '\r' && data[i] != '\n'; i++)
                fname[strlen(fname)] = data[i];
            
            current_time = time(NULL);
            strcpy(cdate, ctime(&current_time));
            cdate[strlen(cdate) - 1] = '\0';
            if(stat(fname, &st))
                return(not_found(nbc));
            else {
                strcpy(fdate, ctime(&st.st_mtime));
                fdate[strlen(fdate) - 1] = '\0';
                memset(odata, 0, BUF_SIZE);
                if(-1 == (cl->fd = open(fname, 0)))
                    return(not_found(nbc));
                else {
                                                /* Get file size */
                    sz = lseek(cl->fd, 0, SEEK_END);
                    lseek(cl->fd, 0, SEEK_SET);
                                                /* Make the first http-answer */
                    sprintf(odata, "HTTP/1.1 200 OK\r\n"
                        "Date: %s\r\n"
                        "Server: HighPerformanceDownloadServer\r\n"
                        "Last-Modified: %s\r\n"
                        "Accept-Ranges: bytes\r\n"
                        "Content-Length: %d\r\n"
                        "Content-Type: text/plain\r\n\r\n",
                        cdate, fdate, sz);
                    olen = strlen(odata);
                    len = BUF_SIZE - olen;
                                                /* Read first block of file */
                    n = read(cl->fd, odata + olen, len);
                    if(n < len){
                        close(cl->fd);
                        if(n <= 0)
                            nb_disconnect(nbc);
                    }                                
                                                /* Put it into output buffer */
                    if(n > 0){
                        cl->written = n;
                        if(n < len)
                            nb_put_disconnect(nbc, odata, olen + n);
                        else
                            nb_put(nbc, odata, olen + n);
                    }
                    
                    return 0;
                }
            }
        }
    }
                /* Some errors, disconnect */
    return 1;
}

/*
    After data sending. Callback function.
    Read next data block and send it.
*/
int srv_empty(struct nb_conn *nbc)
{
    CLIENT *cl;
    int n;

    cl = (CLIENT *)nbc->private_data;
                                /* Read next data block */
    n = read(cl->fd, odata, BUF_SIZE);
    if(n < BUF_SIZE){
        close(cl->fd);
        if(n <= 0)
                nb_disconnect(nbc);
    }
                                /* And put it into output buffer */
    if(n > 0){
        cl->written += n;
        if(n < BUF_SIZE)
            nb_put_disconnect(nbc, odata, n);
        else
            nb_put(nbc, odata, n);
    }

    return 0;
}


main(int argc, char *argv[])
{
    NB_SERVER *nbs;
    int rc;

    if(argc < 2)
        strcpy(wwwroot, ".");
    else
        strcpy(wwwroot, argv[1]);

    printf("www root dir is %s\n", wwwroot);

    nb_tcp(5, 1000);
    nb_serv(&nbs, PORTON, srv_create, srv_close, srv_conn, srv_data, srv_empty);
    if(0 != (rc = nb_listen(nbs))){
        printf("nbs_listen err %d\n", rc);
        exit(rc);
    }

/*
    daemon(1, 1);
    ...
*/
                                /* Main loop */
    while(1)
        nb_poll(1000);

    return 0;
}



(c) /dev/www, 2006