Merge pull request #1 from overflowerror/devel

Update current state on main
This commit is contained in:
overflowerror 2021-12-05 22:48:02 +01:00 committed by GitHub
commit 7b6e4ce8a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 548 additions and 37 deletions

View file

@ -1,14 +1,14 @@
CC = gcc CC = gcc
LD = gcc LD = gcc
CFLAGS = -Wall -g -std=c99 -ICFloor/src/ -Ilibargo/src/ -Ilibparcival/src/ -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=500 CFLAGS = -Wall -g -std=c99 -ICFloor/src/ -Ilibargo/src/ -Ilibparcival/src/ -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=500
LDFLAGS = -lpthread -lrt LDFLAGS = -lpthread -lrt -luuid
CFLOOR_LIB = CFloor/libcfloor.a CFLOOR_LIB = CFloor/libcfloor.a
LIBARGO = libargo/libargo.a LIBARGO = libargo/libargo.a
LIBPARCIVAL = libparcival/libparcival.a LIBPARCIVAL = libparcival/libparcival.a
LIBS = $(CFLOOR_LIB) $(LIBARGO) $(LIBPARCIVAL) LIBS = $(CFLOOR_LIB) $(LIBARGO) $(LIBPARCIVAL)
OBJS = obj/router.o obj/request.o obj/base_cfloor.o obj/base_cgi.o obj/auth.o obj/base64.o OBJS = obj/router.o obj/request.o obj/base_cfloor.o obj/base_cgi.o obj/auth.o obj/base64.o obj/common.o obj/cookies.o obj/sessions.o
DEPS = $(OBJS:%.o=%.d) DEPS = $(OBJS:%.o=%.d)
DEMO_OBJS = obj/demo.o obj/entities.tab.o obj/template.tab.o DEMO_OBJS = obj/demo.o obj/entities.tab.o obj/template.tab.o

View file

@ -1,40 +1,44 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <controller.h> #include <controller.h>
#define SESSION_PTR_TYPE const char*
#include <sessions.h>
#include "entities.h" #include "entities.h"
GET("/", hello); GET("/", hello);
GET("/index.*", hello); GET("/index.*", hello);
response_t hello(ctx_t ctx) { response_t hello(ctx_t* ctx) {
return rawResponse(200, "Hello World\n"); return rawResponse(200, "Hello World\n");
} }
GET("/foobar", foobar); GET("/foobar", foobar);
response_t foobar(ctx_t ctx) { response_t foobar(ctx_t* ctx) {
return fileResponse("demo/foobar.txt"); return fileResponse("demo/foobar.txt");
} }
response_t authenticate(ctx_t ctx) { response_t authenticate(ctx_t* ctx) {
if (ctx.auth.type != BASIC) { if (ctx->auth.type != BASIC) {
return basicAuthResponse(401, "Protected Area"); return basicAuthResponse(401, "Protected Area");
} }
if (strcmp(ctx.auth.basic.user, "admin") != 0 || if (strcmp(ctx->auth.basic.user, "admin") != 0 ||
strcmp(ctx.auth.basic.password, "password") != 0 strcmp(ctx->auth.basic.password, "password") != 0
) { ) {
// username or password wrong // username or password wrong
return basicAuthResponse(401, "Protected Area"); return basicAuthResponse(401, "Protected Area");
} }
return next(); return next();
} }
GET("/user", authenticate, user); GET("/user", authenticate, user);
response_t user(ctx_t ctx) { POST("/user", authenticate, user);
response_t user(ctx_t* ctx) {
user_t user = { user_t user = {
.username = "overflowerror", .username = "overflowerror",
.github = "https://github.com/overflowerror" .github = "https://github.com/overflowerror"
@ -44,6 +48,26 @@ response_t user(ctx_t ctx) {
} }
GET("/template", template); GET("/template", template);
response_t template(ctx_t ctx) { response_t template(ctx_t* ctx) {
return templateResponse(200, "demo.templ", "Page Title", "Overflow"); return templateResponse(200, "demo.templ", "Page Title", "Overflow");
} }
GET("/sessions", sessions);
response_t sessions(ctx_t* ctx) {
const char** sessiondata = session_start(ctx);
const char* output = "null\n";
if (*sessiondata == NULL) {
*sessiondata = "Test\n";
session_update(ctx);
} else {
output = *sessiondata;
}
fprintf(stderr, "%s, %d\n", output, strlen(output));
return rawResponse(200, output);
}

@ -1 +1 @@
Subproject commit 30c62e03b86573a3fc5df788bda4bb95d2d89f9b Subproject commit e4a86956046c03055780e98c4e95f352e683d985

View file

@ -15,6 +15,8 @@
struct networkingConfig netConfig; struct networkingConfig netConfig;
void session_end(ctx_t*);
static void handler(struct request request, struct response _response) { static void handler(struct request request, struct response _response) {
ctx_t ctx = { ctx_t ctx = {
method: request.metaData.method, method: request.metaData.method,
@ -22,18 +24,25 @@ static void handler(struct request request, struct response _response) {
queryString: request.metaData.queryString, queryString: request.metaData.queryString,
peerAddr: request.peer.addr, peerAddr: request.peer.addr,
peerPort: request.peer.port, peerPort: request.peer.port,
auth: getAuthData(request.headers) auth: getAuthData(request.headers),
requestHeaders: *request.headers,
responseHeaders: headers_create(),
session: EMPTY_SESSION_CTX,
}; };
response_t response = routerHandler(ctx); response_t response = routerHandler(&ctx);
if (response.output == NULL) { if (response.output == NULL) {
response = errorResponse(500, "route did not provide a reponse handler"); response = errorResponse(500, "route did not provide a reponse handler");
} }
freeAuthData(ctx.auth); freeAuthData(ctx.auth);
session_end(&ctx);
headers_merge(&ctx.responseHeaders, &response.headers);
int fd = _response.sendHeader(response.status, &response.headers, &request); int fd = _response.sendHeader(response.status, &ctx.responseHeaders, &request);
headers_free(&response.headers); headers_free(&response.headers);
headers_free(&ctx.responseHeaders);
if (fd < 0) { if (fd < 0) {
error("csite: sendHeader: %s", strerror(errno)); error("csite: sendHeader: %s", strerror(errno));
@ -46,7 +55,7 @@ static void handler(struct request request, struct response _response) {
return; return;
} }
response.output(out, response._userData, ctx); response.output(out, response._userData, &ctx);
fclose(out); fclose(out);
} }

View file

@ -96,14 +96,14 @@ const char* or(const char* v1, const char* v2) {
} }
} }
void session_end(ctx_t*);
int main(int argc, char** argv) { int main(int argc, char** argv) {
struct headers headers = headers_create(); struct headers headers = headers_create();
if (setHttpHeaders(&headers)) { if (setHttpHeaders(&headers)) {
fprintf(stderr, "%s: %s\n", argv[0], strerror(errno)); fprintf(stderr, "%s: %s\n", argv[0], strerror(errno));
exit(1); exit(1);
} }
// TODO use request headers
ctx_t ctx = { ctx_t ctx = {
method: getMethod(or(getenv("REQUEST_METHOD"), "GET")), method: getMethod(or(getenv("REQUEST_METHOD"), "GET")),
@ -111,25 +111,32 @@ int main(int argc, char** argv) {
queryString: or(getenv("QUERY_STRING"), ""), queryString: or(getenv("QUERY_STRING"), ""),
peerAddr: or(getenv("REMOTE_ADDR"), ""), peerAddr: or(getenv("REMOTE_ADDR"), ""),
peerPort: 0, // TODO peerPort: 0, // TODO
auth: getAuthData(request.headers) auth: getAuthData(request.headers),
requestHeaders: headers,
responseHeaders: headers_create(),
session: EMPTY_SESSION_CTX,
}; };
headers_free(&headers);
response_t response = routerHandler(ctx); response_t response = routerHandler(&ctx);
if (response.output == NULL) { if (response.output == NULL) {
response = errorResponse(500, "route did not provide a reponse handler"); response = errorResponse(500, "route did not provide a reponse handler");
} }
headers_free(&headers);
headers_merge(&ctx.responseHeaders, &response.headers);
freeAuthData(ctx.auth); freeAuthData(ctx.auth);
session_end(&ctx);
printf("Status: %d\n\r", response.status); printf("Status: %d\n\r", response.status);
headers_dump(&response.headers, stdout); headers_dump(&ctx.responseHeaders, stdout);
printf("\n\r"); printf("\n\r");
headers_free(&response.headers); headers_free(&response.headers);
headers_free(&ctx.responseHeaders);
response.output(stdout, response._userData, ctx); response.output(stdout, response._userData, &ctx);
return 0; return 0;
} }

9
src/common.c Normal file
View file

@ -0,0 +1,9 @@
#include <headers.h>
#include "common.h"
void headers_merge(struct headers* dst, struct headers* src) {
for (int i = 0; i < src->number; i++) {
headers_mod(dst, src->headers[i].key, src->headers[i].value);
}
}

View file

@ -15,4 +15,6 @@ typedef enum method method_t;
#define HTTP_CONNECT (CONNECT) #define HTTP_CONNECT (CONNECT)
#define HTTP_PATCH (PATCH) #define HTTP_PATCH (PATCH)
void headers_merge(struct headers*, struct headers*);
#endif #endif

227
src/cookies.c Normal file
View file

@ -0,0 +1,227 @@
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
#include <stdio.h>
#include <headers.h>
#include "cookies.h"
char* getCookie(ctx_t* ctx, const char* key) {
// ignore const
char* cookieHeader = (char*) headers_get(&ctx->requestHeaders, "Cookie");
if (cookieHeader == NULL) {
return NULL;
}
cookieHeader = strdup(cookieHeader);
if (cookieHeader == NULL) {
return NULL;
}
char* saveptr = NULL;
char* str = cookieHeader;
char* value = NULL;
while((str = strtok_r(str, ";", &saveptr)) != NULL) {
while(*str == ' ') str++;
char* keyCandidate = str;
for (; *str != '='; str++) {
if (*str == '\0') {
str = NULL;
break;
}
}
if (str == NULL) {
// illegal cookie definition; ignore
// str is already NULL
continue;
}
*str = '\0';
if (strcmp(keyCandidate, key) == 0) {
value = str + 1;
break;
}
str = NULL;
}
if (value != NULL) {
value = strdup(value);
}
free(cookieHeader);
return value;
}
cookieSettings_t cookieSettingsNull() {
return (cookieSettings_t) {
.expires = COOKIE_NO_EXPIRES,
.maxAge = COOKIE_NO_MAX_AGE,
.domain = NULL,
.path = NULL,
.secure = false,
.httpOnly = false
};
}
int setCookie(ctx_t* ctx, const char* name, const char* value, cookieSettings_t settings) {
size_t length = 0;
length += strlen(name) + 1 + strlen(value);
if (settings.expires != COOKIE_NO_EXPIRES) {
length += 2;
length += strlen("Expires=");
length += 3 + 2 + 2 + 1 + 3 + 1 + 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 3;
}
if (settings.maxAge != COOKIE_NO_MAX_AGE) {
length += 2;
length += strlen("Max-Age=");
long tmp = settings.maxAge;
if (tmp <= 0) {
length++;
tmp *= -1;
}
for (; tmp > 0; tmp /= 10) length++;
}
if (settings.domain != NULL) {
length += 2;
length += strlen("Domain=");
length += strlen(settings.domain);
}
if (settings.path != NULL) {
length += 2;
length += strlen("Path=");
length += strlen(settings.path);
}
if (settings.secure) {
length += 2;
length += strlen("Secure");
}
if (settings.httpOnly) {
length += 2;
length += strlen("HttpOnly");
}
char* buffer = alloca(length + 1);
char* bufferPtr = buffer;
size_t tmp;
tmp = snprintf(bufferPtr, length + 1, "%s=%s", name, value);
bufferPtr += tmp;
length -= tmp;
if (settings.expires != COOKIE_NO_EXPIRES) {
struct tm result;
gmtime_r(&settings.expires, &result);
char* weekday;
switch(result.tm_wday) {
case 0:
weekday = "Sun";
break;
case 1:
weekday = "Mon";
break;
case 2:
weekday = "Tue";
break;
case 3:
weekday = "Wed";
break;
case 4:
weekday = "Thu";
break;
case 5:
weekday = "Fri";
break;
case 6:
weekday = "Sat";
break;
default:
weekday = "err";
break;
}
char* month;
switch(result.tm_mon) {
case 0:
month = "Jan";
break;
case 1:
month = "Feb";
break;
case 2:
month = "Mar";
break;
case 3:
month = "Apr";
break;
case 4:
month = "May";
break;
case 5:
month = "Jun";
break;
case 6:
month = "Jul";
break;
case 7:
month = "Aug";
break;
case 8:
month = "Sep";
break;
case 9:
month = "Oct";
break;
case 10:
month = "Nov";
break;
case 11:
month = "Dec";
break;
default:
month = "err";
break;
}
tmp = snprintf(bufferPtr, length + 1, "; Expires=%s, %02d %s %d %02d:%02d:%02d GMT", weekday, result.tm_mday, month, result.tm_year + 1900, result.tm_hour, result.tm_min, result.tm_sec);
bufferPtr += tmp;
length -= tmp;
}
if (settings.maxAge != COOKIE_NO_MAX_AGE) {
tmp = snprintf(bufferPtr, length + 1, "; Max-Age=%ld", settings.maxAge);
bufferPtr += tmp;
length -= tmp;
}
if (settings.domain != NULL) {
tmp = snprintf(bufferPtr, length + 1, "; Domain=%s", settings.domain);
bufferPtr += tmp;
length -= tmp;
}
if (settings.path != NULL) {
tmp = snprintf(bufferPtr, length + 1, "; Path=%s", settings.path);
bufferPtr += tmp;
length -= tmp;
}
if (settings.secure) {
tmp = snprintf(bufferPtr, length + 1, "; Secure");
bufferPtr += tmp;
length -= tmp;
}
if (settings.httpOnly) {
tmp = snprintf(bufferPtr, length + 1, "; HttpOnly");
bufferPtr += tmp;
length -= tmp;
}
headers_mod(&ctx->responseHeaders, "Set-Cookie", buffer);
return 0;
}

28
src/cookies.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef COOKIES_H_
#define COOKIES_H_
#include <time.h>
#include <stdbool.h>
#include <limits.h>
#include "request.h"
char* getCookie(ctx_t*, const char*);
#define COOKIE_NO_EXPIRES (0)
#define COOKIE_NO_MAX_AGE (LONG_MIN)
typedef struct {
time_t expires;
long maxAge;
const char* domain;
const char* path;
bool secure;
bool httpOnly;
} cookieSettings_t;
cookieSettings_t cookieSettingsNull();
int setCookie(ctx_t*, const char*, const char*, cookieSettings_t);
#endif

View file

@ -3,6 +3,6 @@
#include "request.h" #include "request.h"
typedef response_t (handle_t)(ctx_t); typedef response_t (handle_t)(ctx_t*);
#endif #endif

View file

@ -31,13 +31,13 @@ void setDefaultErrorFormat(errorformat_t format) {
errorformat = format; errorformat = format;
} }
static void rawOutputAndFree(FILE* out, void* _userData, ctx_t ctx) { static void rawOutputAndFree(FILE* out, void* _userData, ctx_t* ctx) {
fprintf(out, "%s", (char*) _userData); fprintf(out, "%s", (char*) _userData);
free(_userData); free(_userData);
} }
static void rawOutput(FILE* out, void* _userData, ctx_t ctx) { static void rawOutput(FILE* out, void* _userData, ctx_t* ctx) {
fprintf(out, "%s", (const char*) _userData); fprintf(out, "%s", (const char*) _userData);
} }
@ -70,7 +70,7 @@ struct statusdata {
const char* message; const char* message;
}; };
static void statusOutput(FILE* out, void* _userData, ctx_t ctx) { static void statusOutput(FILE* out, void* _userData, ctx_t* ctx) {
struct statusdata* data = (struct statusdata*) _userData; struct statusdata* data = (struct statusdata*) _userData;
const char* statusString = getStatusStrings(data->status).statusString; const char* statusString = getStatusStrings(data->status).statusString;
@ -80,7 +80,7 @@ static void statusOutput(FILE* out, void* _userData, ctx_t ctx) {
"status", json_long(data->status), "status", json_long(data->status),
"error", json_string(statusString), "error", json_string(statusString),
"message", json_string(data->message), "message", json_string(data->message),
"path", json_string(ctx.path) "path", json_string(ctx->path)
); );
free(data); free(data);
free(tmp); free(tmp);
@ -126,7 +126,7 @@ response_t errorResponse(int status, const char* message) {
return statusResponse(status, message); return statusResponse(status, message);
} }
static void fileOutput(FILE* out, void* _userData, ctx_t ctx) { static void fileOutput(FILE* out, void* _userData, ctx_t* ctx) {
FILE* in = (FILE*) _userData; FILE* in = (FILE*) _userData;
#define READ_BUFFER_SIZE (1024) #define READ_BUFFER_SIZE (1024)
@ -171,7 +171,7 @@ response_t fileResponse(const char* file) {
return response; return response;
} }
static void jsonOutput(FILE* output, void* _userData, ctx_t ctx) { static void jsonOutput(FILE* output, void* _userData, ctx_t* ctx) {
jsonValue_t* json = (jsonValue_t*) _userData; jsonValue_t* json = (jsonValue_t*) _userData;
char* result = json_stringify(json); char* result = json_stringify(json);
@ -196,8 +196,8 @@ response_t _jsonResponse(int status, const char* type, void* value) {
return response; return response;
} }
extern size_t _sizeTemplate(const char*, ...); extern size_t _sizeTemplate(const char*, va_list);
extern void _renderTemplate(const char*, FILE*, ...); extern void _renderTemplate(const char*, FILE*, va_list);
response_t templateResponse(int status, const char* name, ...) { response_t templateResponse(int status, const char* name, ...) {
response_t response = emptyResponse(); response_t response = emptyResponse();

View file

@ -11,6 +11,14 @@
#define NEXT_RESPONSE_STATUS (0) #define NEXT_RESPONSE_STATUS (0)
struct session_ctx {
void* session;
time_t accessTime;
void* data;
};
#define EMPTY_SESSION_CTX ((struct session_ctx) {.session = NULL})
typedef struct { typedef struct {
method_t method; method_t method;
const char* path; const char* path;
@ -18,6 +26,9 @@ typedef struct {
const char* peerAddr; const char* peerAddr;
int peerPort; int peerPort;
struct auth auth; struct auth auth;
struct headers requestHeaders;
struct headers responseHeaders;
struct session_ctx session;
} ctx_t; } ctx_t;
typedef struct { typedef struct {
@ -25,7 +36,7 @@ typedef struct {
struct headers headers; struct headers headers;
void* _userData; void* _userData;
void (*output) (FILE* conenction, void* _userData, ctx_t ctx); void (*output) (FILE* conenction, void* _userData, ctx_t* ctx);
} response_t; } response_t;
typedef enum { typedef enum {

View file

@ -121,8 +121,8 @@ int registerRoute(method_t method, const char* path, ...) {
return 0; return 0;
} }
response_t routerHandler(ctx_t ctx) { response_t routerHandler(ctx_t* ctx) {
struct route* route = findRoute(ctx.method, ctx.path); struct route* route = findRoute(ctx->method, ctx->path);
if (route == NULL) { if (route == NULL) {
return errorResponse(404, "no route found"); return errorResponse(404, "no route found");
} }

View file

@ -5,6 +5,6 @@
int registerRoute(method_t method, const char* path, ...); int registerRoute(method_t method, const char* path, ...);
response_t routerHandler(ctx_t ctx); response_t routerHandler(ctx_t* ctx);
#endif #endif

161
src/sessions.c Normal file
View file

@ -0,0 +1,161 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <pthread.h>
#include <headers.h>
// SESSION_PTR_TYPE doesn't matter for this file
#define SESSION_PTR_TYPE int
#include "sessions.h"
#include "cookies.h"
struct session {
bool inUse;
uuid_t id;
time_t lastAccess;
time_t lastWrite;
void* data;
};
static struct session* sessions = NULL;
static size_t sessionno = 0;
static pthread_mutex_t globalLock = PTHREAD_MUTEX_INITIALIZER;
#define SESSION_BLOCK_SIZE (128)
int resizeSessionList() {
struct session* tmp = realloc(sessions, sizeof(struct session) * (sessionno + SESSION_BLOCK_SIZE));
if (tmp == NULL) {
return -1;
}
for (size_t i = 0; i < SESSION_BLOCK_SIZE; i++) {
struct session* session = &tmp[sessionno + i];
session->inUse = 0;
}
sessions = tmp;
sessionno += SESSION_BLOCK_SIZE;
return 0;
}
struct session* newSession(size_t size) {
for (size_t i = 0; i < sessionno; i++) {
if (!sessions[i].inUse) {
sessions[i].inUse = true;
sessions[i].data = malloc(size);
if (sessions[i].data == NULL) {
sessions[i].inUse = false;
return NULL;
}
memset(sessions[i].data, 0, size);
sessions[i].lastWrite = 0;
return &(sessions[i]);
}
}
// no free session slot
if (resizeSessionList() < 0) {
return NULL;
}
return newSession(size);
}
struct session* findSession(uuid_t id) {
for (size_t i = 0; i < sessionno; i++) {
if (!sessions[i].inUse) {
continue;
}
if (uuid_compare(sessions[i].id, id) == 0) {
return &(sessions[i]);
}
}
return NULL;
}
void* _session_start(ctx_t* ctx, const char* cookie, size_t size) {
char* cookieValue = getCookie(ctx, cookie);
bool isValid = false;
uuid_t id;
struct session* session = NULL;
if (cookieValue != NULL) {
if (uuid_parse(cookieValue, id) == 0) {
isValid = true;
}
free(cookieValue);
} else {
isValid = false;
}
pthread_mutex_lock(&globalLock);
if (isValid) {
session = findSession(id);
}
if (session == NULL) {
session = newSession(size);
if (session == NULL) {
return NULL;
}
uuid_generate_time(session->id);
char buffer[36 + 1];
uuid_unparse(session->id, buffer);
setCookie(ctx, cookie, buffer, cookieSettingsNull());
}
pthread_mutex_unlock(&globalLock);
session->lastAccess = time(NULL);
ctx->session.session = session;
ctx->session.accessTime = time(NULL);
void* requestSessionData = malloc(size);
if (requestSessionData == NULL) {
return NULL;
}
memcpy(requestSessionData, session->data, size);
ctx->session.data = requestSessionData;
return requestSessionData;
}
int _session_update(ctx_t* ctx, size_t size) {
struct session_ctx* sessionCtx = &(ctx->session);
struct session* session = (struct session*) sessionCtx->session;
if (session == NULL) {
return ERROR_NO_SESSION;
}
pthread_mutex_lock(&globalLock);
if (session->lastWrite > sessionCtx->accessTime) {
pthread_mutex_unlock(&globalLock);
return ERROR_CONCURRENT_SESSION;
}
session->lastWrite = time(NULL);
sessionCtx->accessTime = session->lastWrite;
memcpy(session->data, sessionCtx->data, size);
pthread_mutex_unlock(&globalLock);
return 0;
}
void session_end(ctx_t* ctx) {
if (ctx->session.session != NULL) {
free(ctx->session.data);
}
}

33
src/sessions.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef SESSIONS_H_
#define SESSIONS_H_
#include <time.h>
#include <uuid/uuid.h>
#ifndef SESSION_PTR_TYPE
#pragma GCC warning "session ptr type not defined"
#define SESSION_PTR_TYPE int
#endif
#ifndef SESSION_LENGTH
#define SESSION_LENGTH (24*60*60*1000)
#endif
#ifndef SESSION_COOKIE_NAME
#define SESSION_COOKIE_NAME "cshore_session"
#endif
#include "request.h"
#define ERROR_NO_SESSION (-2)
#define ERROR_CONCURRENT_SESSION (-1)
void* _session_start(ctx_t*, const char*, size_t);
int _session_update(ctx_t*, size_t);
void session_end(ctx_t*);
#define session_start(c) ((SESSION_PTR_TYPE*) _session_start(c, SESSION_COOKIE_NAME, sizeof(SESSION_PTR_TYPE)))
#define session_update(c) _session_update(c, sizeof(SESSION_PTR_TYPE))
#endif