All pastes #2166 Raw Edit

mpr

public c v1 · immutable
#2166 ·published 2004-11-18 04:11 UTC
rendered paste body
#include <curl/curl.h>#include <pthread.h>#include <fcntl.h>#include <semaphore.h>#include <sys/socket.h>#include <netinet/in.h>char boundary[128];struct image {    pthread_mutex_t lock;    char *data;    int length;    int received;};sem_t new_image;struct image curr_image, next_image;static size_t write_cb(void *data, size_t size, size_t nmemb, void *stream) {    static int state = 0;    char *tmp;    int msize = size * nmemb;    int retval = size * nmemb;        /* char *tmp = strstr(data, "\377\330\377\340\000\020JFIF\000"); JPEG Header */        size *= nmemb;        while(msize > 0) {        char *tmp1, *tmp2;                if(state == 0 && !strncmp(data, boundary, strlen(boundary))) {            state = 1;            data += strlen(boundary);            msize -= strlen(boundary);        } else if(state == 0 && !strncmp(data+2, boundary, strlen(boundary))) {            state = 1;            data += strlen(boundary) + 2;            msize -= strlen(boundary) + 2;        } else if(state == 1 && (tmp1 = strstr(data, "Content-Length: "))) {            tmp2 = index(tmp1, '\r');            *tmp2 = '\0';            pthread_mutex_lock(&next_image.lock);            next_image.length = atoi(data + 16);            next_image.data = (char *)malloc(next_image.length);            next_image.received = 0;            pthread_mutex_unlock(&next_image.lock);            msize -= ((void *)tmp2+2)-(data);            data = tmp2+2;            state = 2;        } else if(state == 2 && (tmp1 = strstr(data, "Content-Type: "))) {            tmp1 = data + strlen("Content-Type: image/jpeg\r\n\r\n");            msize -= (int)((void *)tmp1 - (void *)data);            data = tmp1;            state = 3;        } else if(state == 3) {            int copy;            pthread_mutex_lock(&next_image.lock);                        /* Determine how much to copy */            copy = (next_image.length - next_image.received > msize ?                    msize :                    next_image.length - next_image.received);            memcpy(next_image.data + next_image.received, data, copy);                        /* Include this in our received count */            next_image.received += copy;            data += copy;                        if(next_image.length == next_image.received) {                /* If we received it all, lock the current and replace it */                pthread_mutex_lock(&curr_image.lock);                if(curr_image.data)                    free(curr_image.data);                curr_image.data = next_image.data;                curr_image.length = next_image.length;                curr_image.received = next_image.received;                pthread_mutex_unlock(&curr_image.lock);                                /* Notify the other thread */                sem_post(&new_image);                                /* Drop the "next image" information,                 * since it is now current image */                next_image.data = NULL;                next_image.length = 0;                next_image.received = 0;                state = 0;            }            msize -= copy;            if(msize >= 2) {                msize -= 2;                data += 2;            }            pthread_mutex_unlock(&next_image.lock);        }    }        return retval;}static size_t header_cb(void *data, size_t size, size_t nmemb, void *stream) {    if(size * nmemb > 14 && !strncasecmp(data, "Content-Type: ", 14)) {        char *tmp;        tmp = index(data, ';');        snprintf(boundary, 128, "--%s", tmp + 10);    }    return size * nmemb;}static void *reader_thread(void *arg) {    CURL *curl;        curl = curl_easy_init();        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb);    curl_easy_setopt(curl, CURLOPT_URL, (char *)arg);        curl_easy_perform(curl);        curl_easy_cleanup(curl);        pthread_exit(0);}pthread_mutex_t clientlock;struct client {    int fd;    int first;    struct sockaddr_in sa;    struct client *next;};struct client *clientlist = NULL;static void *listen_thread(void *arg) {    int lfd, res, tmp;    struct sockaddr_in sa;    struct client *c;        sa.sin_family = AF_INET;    sa.sin_port = htons(9194);    sa.sin_addr.s_addr = INADDR_ANY;    lfd = socket(AF_INET, SOCK_STREAM, 0);    bind(lfd, (struct sockaddr *)&sa, sizeof(sa));    listen(lfd, 20);        tmp = sizeof(sa);    while((res = accept(lfd, (struct sockaddr *)&sa, &tmp))) {        pthread_mutex_lock(&clientlock);        c = clientlist;        while(c) {            if(c->fd == -1)                break;            c = c->next;        }        if(!c) {            c = (struct client *)malloc(sizeof(struct client));            memcpy(&c->sa, &sa, sizeof(sa));            c->next = clientlist;            clientlist = c;        }        c->first = 1;        c->fd = res;#define HELLO "HTTP/1.0 200 OK\r\nConnection: close\r\nPragma: no-cache\r\nCache-Controler: no-cache\r\nContent-Type: multipart/x-mixed-replace;boundary=Juigt9G7bb7sfdgsdZGIDFsjhn\r\n\r\n"        write(c->fd, HELLO, strlen(HELLO));        pthread_mutex_unlock(&clientlock);        printf("Client connected.\n");    }}static void *writer_thread(void *arg) {    int framecnt = 0;        while(1) {        int fd;        char buf[1024];        struct client *c;        int cnt;                sem_wait(&new_image);        pthread_testcancel();        pthread_mutex_lock(&curr_image.lock);        pthread_mutex_lock(&clientlock);                c = clientlist;        cnt = 0;        while(c) {            if(c->fd != -1) {                if(c->first) {                    snprintf(buf, 1024, "%sContent-Length: %d\r\nContent-Type: image/jpeg\r\n\r\n", boundary, curr_image.length);                    c->first = 0;                } else {                    snprintf(buf, 1024, "Content-Length: %d\r\nContent-Type: image/jpeg\r\n\r\n", curr_image.length);                }                write(c->fd, buf, strlen(buf));                if(write(c->fd, curr_image.data, curr_image.length) < curr_image.length) {                    shutdown(c->fd, 2);                    close(c->fd);                    c->fd = -1;                }                write(c->fd, "\r\n", 2);                write(c->fd, boundary, strlen(boundary));                cnt++;            }            c = c->next;        }                snprintf(buf, 30, "tmp%04d.jpg", framecnt++%100);        fd = open(buf , O_WRONLY | O_TRUNC | O_CREAT, 0666);        write(fd, curr_image.data, curr_image.length);        close(fd);                printf("Wrote %d bytes to %d clients (%d bytes total)\n", curr_image.length, cnt, cnt * curr_image.length);                pthread_mutex_unlock(&clientlock);        pthread_mutex_unlock(&curr_image.lock);    }}int main(int argc, char **argv) {    pthread_t reader;    pthread_t writer;    pthread_t listen_t;        curr_image.data = 0;    next_image.data = 0;        if(argc < 1) {        printf("not enough parameters. provide URL to stream.\n");        exit(0);    }        sem_init(&new_image, 0, 0);        curl_global_init(CURL_GLOBAL_NOTHING);        pthread_create(&reader, NULL, reader_thread, argv[1]);    pthread_create(&writer, NULL, writer_thread, NULL);    pthread_create(&listen_t, NULL, listen_thread, NULL);    pthread_join(reader, NULL);        curl_global_cleanup();}