/* * threaded.c -- A simple multi-threaded FastCGI application. */ #ifndef lint // static const char rcsid[] = "$Id: threaded.c,v 1.9 2001/11/20 03:23:21 robs Exp $"; // just popps up warnings #endif /* not lint */ #include "fcgi_config.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #include "fcgiapp.h" #include #include #include #include "urlcode.c" #include #include #define MALLOC_RETURNED_NULL fprintf(stderr, "%s()@" __FILE__ ":%d: malloc() returned NULL\n", __func__, __LINE__); #define THREAD_COUNT 20 static int counts[THREAD_COUNT]; struct assoc_s { char * key; char * value; }; // value je lahko NULL void free_assoc_s(struct assoc_s * s) { if (s->key != NULL) { free(s->key); s->key = NULL; } if (s->value != NULL) { free(s->value); s->value = NULL; } free(s); s = NULL; return; } struct request_uri_s { char * path; struct assoc_s ** params; // to je "array". zadnji naj bo NULL. }; void free_request_uri_s(struct request_uri_s * s) { int unsigned i = 0; while (s->params[i] != NULL) { free_assoc_s(s->params[i]); s->params[i++] = NULL; } free(s->path); s->path = NULL; free(s->params); s->params = NULL; free(s); s = NULL; return; } struct assoc_s ** parse_html_keyvalue(const char * t) { struct assoc_s ** params = malloc(sizeof(void *)); if (params == NULL) { MALLOC_RETURNED_NULL return NULL; } unsigned int o = 0; // številka parametra od 0 vključno z 0 unsigned int n = 0; // 0 če smo v key, 1 če smo v value, 3 če je konec urija unsigned int a = 0; // nakazuje pozicijo naslednjega znaka, ki ga bomo napisa. params[0] = malloc(sizeof(struct assoc_s)); if (params[0] == NULL) { MALLOC_RETURNED_NULL return NULL; } for (unsigned int e = 0; n != 3 && e <= UINT_MAX; e++) { switch (t[e]) { case '\0': params = realloc(params, sizeof(struct assoc_s)*(o+1)); if (params == NULL) { MALLOC_RETURNED_NULL return NULL; } // zadnji mora biti null params[o+1] = NULL; n = 3; break; case '=': if (n == 0) { // ni treba mallocat, realloca se pred vsakim writom bajta n = 1; a = 0; } else { // this is some undocumented behaviour, adding = to param value params[o]->value = realloc(params[o]->value, a+1); if (params[o]->value == NULL) { MALLOC_RETURNED_NULL return NULL; } params[o]->value[a++] = '='; } break; case '&': // tu je treba mallocat, ker assoc_s še ne obstaja za naslednji n = 0; a = 0; o++; params = realloc(params, sizeof(struct assoc_s)*(o+1)); if (params == NULL) { MALLOC_RETURNED_NULL return NULL; } params[o] = malloc(sizeof(struct assoc_s)); // value kasneje if (params[o] == NULL) { MALLOC_RETURNED_NULL return NULL; } break; default: if (n == 0) { params[o]->key = realloc(params[o]->key, a+1); if (params[o]->key == NULL) { MALLOC_RETURNED_NULL return NULL; } params[o]->key[a++] = t[e]; } else { params[o]->value = realloc(params[o]->value, a+1); if (params[o]->value == NULL) { MALLOC_RETURNED_NULL return NULL; } params[o]->value[a++] = t[e]; } break; } } return params; } struct request_uri_s * parse_request_uri(char * uri) { // returns NULL on fail! struct request_uri_s * parsed = malloc(sizeof(struct request_uri_s)); if (parsed == NULL) { // and returns pointer to ONE request_uri_s on success^ MALLOC_RETURNED_NULL return NULL; } char * t = strchr(uri, '?'); // remember to free /\ ! if (t != NULL) t[0] = '\0'; // uri vedno vseeno pride ven nespremenjen/popravljen parsed->path = malloc(sizeof(char)*strlen(uri)+1); //znak po path je itak NULL if (parsed->path == NULL) { // malloc returna NULL, fucking panic! if (t != NULL) // popravimo še \0 nazaj na ? t[0] = '?'; MALLOC_RETURNED_NULL return NULL; } strncpy(parsed->path, uri, strlen(uri)+1); // torej zadnji znak patha bo NULL parsed->params = NULL; // če slučajno ni query_stringa in kmalu returnamo if (t == NULL) // ni query stringa zato je path parse dovoljšen return parsed; // parsed.params je NULL, to pred uporabo PREVERIMO! t[0] = '?'; // ker smo prej zaradi strlen in strncpy dali na NULL, sedaj spre. t++; // da ne začnemo z vprašajem ampak z prvim znakom parsed->params = parse_html_keyvalue(t); return parsed; } static void *doit(void *a) { intptr_t rc, i, thread_id = (intptr_t)a; pid_t pid = getpid(); FCGX_Request request; char *server_name; char * uri_to_parse; struct request_uri_s * parseduri; FCGX_InitRequest(&request, 0, 0); for (;;) { static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER; /* Some platforms require accept() serialization, some don't.. */ pthread_mutex_lock(&accept_mutex); rc = FCGX_Accept_r(&request); pthread_mutex_unlock(&accept_mutex); if (rc < 0) break; server_name = FCGX_GetParam("SERVER_NAME", request.envp); uri_to_parse = FCGX_GetParam("REQUEST_URI", request.envp); parseduri = parse_request_uri(uri_to_parse); if (strchr(parseduri->path, 'S') != NULL) { exit(0); } if (parseduri == NULL) { FCGX_FPrintF(request.out, "Status: 500 Zaledna napaka\r\n" "Content-Type: text/plain; charset=utf-8\r\n\r\n" "zgodila se je napaka na strežniku med procesiranjem URIja.\r\n"); free_request_uri_s(parseduri); goto doit_finish; } FCGX_FPrintF(request.out, "Status: 200 V redu\r\n" "Content-type: text/html; charset=utf-8\r\n" "\r\n" "FastCGI Pozdravljen svet! (večnitenje v C, knjižnica fcgiapp)" "

FastCGI Pozdravljen svet! (večnitenje v C, knjižnica fcgiapp)

" "Nit %d, Proces %ld

" "Števci zahtev za %d niti na strežniku %s

", thread_id, pid, THREAD_COUNT, server_name ? server_name : "?"); free_request_uri_s(parseduri); pthread_mutex_lock(&counts_mutex); ++counts[thread_id]; for (i = 0; i < THREAD_COUNT; i++) FCGX_FPrintF(request.out, "%5d " , counts[i]); pthread_mutex_unlock(&counts_mutex); doit_finish: FCGX_Finish_r(&request); } return NULL; } int main(void) { intptr_t i; pthread_t id[THREAD_COUNT]; FCGX_Init(); for (i = 1; i < THREAD_COUNT; i++) pthread_create(&id[i], NULL, doit, (void*)i); doit(0); // trenutno nit uporabimo tudi kot handler, zakaj pa ne (: return 0; }