/*
* 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 <pthread.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "fcgiapp.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "urlcode.c"
#include <limits.h>
#include <stdio.h>
#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"
"<title>FastCGI Pozdravljen svet! (večnitenje v C, knjižnica fcgiapp)</title>"
"<h1>FastCGI Pozdravljen svet! (večnitenje v C, knjižnica fcgiapp)</h1>"
"Nit %d, Proces %ld<p>"
"Števci zahtev za %d niti na strežniku <i>%s</i><p><code>",
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;
}