refactors to make userdata part of the common connData struct

master
Ondřej Hruška 2 years ago
parent 27289fda27
commit 59e2223ef7
  1. 38
      demo/server_demo.c
  2. 23
      spritehttpd/include/cgi-espfs.h
  3. 2
      spritehttpd/include/cgi-websocket.h
  4. 32
      spritehttpd/include/httpd-platform.h
  5. 20
      spritehttpd/include/httpd-types.h
  6. 2
      spritehttpd/include/httpd.h
  7. 58
      spritehttpd/src/cgi-espfs.c
  8. 12
      spritehttpd/src/httpd-loop.c
  9. 59
      spritehttpd/src/httpd.c
  10. 6
      spritehttpd/src/port/httpd-posix.c

@ -22,51 +22,51 @@ struct RequestData {
}; };
/** "About" page */ /** "About" page */
httpd_cgi_state templateReplacer(TplData *td) httpd_cgi_state templateReplacer(HttpdConnData *conn, const char *token)
{ {
struct RequestData *rd; struct RequestData *rd;
if (!td->conn) { if (!token) {
if (td->userData) { if (conn->userData) {
httpdPlatFree(td->userData); httpdPlatFree(conn->userData);
td->userData = NULL; conn->userData = NULL;
} }
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
if (!td->userData) { if (!conn->userData) {
rd = httpdPlatMalloc(sizeof(struct RequestData)); rd = httpdPlatMalloc(sizeof(struct RequestData));
td->userData = rd; conn->userData = rd;
rd->counter = 0; rd->counter = 0;
shared.visits++; shared.visits++;
} else { } else {
rd = td->userData; rd = conn->userData;
} }
char buf[100]; char buf[100];
if (streq(td->token, "visits")) { if (streq(token, "visits")) {
sprintf(buf, "%d", shared.visits); sprintf(buf, "%d", shared.visits);
tplSend(td, buf); tplSend(conn, buf);
} }
else if (streq(td->token, "html1")) { else if (streq(token, "html1")) {
tplSend(td, "<a href=\"foo\">foo</a>"); tplSend(conn, "<a href=\"foo\">foo</a>");
} }
else if (streq(td->token, "html2")) { else if (streq(token, "html2")) {
tplSend(td, "<a href=\"bar\">bar</a>"); tplSend(conn, "<a href=\"bar\">bar</a>");
} }
else if (streq(td->token, "json1")) { else if (streq(token, "json1")) {
tplSend(td, "\"hello\":\"foo<angle>'' and backslash\\ \" also crlf \r\n"); tplSend(conn, "\"hello\":\"foo<angle>'' and backslash\\ \" also crlf \r\n");
} }
else if (streq(td->token, "multipart")) { else if (streq(token, "multipart")) {
if (rd->counter < 100) { if (rd->counter < 100) {
sprintf(buf, "HELLO %d, ", rd->counter); sprintf(buf, "HELLO %d, ", rd->counter);
tplSend(td, buf); tplSend(conn, buf);
rd->counter++; rd->counter++;
return HTTPD_CGI_MORE; return HTTPD_CGI_MORE;
} }
tplSend(td, "and that's it."); tplSend(conn, "and that's it.");
} }
else { else {
return HTTPD_CGI_NOTFOUND; return HTTPD_CGI_NOTFOUND;

@ -5,25 +5,12 @@
#define HTTPD_ESPFS_TOKEN_LEN 64 #define HTTPD_ESPFS_TOKEN_LEN 64
typedef struct TplData {
/// Connection. Is set to NULL during final clean-up
HttpdConnData *conn;
/// Currently parsed token. Cleared during clean-up
const char *token;
/// Pointer to arbitrary user data that should be freed/cleaned up
/// during clean-up
void *userData;
} TplData;
/** /**
* The template substitution callback. * The template substitution callback.
*
* Returns CGI_MORE if more should be sent within the token, CGI_DONE otherwise. * Returns CGI_MORE if more should be sent within the token, CGI_DONE otherwise.
* * If token is NULL, we're doing a clean-up at the end of the request, this is a good place to free any user data.
* The td.userData pointer can be used to attach arbitrary data to the request.
* If connData is NULL (and token empty), we are doing cleanup - free td.userData, if needed.
*/ */
typedef httpd_cgi_state (* TplCallback)(TplData *td); typedef httpd_cgi_state (* TplCallback)(HttpdConnData *conn, const char *token);
/** /**
* Serve a static file from EspFs. The file name is in the first CGI arg. If NULL, the URI is used as a file name. * Serve a static file from EspFs. The file name is in the first CGI arg. If NULL, the URI is used as a file name.
@ -52,7 +39,7 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn);
* @param len - string len * @param len - string len
* @return 1 = OK * @return 1 = OK
*/ */
int tplSendN(TplData *td, const char *str, int len); int tplSendN(HttpdConnData *conn, const char *str, int len);
/** /**
* Send template substitution string (use strlen) * Send template substitution string (use strlen)
@ -61,6 +48,6 @@ int tplSendN(TplData *td, const char *str, int len);
* @param str - string to send * @param str - string to send
* @return 1 = OK * @return 1 = OK
*/ */
static inline int tplSend(TplData *tpd, const char *str) { static inline int tplSend(HttpdConnData *conn, const char *str) {
return tplSendN(tpd, str, strlen(str)); return tplSendN(conn, str, strlen(str));
} }

@ -50,8 +50,6 @@ typedef struct WebsockPriv WebsockPriv;
// TODO convert to container_of and avoid separate malloc for priv // TODO convert to container_of and avoid separate malloc for priv
struct Websock { struct Websock {
/// Pointer to arbitrary user data, put there e.g. during 'recvCb'
void *userData;
/// Connection pointer /// Connection pointer
HttpdConnData *conn; HttpdConnData *conn;
/// Receive callback - new data; optional, set by user in WsConnectedCb /// Receive callback - new data; optional, set by user in WsConnectedCb

@ -85,21 +85,6 @@ void httpdPlatInit();
*/ */
httpd_thread_handle_t *httpdPlatStart(struct httpd_options *opts); httpd_thread_handle_t *httpdPlatStart(struct httpd_options *opts);
/**
* Server task function, called by httpdPlatStart inside a thread
*
* @param pvParameters
*/
void platHttpServerTask(void *pvParameters);
/**
* Posix format of the server task function
*
* @param pvParameters
* @return
*/
void *platHttpServerTaskPosix(void *pvParameters);
/** /**
* Wait for the server to end * Wait for the server to end
* *
@ -116,3 +101,20 @@ void httpdPlatJoin(httpd_thread_handle_t *handle);
* @return 0 on success * @return 0 on success
*/ */
int httpdPlatEspfsRead(void *dest, uint32_t offset, size_t len); int httpdPlatEspfsRead(void *dest, uint32_t offset, size_t len);
/**
* Server task function, called by httpdPlatStart inside a thread.
*
* @internal
* @param pvParameters
*/
void httpdServerTask(void *pvParameters);
/**
* Posix format of the server task function.
*
* @internal
* @param pvParameters
* @return
*/
void *httpdServerTaskPosix(void *pvParameters);

@ -62,6 +62,10 @@ typedef struct HttpdPostData HttpdPostData;
typedef httpd_cgi_state (* cgiSendCallback)(HttpdConnData *connData); typedef httpd_cgi_state (* cgiSendCallback)(HttpdConnData *connData);
typedef httpd_cgi_state (* cgiRecvHandler)(HttpdConnData *connData, uint8_t *data, size_t len); typedef httpd_cgi_state (* cgiRecvHandler)(HttpdConnData *connData, uint8_t *data, size_t len);
/// Callback type that releases the user data attached to the connection.
/// The format is compatible with regular "free()" or
typedef void (* httpdConnUserDataCleanupCb)(void *userData);
struct httpd_options { struct httpd_options {
uint16_t port; uint16_t port;
}; };
@ -79,15 +83,21 @@ struct HttpdConnData {
cgiSendCallback cgi; // CGI function pointer cgiSendCallback cgi; // CGI function pointer
cgiRecvHandler recvHdl; // Handler for data received after headers, if any cgiRecvHandler recvHdl; // Handler for data received after headers, if any
const void *cgiArg; // Argument to the CGI function, as stated as the 3rd argument of const void *cgiArg; // First CGI argument, can be NULL if not needed
// the builtInUrls entry that referred to the CGI function. const void *cgiArg2; // Second CGI argument for CGIs that need two parameters
const void *cgiArg2; // 4th argument of the builtInUrls entries, used to pass template file to the tpl handler. void *cgiData; // Opaque data pointer for the CGI function
void *cgiData; // Opaque data pointer for the CGI function
/// Opaque data pointer for user data that carries over between CGI calls for the same connection.
void *userData;
/// If userData is not NULL when a connection is finalized, this function (if set) is called to handle the cleanup.
/// This mechanism is useful when the user data is allocated by an auth CGI and the request can end in any number
/// of other routes, perhaps even with a static file - then the cleanup code doesn't need to be repeated everywhere.
httpdConnUserDataCleanupCb userDataCleanupCb;
// this should be at the end because of padding // this should be at the end because of padding
uint16_t remote_port; // Remote TCP port uint16_t remote_port; // Remote TCP port
uint8_t remote_ip[4]; // IP address of client uint8_t remote_ip[4]; // IP address of client
uint8_t slot; // Slot ID uint8_t slot; // Slot ID - index in s_connData
}; };
//A struct describing the POST data sent inside the http connection. This is used by the CGI functions //A struct describing the POST data sent inside the http connection. This is used by the CGI functions

@ -315,5 +315,7 @@ void httpdConnRelease(ConnTypePtr conn);
/** /**
* Close and retire all sockets. * Close and retire all sockets.
* Called during httpd shutdown. * Called during httpd shutdown.
*
* @internal
*/ */
void httpdInternalCloseAllSockets(); void httpdInternalCloseAllSockets();

@ -82,15 +82,15 @@ EspFsFile *tryOpenIndex(const char *path)
return NULL; // failed to guess the right name return NULL; // failed to guess the right name
} }
static httpd_cgi_state serveStaticFile(HttpdConnData *connData, const char *filepath) static httpd_cgi_state serveStaticFile(HttpdConnData *hconn, const char *filepath)
{ {
EspFsFile *file = connData->cgiData; EspFsFile *file = hconn->cgiData;
int len; int len;
uint8_t buff[FILE_CHUNK_LEN + 1]; uint8_t buff[FILE_CHUNK_LEN + 1];
char acceptEncodingBuffer[64 + 1]; char acceptEncodingBuffer[64 + 1];
int isGzip; int isGzip;
if (connData->conn == NULL) { if (hconn->conn == NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
espFsClose(file); espFsClose(file);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
@ -124,31 +124,31 @@ static httpd_cgi_state serveStaticFile(HttpdConnData *connData, const char *file
if (isGzip) { if (isGzip) {
// Check the browser's "Accept-Encoding" header. If the client does not // Check the browser's "Accept-Encoding" header. If the client does not
// advertise that he accepts GZIP send a warning message (telnet users for e.g.) // advertise that he accepts GZIP send a warning message (telnet users for e.g.)
httpdGetHeader(connData, "Accept-Encoding", acceptEncodingBuffer, 64); httpdGetHeader(hconn, "Accept-Encoding", acceptEncodingBuffer, 64);
if (strstr(acceptEncodingBuffer, "gzip") == NULL) { if (strstr(acceptEncodingBuffer, "gzip") == NULL) {
//No Accept-Encoding: gzip header present //No Accept-Encoding: gzip header present
httpdSendStr(connData, gzipNonSupportedMessage); httpdSendStr(hconn, gzipNonSupportedMessage);
espFsClose(file); espFsClose(file);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
} }
connData->cgiData = file; hconn->cgiData = file;
httpdStartResponse(connData, 200); httpdStartResponse(hconn, 200);
const char *mime = httpdGetMimetypeOr(filepath, "application/octet-stream"); const char *mime = httpdGetMimetypeOr(filepath, "application/octet-stream");
httpdHeader(connData, "Content-Type", mime); httpdHeader(hconn, "Content-Type", mime);
if (isGzip) { if (isGzip) {
httpdHeader(connData, "Content-Encoding", "gzip"); httpdHeader(hconn, "Content-Encoding", "gzip");
} }
httpdAddCacheHeaders(connData, mime); httpdAddCacheHeaders(hconn, mime);
httpdEndHeaders(connData); httpdEndHeaders(hconn);
return HTTPD_CGI_MORE; return HTTPD_CGI_MORE;
} }
len = espFsRead(file, buff, FILE_CHUNK_LEN); len = espFsRead(file, buff, FILE_CHUNK_LEN);
if (len > 0) { if (len > 0) {
espfs_dbg("[EspFS] Read file chunk: %d bytes", len); espfs_dbg("[EspFS] Read file chunk: %d bytes", len);
httpdSend(connData, buff, len); httpdSend(hconn, buff, len);
} }
if (len != FILE_CHUNK_LEN) { if (len != FILE_CHUNK_LEN) {
//We're done. //We're done.
@ -182,13 +182,10 @@ typedef enum {
typedef struct { typedef struct {
EspFsFile *file; EspFsFile *file;
// this is the struct passed to user
TplData td;
int tokenPos; int tokenPos;
char buff[FILE_CHUNK_LEN + 1]; char buff[FILE_CHUNK_LEN + 1];
char token[HTTPD_ESPFS_TOKEN_LEN]; char token[HTTPD_ESPFS_TOKEN_LEN];
char *pToken;
bool chunk_resume; bool chunk_resume;
int buff_len; int buff_len;
@ -199,17 +196,19 @@ typedef struct {
} TplDataInternal; } TplDataInternal;
int tplSendN(TplData *td, const char *str, int len) int tplSendN(HttpdConnData *conn, const char *str, int len)
{ {
if (td == NULL) { return 0; } if (conn == NULL) { return 0; }
TplDataInternal *tdi = container_of(td, TplDataInternal, td);
TplDataInternal *tdi = conn->cgiData;
if (!tdi) { return 0; }
if (tdi->tokEncode == ENCODE_PLAIN) { if (tdi->tokEncode == ENCODE_PLAIN) {
return httpdSendStrN(td->conn, str, len); return httpdSendStrN(conn, str, len);
} else if (tdi->tokEncode == ENCODE_HTML) { } else if (tdi->tokEncode == ENCODE_HTML) {
return httpdSend_html(td->conn, str, len); return httpdSend_html(conn, str, len);
} else if (tdi->tokEncode == ENCODE_JS) { } else if (tdi->tokEncode == ENCODE_JS) {
return httpdSend_js(td->conn, str, len); return httpdSend_js(conn, str, len);
} }
return 0; return 0;
} }
@ -228,9 +227,7 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn)
if (tdi) { if (tdi) {
TplCallback callback = (TplCallback) conn->cgiArg; TplCallback callback = (TplCallback) conn->cgiArg;
if (callback) { if (callback) {
tdi->td.conn = NULL; // indicate that this is the final call callback(conn, NULL);
tdi->td.token = NULL;
callback(&tdi->td);
} }
espFsClose(tdi->file); espFsClose(tdi->file);
@ -275,9 +272,6 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn)
return HTTPD_CGI_NOTFOUND; return HTTPD_CGI_NOTFOUND;
} }
tdi->td.conn = conn;
tdi->td.userData = NULL;
tdi->tokenPos = -1; tdi->tokenPos = -1;
conn->cgiData = tdi; conn->cgiData = tdi;
httpdStartResponse(conn, 200); httpdStartResponse(conn, 200);
@ -356,13 +350,13 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn)
tdi->tokEncode = ENCODE_JS; tdi->tokEncode = ENCODE_JS;
} }
tdi->td.token = &tdi->token[prefixLen]; tdi->pToken = &tdi->token[prefixLen];
} }
tdi->chunk_resume = false; tdi->chunk_resume = false;
TplCallback callback = (TplCallback) conn->cgiArg; TplCallback callback = (TplCallback) conn->cgiArg;
httpd_cgi_state status = callback(&tdi->td); httpd_cgi_state status = callback(conn, tdi->pToken);
if (status == HTTPD_CGI_MORE) { if (status == HTTPD_CGI_MORE) {
// espfs_dbg("Multi-part tpl subst, saving parser state"); // espfs_dbg("Multi-part tpl subst, saving parser state");
// wants to send more in this token's place..... // wants to send more in this token's place.....
@ -420,9 +414,7 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn)
TplCallback callback = (TplCallback) conn->cgiArg; TplCallback callback = (TplCallback) conn->cgiArg;
if (callback) { if (callback) {
tdi->td.conn = NULL; callback(conn, NULL);
tdi->td.token = NULL;
callback(&tdi->td);
} }
espfs_info("Template sent."); espfs_info("Template sent.");

@ -47,7 +47,7 @@ void httpdConnDisconnect(ConnTypePtr conn)
conn->needWriteDoneNotif = 1; //because the real close is done in the writable select code conn->needWriteDoneNotif = 1; //because the real close is done in the writable select code
} }
void platHttpServerTask(void *pvParameters) void httpdServerTask(void *pvParameters)
{ {
int32_t listenfd; int32_t listenfd;
int32_t len; int32_t len;
@ -81,7 +81,7 @@ void platHttpServerTask(void *pvParameters)
do { do {
listenfd = socket(AF_INET, SOCK_STREAM, 0); listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1) { if (listenfd == -1) {
error("platHttpServerTask: failed to create sock!"); error("httpdServerTask: failed to create sock!");
httpdPlatDelayMs(1000); httpdPlatDelayMs(1000);
} }
} while (listenfd == -1); } while (listenfd == -1);
@ -99,7 +99,7 @@ void platHttpServerTask(void *pvParameters)
do { do {
ret = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); ret = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (ret != 0) { if (ret != 0) {
error("platHttpServerTask: failed to bind!"); error("httpdServerTask: failed to bind!");
httpdPlatDelayMs(1000); httpdPlatDelayMs(1000);
} }
} while (ret != 0); } while (ret != 0);
@ -108,7 +108,7 @@ void platHttpServerTask(void *pvParameters)
/* Listen to the local connection */ /* Listen to the local connection */
ret = listen(listenfd, HTTPD_MAX_CONNECTIONS); ret = listen(listenfd, HTTPD_MAX_CONNECTIONS);
if (ret != 0) { if (ret != 0) {
error("platHttpServerTask: failed to listen!"); error("httpdServerTask: failed to listen!");
httpdPlatDelayMs(1000); httpdPlatDelayMs(1000);
} }
} while (ret != 0); } while (ret != 0);
@ -162,7 +162,7 @@ void platHttpServerTask(void *pvParameters)
len = sizeof(struct sockaddr_in); len = sizeof(struct sockaddr_in);
const int remotefd = accept(listenfd, (struct sockaddr *) &remote_addr, (socklen_t *) &len); const int remotefd = accept(listenfd, (struct sockaddr *) &remote_addr, (socklen_t *) &len);
if (remotefd < 0) { if (remotefd < 0) {
warn("platHttpServerTask: Huh? Accept failed."); warn("httpdServerTask: Huh? Accept failed.");
continue; continue;
} }
@ -174,7 +174,7 @@ void platHttpServerTask(void *pvParameters)
} }
} }
if (socknum >= HTTPD_MAX_CONNECTIONS) { if (socknum >= HTTPD_MAX_CONNECTIONS) {
warn("platHttpServerTask: Huh? Got accept with all slots full."); warn("httpdServerTask: Huh? Got accept with all slots full.");
continue; continue;
} }

@ -18,7 +18,8 @@ Esp8266 http server - core routines
#include "httpd-utils.h" #include "httpd-utils.h"
#include "httpd-logging.h" #include "httpd-logging.h"
static void httpdRetireConn(HttpdConnData *conn); static void cleanupCgiAndUserData(HttpdConnData *hconn);
static void httpdRetireConn(HttpdConnData *hconn);
//This gets set at init time. //This gets set at init time.
static const HttpdBuiltInUrl *s_builtInUrls; static const HttpdBuiltInUrl *s_builtInUrls;
@ -128,27 +129,34 @@ static HttpdConnData *httpdFindConnData(ConnTypePtr conn, const char *remIp, int
} }
//Retires a connection for re-use //Retires a connection for re-use
static void httpdRetireConn(HttpdConnData *conn) static void httpdRetireConn(HttpdConnData *hconn)
{ {
if (!conn) { if (!hconn) {
return; return;
} }
if (conn->priv->sendBacklog != NULL) { http_info("Pool slot %d: socket closed.", hconn->slot);
// this sets the `conn` pointer to NULL to indicate we are cleaning up to CGI
cleanupCgiAndUserData(hconn);
// Free any memory allocated for backlog - walk the linked list
if (hconn->priv->sendBacklog != NULL) {
HttpSendBacklogItem *i, *j; HttpSendBacklogItem *i, *j;
i = conn->priv->sendBacklog; i = hconn->priv->sendBacklog;
do { do {
j = i; j = i;
i = i->next; i = i->next;
httpdPlatFree(j); httpdPlatFree(j);
} while (i != NULL); } while (i != NULL);
} }
if (conn->post->buff != NULL) { httpdPlatFree(conn->post->buff); } if (hconn->post->buff != NULL) { httpdPlatFree(hconn->post->buff); }
if (conn->post != NULL) { httpdPlatFree(conn->post); } if (hconn->post != NULL) { httpdPlatFree(hconn->post); }
if (conn->priv != NULL) { httpdPlatFree(conn->priv); } if (hconn->priv != NULL) { httpdPlatFree(hconn->priv); }
httpdPlatFree(conn);
for (int i = 0; i < HTTPD_MAX_CONNECTIONS; i++) { // Unlink from the connection list
if (s_connData[i] == conn) { s_connData[i] = NULL; } s_connData[hconn->slot] = NULL;
} // release memory
httpdPlatFree(hconn);
} }
//Get the value of a certain header in the HTTP client head //Get the value of a certain header in the HTTP client head
@ -525,12 +533,12 @@ static void httpdProcessRequest(HttpdConnData *conn)
//See if there's a literal match //See if there's a literal match
if (streq(route, conn->url)) { match = 1; } if (streq(route, conn->url)) { match = 1; }
//See if there's a wildcard match (*) //See if there's a wildcard match (*)
if (last_char(route) == '*' && if (!match && last_char(route) == '*' &&
strneq(route, conn->url, strlen(route) - 1)) { strneq(route, conn->url, strlen(route) - 1)) {
match = 1; match = 1;
} }
// Optional slash (/?) // Optional slash (/?)
if (last_char(route) == '?' && last_char_n(route, 2) == '/' && if (!match && last_char(route) == '?' && last_char_n(route, 2) == '/' &&
strneq(route, conn->url, strlen(route) - 2) && strneq(route, conn->url, strlen(route) - 2) &&
strlen(conn->url) <= strlen(route) - 1) { strlen(conn->url) <= strlen(route) - 1) {
match = 1; match = 1;
@ -820,13 +828,30 @@ void httpdDisconCb(ConnTypePtr rconn, const char *remIp, int remPort)
httpdPlatUnlock(); httpdPlatUnlock();
return; return;
} }
http_info("Pool slot %d: socket closed.", hconn->slot);
hconn->conn = NULL; //indicate cgi the connection is gone
if (hconn->cgi) { hconn->cgi(hconn); } //Execute cgi fn if needed
httpdRetireConn(hconn); httpdRetireConn(hconn);
httpdPlatUnlock(); httpdPlatUnlock();
} }
/**
* Clean up cgiData and userData and do any cgi-specific finalizing.
*
* @param hconn
*/
static void cleanupCgiAndUserData(HttpdConnData *hconn)
{
hconn->conn = NULL; //indicate cgi the connection is gone
if (hconn->cgi) {
//Execute cgi fn if needed
hconn->cgi(hconn);
hconn->cgi = NULL;
}
if (hconn->userDataCleanupCb && hconn->userData) {
hconn->userDataCleanupCb(hconn->userData);
hconn->userData = NULL;
hconn->userDataCleanupCb = NULL;
}
}
int httpdConnectCb(ConnTypePtr conn, const char *remIp, int remPort) int httpdConnectCb(ConnTypePtr conn, const char *remIp, int remPort)
{ {

@ -45,9 +45,9 @@ struct httpd_thread_handle {
// TODO some way to signal shutdown? // TODO some way to signal shutdown?
}; };
void* platHttpServerTaskPosix(void *pvParameters) void* httpdServerTaskPosix(void *pvParameters)
{ {
platHttpServerTask(pvParameters); httpdServerTask(pvParameters);
return NULL; return NULL;
} }
@ -59,7 +59,7 @@ httpd_thread_handle_t *httpdPlatStart(struct httpd_options *opts)
return NULL; return NULL;
} }
pthread_create( &handle->handle, NULL, platHttpServerTaskPosix, (void*) opts); pthread_create(&handle->handle, NULL, httpdServerTaskPosix, (void *) opts);
return handle; return handle;
} }

Loading…
Cancel
Save