diff options
-rw-r--r-- | nanohttp/nanohttp-client.c | 1357 | ||||
-rw-r--r-- | nanohttp/nanohttp-common.c | 1050 | ||||
-rw-r--r-- | nanohttp/nanohttp-common.h | 4 | ||||
-rw-r--r-- | nanohttp/nanohttp-server.c | 680 | ||||
-rw-r--r-- | nanohttp/nanohttp-socket.c | 543 | ||||
-rw-r--r-- | nanohttp/nanohttp-socket.h | 10 | ||||
-rw-r--r-- | nanohttp/nanohttp.vcproj | 173 | ||||
-rw-r--r-- | nanohttp/pthread.h | 1345 | ||||
-rw-r--r-- | nanohttp/sched.h | 174 | ||||
-rw-r--r-- | nanohttp/semaphore.h | 163 | ||||
-rw-r--r-- | nanohttp/wsockcompat.h | 61 |
11 files changed, 3794 insertions, 1766 deletions
diff --git a/nanohttp/nanohttp-client.c b/nanohttp/nanohttp-client.c index 4f62afc..8f49048 100644 --- a/nanohttp/nanohttp-client.c +++ b/nanohttp/nanohttp-client.c @@ -1,28 +1,34 @@ /****************************************************************** - * $Id: nanohttp-client.c,v 1.12 2004/06/04 08:55:07 snowdrop Exp $ - * - * CSOAP Project: A http client/server library in C - * Copyright (C) 2003 Ferhat Ayaz - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Email: ayaz@jprogrammer.net - ******************************************************************/ +* $Id: nanohttp-client.c,v 1.13 2004/08/26 17:07:47 rans Exp $ +* +* CSOAP Project: A http client/server library in C +* Copyright (C) 2003 Ferhat Ayaz +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +* +* Email: ayaz@jprogrammer.net +******************************************************************/ #include <nanohttp/nanohttp-client.h> +#ifdef WIN32 +#include "wsockcompat.h" +#include <winsock2.h> +#define close(s) closesocket(s) +#endif + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -30,858 +36,859 @@ #include <time.h> #include <stdio.h> #include <stdlib.h> - - +#ifdef WIN32 +#include <string.h> +static struct tm *localtime_r(const time_t *const timep, struct tm *p_tm) +{ + static tm* tmp; + tmp = localtime(timep); + if (tmp) { + memcpy(p_tm, tmp, sizeof(struct tm)); + tmp = p_tm; + } + return tmp; +} +#endif /*-------------------------------------------------- - FUNCTION: httpc_new - DESC: Creates a new http client connection object - You need to create at least 1 http client connection - to communicate via http. +FUNCTION: httpc_new +DESC: Creates a new http client connection object +You need to create at least 1 http client connection +to communicate via http. ----------------------------------------------------*/ httpc_conn_t* httpc_new() { - httpc_conn_t* res = (httpc_conn_t*)malloc(sizeof(httpc_conn_t)); + httpc_conn_t* res = (httpc_conn_t*)malloc(sizeof(httpc_conn_t)); - hsocket_init(&res->sock); - res->header = NULL; - res->url = NULL; + hsocket_init(&res->sock); + res->header = NULL; + res->url = NULL; - return res; + return res; } /*-------------------------------------------------- - FUNCTION: httpc_free - DESC: Free the given http client object. +FUNCTION: httpc_free +DESC: Free the given http client object. ----------------------------------------------------*/ void httpc_free(httpc_conn_t* conn) { - hpair_t *tmp; - - if (conn != NULL) { - hsocket_free(conn->sock); - - while (conn->header != NULL) { - tmp = conn->header; - conn->header = conn->header->next; - hpairnode_free(tmp); - } - - free(conn); - } + hpair_t *tmp; + + if (conn != NULL) { + hsocket_free(conn->sock); + + while (conn->header != NULL) { + tmp = conn->header; + conn->header = conn->header->next; + hpairnode_free(tmp); + } + + free(conn); + } } /*-------------------------------------------------- - FUNCTION: httpc_set_header - DESC: Adds a new (key, value) pair to the header - or modifies the old pair if this function will - finds another pair with the same 'key' value. +FUNCTION: httpc_set_header +DESC: Adds a new (key, value) pair to the header +or modifies the old pair if this function will +finds another pair with the same 'key' value. ----------------------------------------------------*/ int httpc_set_header(httpc_conn_t *conn, const char* key, const char* value) { - hpair_t *p; - - if (conn == NULL) { - log_warn1("Connection object is NULL"); - return 0; - } - - p = conn->header; - while (p != NULL) { - if (p->key != NULL) { - if (!strcmp(p->key, key)) { - free(p->value); - p->value = (char*)malloc(strlen(value)+1); - strcpy(p->value, value); - return 1; - } - } - p = p->next; - } - - conn->header = hpairnode_new(key, value, conn->header); - return 0; + hpair_t *p; + + if (conn == NULL) { + log_warn1("Connection object is NULL"); + return 0; + } + + p = conn->header; + while (p != NULL) { + if (p->key != NULL) { + if (!strcmp(p->key, key)) { + free(p->value); + p->value = (char*)malloc(strlen(value)+1); + strcpy(p->value, value); + return 1; + } + } + p = p->next; + } + + conn->header = hpairnode_new(key, value, conn->header); + return 0; } /*-------------------------------------------------- - FUNCTION: httpc_header_add_date - DESC: Adds the current date to the header. +FUNCTION: httpc_header_add_date +DESC: Adds the current date to the header. ----------------------------------------------------*/ static void httpc_header_add_date(httpc_conn_t *conn) { - char buffer[255]; - time_t nw; - struct tm stm; - - /* Set date */ - nw = time(NULL); - localtime_r(&nw, &stm); - strftime(buffer, 255, "%a, %d %b %y %T GMT", &stm); - httpc_set_header(conn, HEADER_DATE, buffer); + char buffer[255]; + time_t nw; + struct tm stm; + + /* Set date */ + nw = time(NULL); + localtime_r(&nw, &stm); + strftime(buffer, 255, "%a, %d %b %y %T GMT", &stm); + httpc_set_header(conn, HEADER_DATE, buffer); } /*-------------------------------------------------- - FUNCTION: httpc_send_header - DESC: Sends the current header information stored - in conn through conn->sock. +FUNCTION: httpc_send_header +DESC: Sends the current header information stored +in conn through conn->sock. ----------------------------------------------------*/ int httpc_send_header(httpc_conn_t *conn) { - hpair_t *p; - int status; - char buffer[1024]; - - p = conn->header; - while (p != NULL) { - if (p->key && p->value) { - sprintf(buffer, "%s: %s\r\n", p->key, p->value); - status = hsocket_send(conn->sock, buffer); - if (status != HSOCKET_OK) - return status; - } - p = p->next; - } + hpair_t *p; + int status; + char buffer[1024]; + + p = conn->header; + while (p != NULL) { + if (p->key && p->value) { + sprintf(buffer, "%s: %s\r\n", p->key, p->value); + status = hsocket_send(conn->sock, buffer); + if (status != HSOCKET_OK) + return status; + } + p = p->next; + } - status = hsocket_send(conn->sock, "\r\n"); - return status; + status = hsocket_send(conn->sock, "\r\n"); + return status; } static hresponse_t *httpc_receive_header(hsocket_t sock) { - hresponse_t *res; - int done; - int i; - int status; - char buffer[HSOCKET_MAX_BUFSIZE]; - char *response; - char *rest; - int rsize; - int restsize; - - /* Receive Response incl. header */ - rsize = restsize = 0; - response = rest = NULL; - done = 0; - - while (!done) { - - status = hsocket_read(sock, buffer, HSOCKET_MAX_BUFSIZE, 0); - - if (status <= 0) { - log_error2("Can not receive response (status:%d)", status); - return NULL; - } - - - for (i=0;i<status-2;i++) { - - /* log_debug5("%d -> '%c' (%d, %d)", buffer[i], buffer[i], - buffer[i+1], buffer[i+2]); - */ - if (buffer[i] == '\n') { - if (buffer[i+1] == '\n') { - - response = (char*)realloc(response, rsize+i+1); - strncpy(&response[rsize], buffer, i); - response[rsize+i] = '\0'; - rsize += i; - - restsize = status - i - 2; - rest = (char*)malloc(restsize+1); - strncpy(rest, &buffer[i+2], restsize); - rest[restsize] = '\0'; - done = 1; - break; - - } else if (buffer[i+1] == '\r' && buffer[i+2] == '\n') { - - response = (char*)realloc(response, rsize+i+1); - strncpy(&response[rsize], buffer, i); - response[rsize+i] = '\0'; - rsize += i; - - restsize = status - i - 3; - rest = (char*)malloc(restsize+1); - strncpy(rest, &buffer[i+3], restsize); - rest[restsize] = '\0'; - done = 1; - break; + hresponse_t *res; + int done; + int i; + int status; + char buffer[HSOCKET_MAX_BUFSIZE]; + char *response; + char *rest; + int rsize; + int restsize; + + /* Receive Response incl. header */ + rsize = restsize = 0; + response = rest = NULL; + done = 0; + + while (!done) { + + status = hsocket_read(sock, buffer, HSOCKET_MAX_BUFSIZE, 0); + + if (status <= 0) { + log_error2("Can not receive response (status:%d)", status); + return NULL; + } + + + for (i=0;i<status-2;i++) { + + /* log_debug5("%d -> '%c' (%d, %d)", buffer[i], buffer[i], + buffer[i+1], buffer[i+2]); + */ + if (buffer[i] == '\n') { + if (buffer[i+1] == '\n') { + + response = (char*)realloc(response, rsize+i+1); + strncpy(&response[rsize], buffer, i); + response[rsize+i] = '\0'; + rsize += i; + + restsize = status - i - 2; + rest = (char*)malloc(restsize+1); + strncpy(rest, &buffer[i+2], restsize); + rest[restsize] = '\0'; + done = 1; + break; + + } else if (buffer[i+1] == '\r' && buffer[i+2] == '\n') { + + response = (char*)realloc(response, rsize+i+1); + strncpy(&response[rsize], buffer, i); + response[rsize+i] = '\0'; + rsize += i; + + restsize = status - i - 3; + rest = (char*)malloc(restsize+1); + strncpy(rest, &buffer[i+3], restsize); + rest[restsize] = '\0'; + done = 1; + break; + } + } + } + + if (!done) + rsize += status; + } + + + if (response == NULL) { + log_error1("Header too long!"); + return NULL; + } + + res = hresponse_new_from_buffer(response); + if (res == NULL) { + log_error1("Can't create response"); + return NULL; + } + + res->bodysize = restsize; + res->body = rest; + + if (res->errcode == 100) { /* continue */ + hresponse_free(res); + res = httpc_receive_header(sock); } - } - } - - if (!done) - rsize += status; - } - - - if (response == NULL) { - log_error1("Header too long!"); - return NULL; - } - - res = hresponse_new_from_buffer(response); - if (res == NULL) { - log_error1("Can't create response"); - return NULL; - } - - res->bodysize = restsize; - res->body = rest; - - if (res->errcode == 100) { /* continue */ - hresponse_free(res); - res = httpc_receive_header(sock); - } - return res; + return res; } static int httpc_receive_with_connection_closed(httpc_conn_t *conn, - hresponse_t *res, - httpc_response_callback cb, - void *userdata) + hresponse_t *res, + httpc_response_callback cb, + void *userdata) { - /* connection closed */ - char *connection_status; - int status; - char buffer[HSOCKET_MAX_BUFSIZE]; - int counter; + /* connection closed */ + char *connection_status; + int status; + char buffer[HSOCKET_MAX_BUFSIZE]; + int counter; + + counter = 0; + + /* ================================================= */ + /* Retreive with only "Connection: close" */ + /* ================================================= */ + connection_status = + hpairnode_get(res->header, HEADER_CONNECTION); - counter = 0; + if (connection_status != NULL && + !strcmp(connection_status, "close")) { - /* ================================================= */ - /* Retreive with only "Connection: close" */ - /* ================================================= */ - connection_status = - hpairnode_get(res->header, HEADER_CONNECTION); + log_debug1("Server communicates with 'Connection: close' !"); - if (connection_status != NULL && - !strcmp(connection_status, "close")) { + /* Invoke callback for rest */ + if (res->bodysize > 0) + cb(0, conn, userdata, res->bodysize, res->body); - log_debug1("Server communicates with 'Connection: close' !"); - /* Invoke callback for rest */ - if (res->bodysize > 0) - cb(0, conn, userdata, res->bodysize, res->body); + while (1) { + status = hsocket_read(conn->sock, buffer, HSOCKET_MAX_BUFSIZE, 0); - while (1) { - - status = hsocket_read(conn->sock, buffer, HSOCKET_MAX_BUFSIZE, 0); + if (status == 0) { /* close connection */ + close(conn->sock); + return 0; + } - if (status == 0) { /* close connection */ - close(conn->sock); - return 0; - } - - if (status < 0) { /* error */ - log_error2("Can nor read from socket (status: %d)", status); - return 11; - } + if (status < 0) { /* error */ + log_error2("Can nor read from socket (status: %d)", status); + return 11; + } - /* Invoke callback */ - cb(counter++, conn, userdata, status, buffer); - } + /* Invoke callback */ + cb(counter++, conn, userdata, status, buffer); + } - return 0; - } + return 0; + } - return -1; + return -1; } static int httpc_receive_with_chunked_encoding(httpc_conn_t *conn, - hresponse_t *res, - httpc_response_callback cb, - void *userdata) + hresponse_t *res, + httpc_response_callback cb, + void *userdata) { - /* chunked encoding */ - char *transfer_encoding; - char *chunk_buffer; - int chunk_size; - hbufsocket_t bufsock; - char chunk_size_str[25]; - int chunk_size_cur; - int counter; - char buffer[2]; - - counter = 0; - /* ================================================= */ - /* Retreive with chunked encoding */ - /* ================================================= */ - - /* Check if server communicates with chunked encoding */ - transfer_encoding = - hpairnode_get(res->header, HEADER_TRANSFER_ENCODING); - - if (transfer_encoding != NULL && - !strcmp(transfer_encoding, "chunked")) { - - log_debug1("Server communicates with chunked encoding !"); - - /* initialize buffered socket */ - bufsock.sock = conn->sock; - bufsock.cur = 0; - bufsock.buffer = res->body; - bufsock.bufsize = res->bodysize; - - chunk_size = 1; - while (chunk_size > 0) { - - /* read chunk size */ - chunk_size_cur = 0; - while (1) { - - - if (hbufsocket_read(&bufsock, &chunk_size_str[chunk_size_cur], 1)) { - log_error1("Can not read from socket"); - return 9; - } - - log_debug2("chunk_size_str[chunk_size_cur] = '%c'", - chunk_size_str[chunk_size_cur]); + /* chunked encoding */ + char *transfer_encoding; + char *chunk_buffer; + int chunk_size; + hbufsocket_t bufsock; + char chunk_size_str[25]; + int chunk_size_cur; + int counter; + char buffer[2]; - if (chunk_size_str[chunk_size_cur] == '\n') { - chunk_size_str[chunk_size_cur] = '\0'; - break; - } + counter = 0; + /* ================================================= */ + /* Retreive with chunked encoding */ + /* ================================================= */ - if (chunk_size_str[chunk_size_cur] != '\r' - && chunk_size_str[chunk_size_cur] != ';') { - chunk_size_cur++; - } + /* Check if server communicates with chunked encoding */ + transfer_encoding = + hpairnode_get(res->header, HEADER_TRANSFER_ENCODING); + + if (transfer_encoding != NULL && + !strcmp(transfer_encoding, "chunked")) { + + log_debug1("Server communicates with chunked encoding !"); + + /* initialize buffered socket */ + bufsock.sock = conn->sock; + bufsock.cur = 0; + bufsock.buffer = (char *)res->body; + bufsock.bufsize = res->bodysize; - } /* while (1) */ - - chunk_size = strtol(chunk_size_str,(char**)NULL, 16); /* hex to dec */ - log_debug3("chunk_size: '%s' as dec: '%d'", - chunk_size_str, chunk_size); - - if (chunk_size <= 0) break; - - chunk_buffer = (char*)malloc(chunk_size+1); - if (hbufsocket_read(&bufsock, chunk_buffer, chunk_size)) { - log_error1("Can not read from socket"); - return 9; - } - cb(counter++, conn, userdata, chunk_size, chunk_buffer); - free(chunk_buffer); - - /* skip new line */ - buffer[0] = 0; /* reset buffer[0] */ - while (buffer[0] != '\n') { - hbufsocket_read(&bufsock, &buffer[0], 1); - } - - } /* while (chunk_size > 0) */ - - /* rest and response are no longer required */ - - return 0; - - } /* if transfer_encodig */ - - return -1; + chunk_size = 1; + while (chunk_size > 0) { + + /* read chunk size */ + chunk_size_cur = 0; + while (1) { + + + if (hbufsocket_read(&bufsock, &chunk_size_str[chunk_size_cur], 1)) { + log_error1("Can not read from socket"); + return 9; + } + + log_debug2("chunk_size_str[chunk_size_cur] = '%c'", + chunk_size_str[chunk_size_cur]); + + if (chunk_size_str[chunk_size_cur] == '\n') { + chunk_size_str[chunk_size_cur] = '\0'; + break; + } + + if (chunk_size_str[chunk_size_cur] != '\r' + && chunk_size_str[chunk_size_cur] != ';') { + chunk_size_cur++; + } + + } /* while (1) */ + + chunk_size = strtol(chunk_size_str,(char**)NULL, 16); /* hex to dec */ + log_debug3("chunk_size: '%s' as dec: '%d'", + chunk_size_str, chunk_size); + + if (chunk_size <= 0) break; + + chunk_buffer = (char*)malloc(chunk_size+1); + if (hbufsocket_read(&bufsock, chunk_buffer, chunk_size)) { + log_error1("Can not read from socket"); + return 9; + } + cb(counter++, conn, userdata, chunk_size, chunk_buffer); + free(chunk_buffer); + + /* skip new line */ + buffer[0] = 0; /* reset buffer[0] */ + while (buffer[0] != '\n') { + hbufsocket_read(&bufsock, &buffer[0], 1); + } + + } /* while (chunk_size > 0) */ + + /* rest and response are no longer required */ + + return 0; + + } /* if transfer_encodig */ + + return -1; } /* - returns -1 if server does not communicate with - content-length; - */ +returns -1 if server does not communicate with +content-length; +*/ static int httpc_receive_with_content_length(httpc_conn_t *conn, - hresponse_t *res, - httpc_response_callback cb, - void *userdata) + hresponse_t *res, + httpc_response_callback cb, + void *userdata) { - int counter; - int content_length; - int remain_length; - int recvSize; - char *content_length_str; - char buffer[HSOCKET_MAX_BUFSIZE]; + int counter; + int content_length; + int remain_length; + int recvSize; + char *content_length_str; + char buffer[HSOCKET_MAX_BUFSIZE]; - /* ================================================= */ - /* Retreive with content-length */ - /* ================================================= */ + /* ================================================= */ + /* Retreive with content-length */ + /* ================================================= */ - /* Check if server communicates with content-length */ - content_length_str = - hpairnode_get_ignore_case(res->header, HEADER_CONTENT_LENGTH); + /* Check if server communicates with content-length */ + content_length_str = + hpairnode_get_ignore_case(res->header, HEADER_CONTENT_LENGTH); - if (content_length_str != NULL) { + if (content_length_str != NULL) { - log_debug1("Server communicates with content-length!"); - - /* Invoke callback for rest */ - if (res->bodysize > 0) - cb(0, conn, userdata, res->bodysize, res->body); + log_debug1("Server communicates with content-length!"); - /* content length */ - content_length = atol(content_length_str); + /* Invoke callback for rest */ + if (res->bodysize > 0) + cb(0, conn, userdata, res->bodysize, (char *)res->body); - counter = 1; - remain_length = content_length - res->bodysize; - while (remain_length > 0) { - if (remain_length >= HSOCKET_MAX_BUFSIZE) { - recvSize = HSOCKET_MAX_BUFSIZE; - } else { - recvSize = remain_length; - } + /* content length */ + content_length = atol(content_length_str); - if (hsocket_read(conn->sock, buffer, recvSize,1)) { - log_error1("Can not read from socket!"); - return 9; - } else { - cb(counter++, conn, userdata, recvSize, buffer); - } + counter = 1; + remain_length = content_length - res->bodysize; + while (remain_length > 0) { + if (remain_length >= HSOCKET_MAX_BUFSIZE) { + recvSize = HSOCKET_MAX_BUFSIZE; + } else { + recvSize = remain_length; + } - remain_length -= HSOCKET_MAX_BUFSIZE; + if (hsocket_read(conn->sock, buffer, recvSize,1)) { + log_error1("Can not read from socket!"); + return 9; + } else { + cb(counter++, conn, userdata, recvSize, buffer); + } - } /* while */ + remain_length -= HSOCKET_MAX_BUFSIZE; - /* rest and response are no longer required */ + } /* while */ - return 0; + /* rest and response are no longer required */ - } /* if content length */ + return 0; - return -1; + } /* if content length */ + + return -1; } static int httpc_receive_response(httpc_conn_t *conn, - httpc_response_start_callback start_cb, - httpc_response_callback cb, void *userdata) + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata) { - hresponse_t *res; - int status; - - /* receive header */ - log_verbose1("receiving header"); - res = httpc_receive_header(conn->sock); - if (res == NULL) return 1; - log_verbose1("header ok"); - - /* Invoke callback */ - start_cb(conn, userdata, res->header, res->spec, - res->errcode, res->desc); - - /* try to receive with content length */ - status = httpc_receive_with_content_length(conn, res, - cb, userdata); - if (status != -1) { - hresponse_free(res); - return status; - } - - status = httpc_receive_with_chunked_encoding(conn, res, - cb, userdata); - - if (status != -1) { - hresponse_free(res); - return status; - } - - status = httpc_receive_with_connection_closed(conn, res, - cb, userdata); - if (status != -1) { - hresponse_free(res); - return status; - } - - log_error1("Unknown server response retreive type!"); + hresponse_t *res; + int status; + + /* receive header */ + log_verbose1("receiving header"); + res = httpc_receive_header(conn->sock); + if (res == NULL) return 1; + log_verbose1("header ok"); + + /* Invoke callback */ + start_cb(conn, userdata, res->header, res->spec, + res->errcode, res->desc); + + /* try to receive with content length */ + status = httpc_receive_with_content_length(conn, res, + cb, userdata); + if (status != -1) { + hresponse_free(res); + return status; + } + + status = httpc_receive_with_chunked_encoding(conn, res, + cb, userdata); + + if (status != -1) { + hresponse_free(res); + return status; + } + + status = httpc_receive_with_connection_closed(conn, res, + cb, userdata); + if (status != -1) { + hresponse_free(res); + return status; + } + + log_error1("Unknown server response retreive type!"); } /*-------------------------------------------------- - FUNCTION: httpc_talk_to_server - DESC: This function is the heart of the httpc - module. It will send the request and process the - response. - - Here the parameters: - - method: - the request method. This can be HTTP_REQUEST_POST and - HTTP_REQUEST_GET. - - conn: - the connection object (created with httpc_new()) - - urlstr: - the complete url in string format. - http://<host>:<port>/<context> - where <port> is not mendatory. - - start_cb: - a callback function, which will be called when - the response header is completely arrives. - - cb: - a callback function, which will be called everytime - when data arrives. - - content_size: - size of content to send. - (only if method is HTTP_REQUEST_POST) - - content: - the content data to send. - (only if method is HTTP_REQUEST_POST) - - userdata: - a user define data, which will be passed to the - start_cb and cb callbacks as a parameter. This - can also be NULL. - - - If success, this function will return 0. - >0 otherwise. +FUNCTION: httpc_talk_to_server +DESC: This function is the heart of the httpc +module. It will send the request and process the +response. + +Here the parameters: + +method: +the request method. This can be HTTP_REQUEST_POST and +HTTP_REQUEST_GET. + +conn: +the connection object (created with httpc_new()) + +urlstr: +the complete url in string format. +http://<host>:<port>/<context> +where <port> is not mendatory. + +start_cb: +a callback function, which will be called when +the response header is completely arrives. + +cb: +a callback function, which will be called everytime +when data arrives. + +content_size: +size of content to send. +(only if method is HTTP_REQUEST_POST) + +content: +the content data to send. +(only if method is HTTP_REQUEST_POST) + +userdata: +a user define data, which will be passed to the +start_cb and cb callbacks as a parameter. This +can also be NULL. + + +If success, this function will return 0. +>0 otherwise. ----------------------------------------------------*/ static int httpc_talk_to_server(hreq_method method, httpc_conn_t *conn, - const char *urlstr) + const char *urlstr) { - hurl_t *url; - char buffer[4096]; - int status; - - - if (conn == NULL) { - log_error1("Connection object is NULL"); - return 1; - } - - /* Build request header */ - httpc_header_add_date(conn); - - /* Create url */ - url = hurl_new(urlstr); - if (url == NULL) { - log_error2("Can not parse URL '%s'", SAVE_STR(urlstr)); - return 2; - } - - /* Set hostname */ - httpc_set_header(conn, HEADER_HOST, url->host); - - /* Open connection */ - status = hsocket_open(&conn->sock, url->host, url->port); - if (status != HSOCKET_OK) { - log_error3("Can not open connection to '%s' (status:%d)", - SAVE_STR(url->host), status); - return 3; - } - - /* check method */ - if (method == HTTP_REQUEST_GET) { - - /* Set GET Header */ - sprintf(buffer, "GET %s HTTP/1.1\r\n", - (url->context)?url->context:("/")); - - } else if (method == HTTP_REQUEST_POST) { - - /* Set POST Header */ - sprintf(buffer, "POST %s HTTP/1.1\r\n", - (url->context)?url->context:("/")); - } else { - - log_error1("Unknown method type!"); - return 15; - } - - status = hsocket_send(conn->sock, buffer); - if (status != HSOCKET_OK) { - log_error2("Can not send request (status:%d)", status); - hsocket_close(conn->sock); - return 4; - } - - /* Send Header */ - status = httpc_send_header(conn); - if (status != HSOCKET_OK) { - log_error2("Can not send header (status:%d)", status); - hsocket_close(conn->sock); - return 5; - } - - return status; - + hurl_t *url; + char buffer[4096]; + int status; + + + if (conn == NULL) { + log_error1("Connection object is NULL"); + return 1; + } + + /* Build request header */ + httpc_header_add_date(conn); + + /* Create url */ + url = hurl_new(urlstr); + if (url == NULL) { + log_error2("Can not parse URL '%s'", SAVE_STR(urlstr)); + return 2; + } + + /* Set hostname */ + httpc_set_header(conn, HEADER_HOST, url->host); + + /* Open connection */ + status = hsocket_open(&conn->sock, url->host, url->port); + if (status != HSOCKET_OK) { + log_error3("Can not open connection to '%s' (status:%d)", + SAVE_STR(url->host), status); + return 3; + } + +#ifndef WIN32 +#if HSOCKET_BLOCKMODE!=0 + fcntl(conn->sock, F_SETFL, O_NONBLOCK); +#endif +#else + unsigned long iMode = HSOCKET_BLOCKMODE; + if(ioctlsocket(conn->sock, FIONBIO, (u_long FAR*) &iMode) == INVALID_SOCKET) + { + log_error1("ioctlsocket error"); + return -1; + } + +#endif + + /* check method */ + if (method == HTTP_REQUEST_GET) { + + /* Set GET Header */ + sprintf(buffer, "GET %s HTTP/1.1\r\n", + (url->context)?url->context:("/")); + + } else if (method == HTTP_REQUEST_POST) { + + /* Set POST Header */ + sprintf(buffer, "POST %s HTTP/1.1\r\n", + (url->context)?url->context:("/")); + } else { + + log_error1("Unknown method type!"); + return 15; + } + + status = hsocket_send(conn->sock, buffer); + if (status != HSOCKET_OK) { + log_error2("Can not send request (status:%d)", status); + hsocket_close(conn->sock); + return 4; + } + + /* Send Header */ + status = httpc_send_header(conn); + if (status != HSOCKET_OK) { + log_error2("Can not send header (status:%d)", status); + hsocket_close(conn->sock); + return 5; + } + + return status; + } - - + + /*-------------------------------------------------- - FUNCTION: httpc_get_cb - DESC: Wraps the httpc_talk_to_server() function - to communicate with GET method. +FUNCTION: httpc_get_cb +DESC: Wraps the httpc_talk_to_server() function +to communicate with GET method. - See the documentation of httpc_talk_to_server() - for more information. +See the documentation of httpc_talk_to_server() +for more information. ----------------------------------------------------*/ int httpc_get_cb(httpc_conn_t *conn, const char *urlstr, - httpc_response_start_callback start_cb, - httpc_response_callback cb, void *userdata) + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata) { - int status; + int status; - status = httpc_talk_to_server(HTTP_REQUEST_GET, conn, urlstr); + status = httpc_talk_to_server(HTTP_REQUEST_GET, conn, urlstr); - if (status != HSOCKET_OK) - return status; + if (status != HSOCKET_OK) + return status; - status = httpc_receive_response(conn, start_cb, cb, userdata); - return status; + status = httpc_receive_response(conn, start_cb, cb, userdata); + return status; } /*-------------------------------------------------- - FUNCTION: httpc_post_cb - DESC: Wraps the httpc_talk_to_server() function - to communicate with POST method. +FUNCTION: httpc_post_cb +DESC: Wraps the httpc_talk_to_server() function +to communicate with POST method. - See the documentation of httpc_talk_to_server() - for more information. +See the documentation of httpc_talk_to_server() +for more information. - TODO: Add post content rutine +TODO: Add post content rutine ----------------------------------------------------*/ int httpc_post_cb(httpc_conn_t *conn, const char *urlstr, - httpc_response_start_callback start_cb, - httpc_response_callback cb, int content_size, - char *content, void *userdata) + httpc_response_start_callback start_cb, + httpc_response_callback cb, int content_size, + char *content, void *userdata) { - int status; - char buffer[255]; + int status; + char buffer[255]; - sprintf(buffer, "%d", content_size); - httpc_set_header(conn, HEADER_CONTENT_LENGTH, buffer); + sprintf(buffer, "%d", content_size); + httpc_set_header(conn, HEADER_CONTENT_LENGTH, buffer); - status = httpc_talk_to_server(HTTP_REQUEST_POST, conn, urlstr); - if (status != HSOCKET_OK) - return status; + status = httpc_talk_to_server(HTTP_REQUEST_POST, conn, urlstr); + if (status != HSOCKET_OK) + return status; - status = hsocket_nsend(conn->sock, content, content_size); - if (status != HSOCKET_OK) - return status; + status = hsocket_nsend(conn->sock, content, content_size); + if (status != HSOCKET_OK) + return status; - status = httpc_receive_response(conn, start_cb, cb, userdata); - return status; + status = httpc_receive_response(conn, start_cb, cb, userdata); + return status; } - + /*====================================================== - The following functions are used internally to wrap - the httpc_x_cb (x = get|post) functions. - ======================================================*/ +The following functions are used internally to wrap +the httpc_x_cb (x = get|post) functions. +======================================================*/ static void httpc_custom_res_callback(int counter, httpc_conn_t* conn, - void *userdata, int size, char *buffer) + void *userdata, int size, char *buffer) { - hresponse_t *res; + hresponse_t *res; - /* get response object */ - res = (hresponse_t*)userdata; + /* get response object */ + res = (hresponse_t*)userdata; - /* allocate buffersize */ + /* allocate buffersize */ - res->bodysize += size; - res->body = (unsigned char*)realloc(res->body, res->bodysize + 1); + res->bodysize += size; + res->body = (char *)realloc(res->body, res->bodysize + 1); - memcpy(&(res->body[res->bodysize-size]), buffer, size); - res->body[res->bodysize]='\0'; + memcpy(&(res->body[res->bodysize-size]), buffer, size); + res->body[res->bodysize]='\0'; } static void httpc_custom_start_callback(httpc_conn_t *conn, void *userdata, - hpair_t *header, const char *spec, - int errcode, const char *desc) + hpair_t *header, const char *spec, + int errcode, const char *desc) { - hresponse_t *res; + hresponse_t *res; - /* get response object */ - res = (hresponse_t*)userdata; + /* get response object */ + res = (hresponse_t*)userdata; - /* set spec */ - if (spec != NULL) { - strcpy(res->spec, spec); - } + /* set spec */ + if (spec != NULL) { + strcpy(res->spec, spec); + } - /* set errcode */ - res->errcode = errcode; + /* set errcode */ + res->errcode = errcode; - /* set desc */ - if (desc != NULL) { - res->desc = (char*)malloc(strlen(desc)+1); - strcpy(res->desc, desc); - } + /* set desc */ + if (desc != NULL) { + res->desc = (char*)malloc(strlen(desc)+1); + strcpy(res->desc, desc); + } - /* set header */ - if (header == NULL) { - log_warn1("header is NULL!"); - } + /* set header */ + if (header == NULL) { + log_warn1("header is NULL!"); + } - res->header = hpairnode_copy_deep(header); + res->header = hpairnode_copy_deep(header); } - + /*-------------------------------------------------- - FUNCTION: httpc_get +FUNCTION: httpc_get ----------------------------------------------------*/ hresponse_t *httpc_get(httpc_conn_t *conn, const char *url) { - int status; - hresponse_t *res; + int status; + hresponse_t *res; - res = hresponse_new(); - status = httpc_get_cb(conn, url, httpc_custom_start_callback, - httpc_custom_res_callback, res); + res = hresponse_new(); + status = httpc_get_cb(conn, url, httpc_custom_start_callback, + httpc_custom_res_callback, res); - if (status != 0) { - hresponse_free(res); - return NULL; - } + if (status != 0) { + hresponse_free(res); + return NULL; + } - return res; + return res; } /*-------------------------------------------------- - FUNCTION: httpc_post +FUNCTION: httpc_post ----------------------------------------------------*/ hresponse_t *httpc_post(httpc_conn_t *conn, const char *url, - int content_size, const char *content) + int content_size, const char *content) { - int status; - hresponse_t *res; + int status; + hresponse_t *res; - res = hresponse_new(); - status = httpc_post_cb(conn, url, httpc_custom_start_callback, - httpc_custom_res_callback, content_size, - content, res); + res = hresponse_new(); + status = httpc_post_cb(conn, url, httpc_custom_start_callback, + httpc_custom_res_callback, content_size, + (char *)content, res); - if (status != 0) { - hresponse_free(res); - return NULL; - } + if (status != 0) { + hresponse_free(res); + return NULL; + } - return res; + return res; } /* - POST Module - */ +POST Module +*/ /*-------------------------------------------------- - FUNCTION: httpc_post_open +FUNCTION: httpc_post_open ----------------------------------------------------*/ int httpc_post_open(httpc_conn_t *conn, const char *urlstr) { - int status; + int status; - httpc_set_header(conn, HEADER_TRANSFER_ENCODING, "chunked"); + httpc_set_header(conn, HEADER_TRANSFER_ENCODING, "chunked"); - status = httpc_talk_to_server(HTTP_REQUEST_POST, conn, urlstr); - return status; + status = httpc_talk_to_server(HTTP_REQUEST_POST, conn, urlstr); + return status; } /*-------------------------------------------------- - FUNCTION: httpc_post_send +FUNCTION: httpc_post_send ----------------------------------------------------*/ int httpc_post_send(httpc_conn_t *conn, - const char* buffer, - int bufsize) + const char* buffer, + int bufsize) { - char hexsize[100]; /* chunk size in hex */ - int status; - - sprintf(hexsize, "%x\r\n", bufsize); - - status = hsocket_send(conn->sock, hexsize); - if (status != HSOCKET_OK) - return status; - - status = hsocket_nsend(conn->sock, buffer, bufsize); - if (status != HSOCKET_OK) - return status; - - status = hsocket_send(conn->sock, "\r\n"); - - return status; -} + char hexsize[100]; /* chunk size in hex */ + int status; + sprintf(hexsize, "%x\r\n", bufsize); -/*-------------------------------------------------- - FUNCTION: httpc_post_finish -----------------------------------------------------*/ -hresponse_t *httpc_post_finish(httpc_conn_t *conn) -{ - int status; - hresponse_t *res; + status = hsocket_send(conn->sock, hexsize); + if (status != HSOCKET_OK) + return status; - res = hresponse_new(); - status = httpc_post_finish_cb(conn, httpc_custom_start_callback, - httpc_custom_res_callback, res); + status = hsocket_nsend(conn->sock, buffer, bufsize); + if (status != HSOCKET_OK) + return status; - if (status != 0) { - hresponse_free(res); - return NULL; - } + status = hsocket_send(conn->sock, "\r\n"); - return res; + return status; } - /*-------------------------------------------------- - FUNCTION: httpc_post_finish_cb +FUNCTION: httpc_post_finish_cb ----------------------------------------------------*/ int httpc_post_finish_cb(httpc_conn_t *conn, - httpc_response_start_callback start_cb, - httpc_response_callback cb, - void *userdata) + httpc_response_start_callback start_cb, + httpc_response_callback cb, + void *userdata) { - int status; - - status = hsocket_send(conn->sock, "0\r\n\r\n"); - if (status != HSOCKET_OK) return status; - - status = httpc_receive_response(conn, start_cb, cb, userdata); - return status; -} - - - - - - - - - - - - - - - - + int status; + status = hsocket_send(conn->sock, "0\r\n\r\n"); + if (status != HSOCKET_OK) return status; + status = httpc_receive_response(conn, start_cb, cb, userdata); + return status; +} +/*-------------------------------------------------- +FUNCTION: httpc_post_finish +----------------------------------------------------*/ +hresponse_t *httpc_post_finish(httpc_conn_t *conn) +{ + int status; + hresponse_t *res; + res = hresponse_new(); + status = httpc_post_finish_cb(conn, httpc_custom_start_callback, + httpc_custom_res_callback, res); + if (status != 0) { + hresponse_free(res); + return NULL; + } + return res; +} diff --git a/nanohttp/nanohttp-common.c b/nanohttp/nanohttp-common.c index 1d00d42..6fac5ba 100644 --- a/nanohttp/nanohttp-common.c +++ b/nanohttp/nanohttp-common.c @@ -1,26 +1,26 @@ /****************************************************************** - * $Id: nanohttp-common.c,v 1.8 2004/02/03 08:59:23 snowdrop Exp $ - * - * CSOAP Project: A http client/server library in C - * Copyright (C) 2003 Ferhat Ayaz - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Email: ayaz@jprogrammer.net - ******************************************************************/ +* $Id: nanohttp-common.c,v 1.9 2004/08/26 17:07:47 rans Exp $ +* +* CSOAP Project: A http client/server library in C +* Copyright (C) 2003 Ferhat Ayaz +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +* +* Email: ayaz@jprogrammer.net +******************************************************************/ #include <nanohttp/nanohttp-common.h> @@ -28,663 +28,683 @@ #include <stdlib.h> #include <stdarg.h> +#ifdef WIN32 +#include <string.h> +static char *strtok_r (char *s, const char *delim, char **save_ptr) +{ + char *token; + + if (s == NULL) + s = *save_ptr; + + /* Scan leading delimiters. */ + s += strspn (s, delim); + if (*s == '\0') + return NULL; + + /* Find the end of the token. */ + token = s; + s = strpbrk (token, delim); + if (s == NULL) + /* This token finishes the string. */ + *save_ptr = strchr (token, '\0'); + else + { + /* Terminate the token and make *SAVE_PTR point past it. */ + *s = '\0'; + *save_ptr = s + 1; + } + return token; +} +#endif static log_level_t loglevel = HLOG_DEBUG; log_level_t log_set_level(log_level_t level) { - log_level_t old = loglevel; - loglevel = level; - return old; + log_level_t old = loglevel; + loglevel = level; + return old; } log_level_t log_get_level() { - return loglevel; + return loglevel; } - static void log_write(log_level_t level, const char *prefix, - const char* func, const char *format, va_list ap) + const char* func, const char *format, va_list ap) { - char buffer[1054]; - char buffer2[1054]; - - if (level < loglevel) return; - - sprintf(buffer, "*%s*: [%s] %s\n", prefix, func, format); - vsprintf(buffer2, buffer, ap); - printf(buffer2); - fflush(stdout); + char buffer[1054]; + char buffer2[1054]; + + if (level < loglevel) return; + + sprintf(buffer, "*%s*: [%s] %s\n", prefix, func, format); + vsprintf(buffer2, buffer, ap); + printf(buffer2); + fflush(stdout); } void log_verbose(const char* FUNC, const char *format, ...) { - va_list ap; - - va_start(ap, format); - log_write(HLOG_VERBOSE, "VERBOSE", FUNC, format, ap); - va_end(ap); + va_list ap; + + va_start(ap, format); + log_write(HLOG_VERBOSE, "VERBOSE", FUNC, format, ap); + va_end(ap); } void log_debug(const char* FUNC, const char *format, ...) { - va_list ap; - - va_start(ap, format); - log_write(HLOG_DEBUG, "DEBUG", FUNC, format, ap); - va_end(ap); + va_list ap; + + va_start(ap, format); + log_write(HLOG_DEBUG, "DEBUG", FUNC, format, ap); + va_end(ap); } void log_info(const char* FUNC, const char *format, ...) { - va_list ap; - - va_start(ap, format); - log_write(HLOG_INFO, "INFO", FUNC, format, ap); - va_end(ap); + va_list ap; + + va_start(ap, format); + log_write(HLOG_INFO, "INFO", FUNC, format, ap); + va_end(ap); } void log_warn(const char* FUNC, const char *format, ...) { - va_list ap; - - va_start(ap, format); - log_write(HLOG_WARN, "WARN", FUNC, format, ap); - va_end(ap); + va_list ap; + + va_start(ap, format); + log_write(HLOG_WARN, "WARN", FUNC, format, ap); + va_end(ap); } void log_error(const char* FUNC, const char *format, ...) { - va_list ap; - - va_start(ap, format); - log_write(HLOG_ERROR, "ERROR", FUNC, format, ap); - va_end(ap); + va_list ap; + + va_start(ap, format); + log_write(HLOG_ERROR, "ERROR", FUNC, format, ap); + va_end(ap); } /* ----------------------------------------- - FUNCTION: strcmpigcase - ------------------------------------------ */ +FUNCTION: strcmpigcase +------------------------------------------ */ int strcmpigcase(const char *s1, const char *s2) { - int l1, l2, i; + int l1, l2, i; + + if (s1 == NULL && s2 == NULL) return 1; + if (s1 == NULL || s2 == NULL) return 0; - if (s1 == NULL && s2 == NULL) return 1; - if (s1 == NULL || s2 == NULL) return 0; + l1 = strlen(s1); + l2 = strlen(s2); - l1 = strlen(s1); - l2 = strlen(s2); + if (l1 != l2) return 0; - if (l1 != l2) return 0; - - for (i=0;i<l1;i++) - if (toupper(s1[i]) != toupper(s2[i])) - return 0; + for (i=0;i<l1;i++) + if (toupper(s1[i]) != toupper(s2[i])) + return 0; - return 1; + return 1; } hpair_t *hpairnode_new(const char* key, const char* value, hpair_t *next) { - hpair_t *pair; + hpair_t *pair; - log_verbose3("new pair ('%s','%s')", SAVE_STR(key), SAVE_STR(value)); - pair = (hpair_t*)malloc(sizeof(hpair_t)); + log_verbose3("new pair ('%s','%s')", SAVE_STR(key), SAVE_STR(value)); + pair = (hpair_t*)malloc(sizeof(hpair_t)); - if (key != NULL) { - pair->key = (char*)malloc(strlen(key)+1); - strcpy(pair->key, key); - } else { - pair->key = NULL; - } + if (key != NULL) { + pair->key = (char*)malloc(strlen(key)+1); + strcpy(pair->key, key); + } else { + pair->key = NULL; + } - if (value != NULL) { - pair->value = (char*)malloc(strlen(value)+1); - strcpy(pair->value, value); - } else { - pair->value = NULL; - } + if (value != NULL) { + pair->value = (char*)malloc(strlen(value)+1); + strcpy(pair->value, value); + } else { + pair->value = NULL; + } - pair->next = next; + pair->next = next; - return pair; + return pair; } hpair_t *hpairnode_parse(const char *str, const char *delim, hpair_t *next) { - hpair_t *pair; - char *key, *value; - int c; - - pair = (hpair_t*)malloc(sizeof(hpair_t)); - pair->key = ""; - pair->value = ""; - pair->next = next; - - key = strtok_r(str, delim, &value); - - if (key != NULL) { - pair->key = (char*)malloc(strlen(key)+1); - strcpy(pair->key, key); - } - - if (value != NULL) { - for (c=0;value[c]==' ';c++); /* skip white space */ - pair->value = (char*)malloc(strlen(&value[c])+1); - strcpy(pair->value, &value[c]); - } - - return pair; + hpair_t *pair; + char *key, *value; + int c; + + pair = (hpair_t*)malloc(sizeof(hpair_t)); + pair->key = ""; + pair->value = ""; + pair->next = next; + + key = strtok_r((char *)str, delim, &value); + + if (key != NULL) { + pair->key = (char*)malloc(strlen(key)+1); + strcpy(pair->key, key); + } + + if (value != NULL) { + for (c=0;value[c]==' ';c++); /* skip white space */ + pair->value = (char*)malloc(strlen(&value[c])+1); + strcpy(pair->value, &value[c]); + } + + return pair; } hpair_t* hpairnode_copy(const hpair_t *src) { - hpair_t *pair; + hpair_t *pair; - if (src == NULL) return NULL; + if (src == NULL) return NULL; - pair = hpairnode_new(src->key, src->value, NULL); - return pair; + pair = hpairnode_new(src->key, src->value, NULL); + return pair; } hpair_t* hpairnode_copy_deep(const hpair_t *src) { - hpair_t *pair, *result, *next; + hpair_t *pair, *result, *next; + + if (src == NULL) return NULL; - if (src == NULL) return NULL; + result = hpairnode_copy(src); - result = hpairnode_copy(src); + next = src->next; + pair = result; - next = src->next; - pair = result; + while (next != NULL) { + pair->next = hpairnode_copy(next); + pair = pair->next; + next = next->next; + } - while (next != NULL) { - pair->next = hpairnode_copy(next); - pair = pair->next; - next = next->next; - } - - return result; + return result; } void hpairnode_dump(hpair_t *pair) { - if (pair == NULL) { - log_verbose1("(NULL)[]"); - return; - } - - log_verbose5("(%p)['%s','%s','%p']", pair, - SAVE_STR(pair->key), SAVE_STR(pair->value), - pair->next); + if (pair == NULL) { + log_verbose1("(NULL)[]"); + return; + } + + log_verbose5("(%p)['%s','%s','%p']", pair, + SAVE_STR(pair->key), SAVE_STR(pair->value), + pair->next); } void hpairnode_dump_deep(hpair_t *pair) { - hpair_t *p; - p = pair; + hpair_t *p; + p = pair; - log_verbose1("-- BEGIN dump hpairnode_t --"); + log_verbose1("-- BEGIN dump hpairnode_t --"); - while (p != NULL) { - hpairnode_dump(p); - p = p->next; - } + while (p != NULL) { + hpairnode_dump(p); + p = p->next; + } - log_verbose1("-- END dump hpairnode_t --\n"); + log_verbose1("-- END dump hpairnode_t --\n"); } void hpairnode_free(hpair_t *pair) { - if (pair == NULL) return; - - free(pair->key); - free(pair->value); - - free(pair); + if (pair == NULL) return; + + free(pair->key); + free(pair->value); + + free(pair); } void hpairnode_free_deep(hpair_t *pair) { - hpair_t *tmp; + hpair_t *tmp; - while (pair != NULL) { - tmp = pair->next; - hpairnode_free(pair); - pair=tmp; - } + while (pair != NULL) { + tmp = pair->next; + hpairnode_free(pair); + pair=tmp; + } } char *hpairnode_get_ignore_case(hpair_t *pair, const char* key) { - if (key == NULL) { - log_error1("key is NULL"); - return NULL; - } - - while (pair != NULL) { - if (pair->key != NULL) { - if (strcmpigcase(pair->key, key)) { - return pair->value; - } - } - pair = pair->next; - } - - return NULL; + if (key == NULL) { + log_error1("key is NULL"); + return NULL; + } + + while (pair != NULL) { + if (pair->key != NULL) { + if (strcmpigcase(pair->key, key)) { + return pair->value; + } + } + pair = pair->next; + } + + return NULL; } char *hpairnode_get(hpair_t *pair, const char* key) { - if (key == NULL) { - log_error1("key is NULL"); - return NULL; - } - - while (pair != NULL) { - if (pair->key != NULL) { - if (!strcmp(pair->key, key)) { - return pair->value; - } - } - pair = pair->next; - } - - return NULL; + if (key == NULL) { + log_error1("key is NULL"); + return NULL; + } + + while (pair != NULL) { + if (pair->key != NULL) { + if (!strcmp(pair->key, key)) { + return pair->value; + } + } + pair = pair->next; + } + + return NULL; } static void hurl_dump(const hurl_t *url) { - if (url == NULL) { - log_error1("url is NULL!"); - return ; - } + if (url == NULL) { + log_error1("url is NULL!"); + return ; + } - log_verbose2("PROTOCOL : %s", SAVE_STR(url->protocol)); - log_verbose2(" HOST : %s", SAVE_STR(url->host)); - log_verbose2(" PORT : %d", url->port); - log_verbose2(" CONTEXT : %s", SAVE_STR(url->context)); + log_verbose2("PROTOCOL : %s", SAVE_STR(url->protocol)); + log_verbose2(" HOST : %s", SAVE_STR(url->host)); + log_verbose2(" PORT : %d", url->port); + log_verbose2(" CONTEXT : %s", SAVE_STR(url->context)); } hurl_t* hurl_new(const char* urlstr) { - int iprotocol; - int ihost; - int iport; - int len; - int size; - hurl_t *url; - char tmp[8]; - - iprotocol = 0; - len = strlen(urlstr); - - /* find protocol */ - while (urlstr[iprotocol] != ':' && urlstr[iprotocol] != '\0') - { - iprotocol++; - } - - if (iprotocol == 0) { - log_error1("no protocol"); - return NULL; - } - - if (iprotocol + 3 >= len) { - log_error1("no host"); - return NULL; - } - - if ( urlstr[iprotocol] != ':' - && urlstr[iprotocol+1] != '/' - && urlstr[iprotocol+2] != '/') - { - log_error1("no protocol"); - return NULL; - } - - /* find host */ - ihost = iprotocol + 3; - while (urlstr[ihost] != ':' - && urlstr[ihost] != '/' - && urlstr[ihost] != '\0') - { - ihost++; - } - - if (ihost == iprotocol + 1) { - log_error1("no host"); - return NULL; - } - - /* find port */ - iport = ihost; - if (ihost + 1 < len) { - if (urlstr[ihost] == ':') { - while (urlstr[iport] != '/' && urlstr[iport] != '\0') { - iport++; - } - } - } - - url = (hurl_t*)malloc(sizeof(hurl_t)); - - url->protocol = (char*)malloc(sizeof(char)*iprotocol+1); - strncpy(url->protocol, urlstr, iprotocol); - url->protocol[iprotocol] = '\0'; - - size = ihost - iprotocol - 3; - url->host = (char*)malloc(sizeof(char)*size + 1); - strncpy(url->host, &urlstr[iprotocol+3], size); - url->host[size] = '\0'; - - if (iport > ihost) - { - size = iport - ihost; - strncpy(tmp, &urlstr[ihost+1], size); - url->port = atoi(tmp); - } else { - url->port = 80; - } - - len = strlen(urlstr); - if (len > iport ) - { - size = len - iport; - url->context = (char*)malloc(sizeof(char)*size+1); - strncpy(url->context, &urlstr[iport], size); - url->context[size]='\0'; - } else { - url->context = NULL; - } - - hurl_dump(url); - - return url; + int iprotocol; + int ihost; + int iport; + int len; + int size; + hurl_t *url; + char tmp[8]; + + iprotocol = 0; + len = strlen(urlstr); + + /* find protocol */ + while (urlstr[iprotocol] != ':' && urlstr[iprotocol] != '\0') + { + iprotocol++; + } + + if (iprotocol == 0) { + log_error1("no protocol"); + return NULL; + } + + if (iprotocol + 3 >= len) { + log_error1("no host"); + return NULL; + } + + if ( urlstr[iprotocol] != ':' + && urlstr[iprotocol+1] != '/' + && urlstr[iprotocol+2] != '/') + { + log_error1("no protocol"); + return NULL; + } + + /* find host */ + ihost = iprotocol + 3; + while (urlstr[ihost] != ':' + && urlstr[ihost] != '/' + && urlstr[ihost] != '\0') + { + ihost++; + } + + if (ihost == iprotocol + 1) { + log_error1("no host"); + return NULL; + } + + /* find port */ + iport = ihost; + if (ihost + 1 < len) { + if (urlstr[ihost] == ':') { + while (urlstr[iport] != '/' && urlstr[iport] != '\0') { + iport++; + } + } + } + + url = (hurl_t*)malloc(sizeof(hurl_t)); + + url->protocol = (char*)malloc(sizeof(char)*iprotocol+1); + strncpy(url->protocol, urlstr, iprotocol); + url->protocol[iprotocol] = '\0'; + + size = ihost - iprotocol - 3; + url->host = (char*)malloc(sizeof(char)*size + 1); + strncpy(url->host, &urlstr[iprotocol+3], size); + url->host[size] = '\0'; + + if (iport > ihost) + { + size = iport - ihost; + strncpy(tmp, &urlstr[ihost+1], size); + url->port = atoi(tmp); + } else { + url->port = 80; + } + + len = strlen(urlstr); + if (len > iport ) + { + size = len - iport; + url->context = (char*)malloc(sizeof(char)*size+1); + strncpy(url->context, &urlstr[iport], size); + url->context[size]='\0'; + } else { + url->context = NULL; + } + + hurl_dump(url); + + return url; } void hurl_free(hurl_t *url) { - if (url == NULL) return; + if (url == NULL) return; - free(url->protocol); - free(url->host); - free(url->context); + free(url->protocol); + free(url->host); + free(url->context); - free(url); + free(url); } /* request stuff */ /* ----------------------------------------------------- - FUNCTION: hrequest_new_from_buffer +FUNCTION: hrequest_new_from_buffer ----------------------------------------------------- */ hrequest_t *hrequest_new_from_buffer(char *data) { - hrequest_t *req; - hpair_t *hpair = NULL, *qpair = NULL, *tmppair = NULL; - - char *tmp; - char *tmp2; - char *saveptr; - char *saveptr2; - char *saveptr3; - char *result; - char *key; - char *value; - char *opt_key; - char *opt_value; - int firstline = 1; - - req = (hrequest_t*)malloc(sizeof(hrequest_t)); - - req->method = NULL; - req->spec = NULL; - req->path = NULL; - req->query = NULL; - req->header = NULL; - - tmp = data; - - for (;;) { - result = (char*)strtok_r(tmp, "\n", &saveptr); - tmp=saveptr; - - if (result == NULL) - break; - - if (firstline) { - firstline=0; - tmp2 = result; - - /* parse [GET|POST] [PATH] [SPEC] */ - key = (char*)strtok_r(tmp2," ", &saveptr2); - - /* save method (get or post) */ - tmp2 = saveptr2; - if (key != NULL) { - req->method = (char*)malloc(strlen(key)+1); - strcpy(req->method, key); - } - - /* below is key the path and tmp2 the spec */ - key = (char*)strtok_r(tmp2," ", &saveptr2); - - /* save spec */ - tmp2 = saveptr2; - if (tmp2 != NULL) { - req->spec = (char*)malloc(strlen(tmp2)+1); - strcpy(req->spec, tmp2); - } - - /* parse and save path+query - parse: /path/of/target?key1=value1&key2=value2... - */ - - if (key != NULL) { - tmp2 = key; - key = (char*)strtok_r(tmp2,"?", &saveptr2); - tmp2 = saveptr2; - - /* save path */ - req->path = (char*)malloc(strlen(key)+1); - strcpy(req->path, key); - - /* parse options */ - for (;;) { - key = (char*)strtok_r(tmp2,"&",&saveptr2); - tmp2 = saveptr2; - - if (key == NULL) - break; - - opt_key = (char*)strtok_r(key,"=", &saveptr3); - opt_value = saveptr3; - - if (opt_value == NULL) - opt_value = ""; - - /* create option pair */ - if (opt_key != NULL) { - tmppair = (hpair_t*)malloc(sizeof(hpair_t)); - - if (req->query == NULL) { - req->query = qpair = tmppair; - } else { - qpair->next = tmppair; - qpair = tmppair; - } - - /* fill hpairnode_t struct */ - qpair->next = NULL; - qpair->key = (char*)malloc(strlen(opt_key)+1); - qpair->value = (char*)malloc(strlen(opt_value)+1); - - strcpy(qpair->key, opt_key); - strcpy(qpair->value, opt_value); - - } + hrequest_t *req; + hpair_t *hpair = NULL, *qpair = NULL, *tmppair = NULL; + + char *tmp; + char *tmp2; + char *saveptr; + char *saveptr2; + char *saveptr3; + char *result; + char *key; + char *value; + char *opt_key; + char *opt_value; + int firstline = 1; + + req = (hrequest_t*)malloc(sizeof(hrequest_t)); + + req->method = NULL; + req->spec = NULL; + req->path = NULL; + req->query = NULL; + req->header = NULL; + + tmp = data; + + for (;;) { + result = (char*)strtok_r(tmp, "\n", &saveptr); + tmp=saveptr; + + if (result == NULL) + break; + + if (firstline) { + firstline=0; + tmp2 = result; + + /* parse [GET|POST] [PATH] [SPEC] */ + key = (char*)strtok_r(tmp2," ", &saveptr2); + + /* save method (get or post) */ + tmp2 = saveptr2; + if (key != NULL) { + req->method = (char*)malloc(strlen(key)+1); + strcpy(req->method, key); + } + + /* below is key the path and tmp2 the spec */ + key = (char*)strtok_r(tmp2," ", &saveptr2); + + /* save spec */ + tmp2 = saveptr2; + if (tmp2 != NULL) { + req->spec = (char*)malloc(strlen(tmp2)+1); + strcpy(req->spec, tmp2); + } + + /* parse and save path+query + parse: /path/of/target?key1=value1&key2=value2... + */ + + if (key != NULL) { + tmp2 = key; + key = (char*)strtok_r(tmp2,"?", &saveptr2); + tmp2 = saveptr2; + + /* save path */ + req->path = (char*)malloc(strlen(key)+1); + strcpy(req->path, key); + + /* parse options */ + for (;;) { + key = (char*)strtok_r(tmp2,"&",&saveptr2); + tmp2 = saveptr2; + + if (key == NULL) + break; + + opt_key = (char*)strtok_r(key,"=", &saveptr3); + opt_value = saveptr3; + + if (opt_value == NULL) + opt_value = ""; + + /* create option pair */ + if (opt_key != NULL) { + tmppair = (hpair_t*)malloc(sizeof(hpair_t)); + + if (req->query == NULL) { + req->query = qpair = tmppair; + } else { + qpair->next = tmppair; + qpair = tmppair; + } + + /* fill hpairnode_t struct */ + qpair->next = NULL; + qpair->key = (char*)malloc(strlen(opt_key)+1); + qpair->value = (char*)malloc(strlen(opt_value)+1); + + strcpy(qpair->key, opt_key); + strcpy(qpair->value, opt_value); + + } + } + } + + } else { + + /* parse "key: value" */ + tmp2 = result; + key = (char*)strtok_r(tmp2, ": ", &saveptr2); + value = saveptr2; + + /* create pair */ + tmppair = (hpair_t*)malloc(sizeof(hpair_t)); + + if (req->header == NULL) { + req->header = hpair = tmppair; + } else { + hpair->next = tmppair; + hpair = tmppair; + } + + /* fill pairnode_t struct */ + hpair->next = NULL; + hpair->key = (char*)malloc(strlen(key)+1); + hpair->value = (char*)malloc(strlen(value)+1); + + strcpy(hpair->key, key); + strcpy(hpair->value, value); + } } - } - - } else { - - /* parse "key: value" */ - tmp2 = result; - key = (char*)strtok_r(tmp2, ": ", &saveptr2); - value = saveptr2; - - /* create pair */ - tmppair = (hpair_t*)malloc(sizeof(hpair_t)); - - if (req->header == NULL) { - req->header = hpair = tmppair; - } else { - hpair->next = tmppair; - hpair = tmppair; - } - - /* fill pairnode_t struct */ - hpair->next = NULL; - hpair->key = (char*)malloc(strlen(key)+1); - hpair->value = (char*)malloc(strlen(value)+1); - - strcpy(hpair->key, key); - strcpy(hpair->value, value); - } - } - - return req; + + return req; } void hrequest_free(hrequest_t *req) { - if (req == NULL) return; + if (req == NULL) return; - free(req->method); - free(req->path); - free(req->spec); + free(req->method); + free(req->path); + free(req->spec); + + hpairnode_free_deep(req->header); + hpairnode_free_deep(req->query); - hpairnode_free_deep(req->header); - hpairnode_free_deep(req->query); - } /* response stuff */ /* ------------------------------------------- - FUNCTION: hresponse_new - ---------------------------------------------*/ +FUNCTION: hresponse_new +---------------------------------------------*/ hresponse_t *hresponse_new() { - hresponse_t *res; - - /* create response object */ - res = (hresponse_t*)malloc(sizeof(hresponse_t)); - res->spec[0] = '\0'; - res->errcode = -1; - res->desc = NULL; - res->header = NULL; - res->body = NULL; - res->bodysize = 0; - - return res; + hresponse_t *res; + + /* create response object */ + res = (hresponse_t*)malloc(sizeof(hresponse_t)); + res->spec[0] = '\0'; + res->errcode = -1; + res->desc = NULL; + res->header = NULL; + res->body = NULL; + res->bodysize = 0; + + return res; } /* ------------------------------------------- - FUNCTION: hresponse_new_from_buffer - ---------------------------------------------*/ +FUNCTION: hresponse_new_from_buffer +---------------------------------------------*/ hresponse_t *hresponse_new_from_buffer(const char* buffer) { - hresponse_t *res; - char *s1, *s2, *str; - hpair_t *pair; - - /* create response object */ - res = hresponse_new(); - - /* *** parse spec *** */ - /* [HTTP/1.1 | 1.2] [CODE] [DESC] */ - - /* stage 1: HTTP spec */ - str = (char*)strtok_r(buffer, " ", &s2); - s1 = s2; - if (str == NULL) { log_error1("Parse error"); return NULL; } - - strncpy(res->spec, str, 10); - - /* stage 2: http code */ - str = (char*)strtok_r(s1, " ", &s2); - s1 = s2; - if (str == NULL) { log_error1("Parse error"); return NULL; } - - res->errcode = atoi(str); - - /* stage 3: description text */ - str = (char*)strtok_r(s1, "\r\n", &s2); - s1 = s2; - if (str == NULL) { log_error1("Parse error"); return NULL; } - - res->desc = (char*)malloc(strlen(str)+1); - strcpy(res->desc, str); - res->desc[strlen(str)] = '\0'; - - /* *** parse header *** */ - /* [key]: [value] */ - for (;;) { - str = strtok_r(s1, "\n", &s2); - s1 = s2; - - /* check if header ends without body */ - if (str == NULL) { - return res; - } - - /* check also for end of header */ - if (!strcmp(str, "\r")) { - break; - } - - str[strlen(str)-1] = '\0'; - res->header = hpairnode_parse(str, ":", res->header); - } - - /* *** Save body *** */ - res->body = s1; - - /* return response object */ - return res; -} + hresponse_t *res; + char *s1, *s2, *str; + hpair_t *pair; + /* create response object */ + res = hresponse_new(); -void hresponse_free(hresponse_t *res) -{ - /* not implemented yet!*/ -} + /* *** parse spec *** */ + /* [HTTP/1.1 | 1.2] [CODE] [DESC] */ + + /* stage 1: HTTP spec */ + str = (char*)strtok_r((char *)buffer, " ", &s2); + s1 = s2; + if (str == NULL) { log_error1("Parse error"); return NULL; } + + strncpy(res->spec, str, 10); + /* stage 2: http code */ + str = (char*)strtok_r(s1, " ", &s2); + s1 = s2; + if (str == NULL) { log_error1("Parse error"); return NULL; } + res->errcode = atoi(str); + /* stage 3: description text */ + str = (char*)strtok_r(s1, "\r\n", &s2); + s1 = s2; + if (str == NULL) { log_error1("Parse error"); return NULL; } + res->desc = (char*)malloc(strlen(str)+1); + strcpy(res->desc, str); + res->desc[strlen(str)] = '\0'; + /* *** parse header *** */ + /* [key]: [value] */ + for (;;) { + str = strtok_r(s1, "\n", &s2); + s1 = s2; + /* check if header ends without body */ + if (str == NULL) { + return res; + } + /* check also for end of header */ + if (!strcmp(str, "\r")) { + break; + } + str[strlen(str)-1] = '\0'; + res->header = hpairnode_parse(str, ":", res->header); + } + + /* *** Save body *** */ + res->body = s1; + + /* return response object */ + return res; +} + + +void hresponse_free(hresponse_t *res) +{ + /* not implemented yet!*/ +} diff --git a/nanohttp/nanohttp-common.h b/nanohttp/nanohttp-common.h index ebde99c..365fdf3 100644 --- a/nanohttp/nanohttp-common.h +++ b/nanohttp/nanohttp-common.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-common.h,v 1.6 2004/01/21 12:28:20 snowdrop Exp $ + * $Id: nanohttp-common.h,v 1.7 2004/08/26 17:07:47 rans Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -110,7 +110,7 @@ typedef struct hresponse int errcode; char *desc; hpair_t *header; - unsigned char *body; + char *body; long bodysize; }hresponse_t; diff --git a/nanohttp/nanohttp-server.c b/nanohttp/nanohttp-server.c index a752fda..ef7c503 100644 --- a/nanohttp/nanohttp-server.c +++ b/nanohttp/nanohttp-server.c @@ -1,28 +1,34 @@ /****************************************************************** - * $Id: nanohttp-server.c,v 1.7 2004/05/18 16:37:21 snowdrop Exp $ - * - * CSOAP Project: A http client/server library in C - * Copyright (C) 2003 Ferhat Ayaz - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Email: ayaz@jprogrammer.net - ******************************************************************/ +* $Id: nanohttp-server.c,v 1.8 2004/08/26 17:07:47 rans Exp $ +* +* CSOAP Project: A http client/server library in C +* Copyright (C) 2003 Ferhat Ayaz +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +* +* Email: ayaz@jprogrammer.net +******************************************************************/ #include <nanohttp/nanohttp-server.h> +#ifdef WIN32 +#include "wsockcompat.h" +#include <winsock2.h> +#define close(s) closesocket(s) +#endif + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -34,24 +40,25 @@ #include <string.h> #include <signal.h> +#ifndef WIN32 /* According to POSIX 1003.1-2001 */ #include <sys/select.h> - + /* According to earlier standards */ #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> - +#endif typedef struct tag_conndata { - hsocket_t sock; + hsocket_t sock; }conndata_t; /* ----------------------------------------------------- - nano httpd internally globals +nano httpd internally globals ----------------------------------------------------- */ static int _httpd_port = 10000; static hsocket_t _httpd_socket; @@ -61,347 +68,368 @@ static int _httpd_run = 1; static int _httpd_terminate_signal = SIGTERM; /* ----------------------------------------------------- - FUNCTION: httpd_init +FUNCTION: httpd_init ----------------------------------------------------- */ int httpd_init(int argc, char *argv[]) { - int i, status; - - /* write argument information */ - log_verbose1("Arguments:"); - for (i=0;i<argc;i++) - log_verbose3("argv[%i] = '%s'", i, SAVE_STR(argv[i])); - - /* initialize from arguments */ - for (i=0;i<argc;i++) { - if (!strcmp(argv[i], NHTTPD_ARG_PORT) && i < argc-1) { - _httpd_port = atoi(argv[i+1]); - } else if (!strcmp(argv[i], NHTTPD_ARG_TERMSIG) && i < argc-1) { - _httpd_terminate_signal = atoi(argv[i+1]); - } - } - - log_verbose2("socket bind to port '%d'", _httpd_port); - - /* init built-in services */ - /* - httpd_register("/httpd/list", service_list); - */ - - /* create socket */ - hsocket_init(&_httpd_socket); - status = hsocket_bind(&_httpd_socket, _httpd_port); - - return status; + int i, status; + + /* write argument information */ + log_verbose1("Arguments:"); + for (i=0;i<argc;i++) + log_verbose3("argv[%i] = '%s'", i, SAVE_STR(argv[i])); + + /* initialize from arguments */ + for (i=0;i<argc;i++) { + if (!strcmp(argv[i], NHTTPD_ARG_PORT) && i < argc-1) { + _httpd_port = atoi(argv[i+1]); + } else if (!strcmp(argv[i], NHTTPD_ARG_TERMSIG) && i < argc-1) { + _httpd_terminate_signal = atoi(argv[i+1]); + } + } + + log_verbose2("socket bind to port '%d'", _httpd_port); + + /* init built-in services */ + /* + httpd_register("/httpd/list", service_list); + */ + + /* create socket */ + hsocket_init(&_httpd_socket); + status = hsocket_bind(&_httpd_socket, _httpd_port); + + return status; } /* ----------------------------------------------------- - FUNCTION: httpd_register +FUNCTION: httpd_register ----------------------------------------------------- */ int httpd_register(const char* ctx, httpd_service func) { - hservice_t* service; - log_verbose3("register service:t(%p):%s", service, SAVE_STR(ctx)); - - service = (hservice_t*)malloc(sizeof(hservice_t)); - service->next = NULL; - service->func = func; - strcpy(service->ctx, ctx); - - if (_httpd_services_head == NULL) { - _httpd_services_head = _httpd_services_tail = service; - } else { - _httpd_services_tail->next = service; - _httpd_services_tail = service; - } - - return 1; + hservice_t* service; + log_verbose3("register service:t(%p):%s", service, SAVE_STR(ctx)); + + service = (hservice_t*)malloc(sizeof(hservice_t)); + service->next = NULL; + service->func = func; + strcpy(service->ctx, ctx); + + if (_httpd_services_head == NULL) { + _httpd_services_head = _httpd_services_tail = service; + } else { + _httpd_services_tail->next = service; + _httpd_services_tail = service; + } + + return 1; } /* ----------------------------------------------------- - FUNCTION: httpd_services +FUNCTION: httpd_services ----------------------------------------------------- */ hservice_t *httpd_services() { - return _httpd_services_head; + return _httpd_services_head; } /* ----------------------------------------------------- - FUNCTION: httpd_find_service +FUNCTION: httpd_find_service ----------------------------------------------------- */ static hservice_t *httpd_find_service(const char* ctx) { - hservice_t *cur = _httpd_services_head; + hservice_t *cur = _httpd_services_head; - while (cur != NULL) { - if (!strcmp(cur->ctx, ctx)) { - return cur; - } - cur = cur->next; - } + while (cur != NULL) { + if (!strcmp(cur->ctx, ctx)) { + return cur; + } + cur = cur->next; + } - return NULL; + return NULL; } /* ----------------------------------------------------- - FUNCTION: httpd_response_set_content_type +FUNCTION: httpd_response_set_content_type ----------------------------------------------------- */ void httpd_response_set_content_type(httpd_conn_t *res, - const char* content_type) + const char* content_type) { - strncpy(res->content_type, content_type, 25); + strncpy(res->content_type, content_type, 25); } /* ----------------------------------------------------- - FUNCTION: httpd_response_send_header +FUNCTION: httpd_response_send_header ----------------------------------------------------- */ int httpd_send_header(httpd_conn_t *res, - int code, const char* text, - hpair_t *pair) + int code, const char* text, + hpair_t *pair) { - struct tm stm; - time_t nw; - char buffer[255]; - char header[1024]; - hpair_t *cur; - int status; - - /* set status code */ - sprintf(header, "HTTP/1.1 %d %s\r\n", code, text); - - /* set date */ - nw = time(NULL); - localtime_r(&nw, &stm); - strftime(buffer, 255, "Date: %a, %d %b %y %T GMT", &stm); - strcat(header, buffer); - strcat(header, "\r\n"); - - /* set content-type */ - /* - if (res->content_type[0] == '\0') { - strcat(header, "Content-Type: text/html\r\n"); - } else { - sprintf(buffer, "Content-Type: %s\r\n", res->content_type); - strcat(header, buffer); - } - */ - - /* set server name */ - strcat(header, "Server: Nano HTTPD library\r\n"); - - /* set connection status */ - strcat(header, "Connection: close\r\n"); - - /* add pairs */ - cur = pair; - while (cur != NULL) { - sprintf(buffer, "%s: %s\r\n", cur->key, cur->value); - strcat(header, buffer); - cur = cur->next; - } - - /* set end of header */ - strcat(header, "\r\n"); - - /* send header */ - status = hsocket_nsend(res->sock, header, strlen(header)); - - return status; + struct tm stm; + time_t nw; + char buffer[255]; + char header[1024]; + hpair_t *cur; + int status; + + /* set status code */ + sprintf(header, "HTTP/1.1 %d %s\r\n", code, text); + + /* set date */ + nw = time(NULL); + localtime_r(&nw, &stm); + strftime(buffer, 255, "Date: %a, %d %b %y %T GMT", &stm); + strcat(header, buffer); + strcat(header, "\r\n"); + + /* set content-type */ + /* + if (res->content_type[0] == '\0') { + strcat(header, "Content-Type: text/html\r\n"); + } else { + sprintf(buffer, "Content-Type: %s\r\n", res->content_type); + strcat(header, buffer); + } + */ + + /* set server name */ + strcat(header, "Server: Nano HTTPD library\r\n"); + + /* set connection status */ + strcat(header, "Connection: close\r\n"); + + /* add pairs */ + cur = pair; + while (cur != NULL) { + sprintf(buffer, "%s: %s\r\n", cur->key, cur->value); + strcat(header, buffer); + cur = cur->next; + } + + /* set end of header */ + strcat(header, "\r\n"); + + /* send header */ + status = hsocket_nsend(res->sock, header, strlen(header)); + + return status; } int httpd_send_internal_error(httpd_conn_t *conn, const char* errmsg) { - const char *template = - "<html><body><h3>Error!</h3><hr> Message: '%s' </body></html>\r\n"; + const char *template1 = + "<html><body><h3>Error!</h3><hr> Message: '%s' </body></html>\r\n"; - char buffer[4064]; - sprintf(buffer, template, errmsg); - httpd_send_header(conn, 500, "INTERNAL", NULL); - return send(conn->sock, buffer, strlen(buffer), 0); + char buffer[4064]; + sprintf(buffer, template1, errmsg); + httpd_send_header(conn, 500, "INTERNAL", NULL); + return send(conn->sock, buffer, strlen(buffer), 0); } /* ----------------------------------------------------- - FUNCTION: httpd_request_print +FUNCTION: httpd_request_print ----------------------------------------------------- */ static void httpd_request_print(hrequest_t *req) { - hpair_t *pair; - - log_verbose1("++++++ Request +++++++++"); - log_verbose2(" Method : '%s'", req->method); - log_verbose2(" Path : '%s'", req->path); - log_verbose2(" Spec : '%s'", req->spec); - log_verbose1(" Parsed query string :"); - - pair = req->query; - while (pair != NULL) { - log_verbose3(" %s = '%s'", pair->key, pair->value); - pair = pair->next; - } - log_verbose1("++++++++++++++++++++++++"); - + hpair_t *pair; + + log_verbose1("++++++ Request +++++++++"); + log_verbose2(" Method : '%s'", req->method); + log_verbose2(" Path : '%s'", req->path); + log_verbose2(" Spec : '%s'", req->spec); + log_verbose1(" Parsed query string :"); + + pair = req->query; + while (pair != NULL) { + log_verbose3(" %s = '%s'", pair->key, pair->value); + pair = pair->next; + } + log_verbose1("++++++++++++++++++++++++"); + } /* ----------------------------------------------------- - FUNCTION: httpd_session_main +FUNCTION: httpd_session_main ----------------------------------------------------- */ static void* httpd_session_main(void *data) { - conndata_t *conn = (conndata_t*)data; - const char *msg = "SESSION 1.0\n"; - int len = strlen(msg); - char ch[2]; - char buffer[256]; /* temp buffer for recv() */ - char header[4064]; /* received header */ - int total; /* result from recv() */ - int hindex; /* searching end of header */ - int headerreached =0; /* whether reach header "\n\n" */ - hrequest_t* req = NULL; /* only for test */ - httpd_conn_t *rconn; - hservice_t* service = NULL; - char *content_length_str; - long content_length = 0; - - header[0] = '\0'; - len = 0; - - - log_verbose1("starting httpd_session_main()"); - - while (len < 4064) { - /*printf("receiving ...\n");*/ - total = recv(conn->sock, ch, 1, 0); - if (total==0) break; - header[len] = ch[0]; - len++; - if (len > 3) { - if (!strncmp(&header[len-4], "\r\n\r\n", 4)) { - header[len] = '\0'; - break; - } - } - } - - /* log_verbose2("=== HEADER ===\n%s\n============\n", header);*/ - /* call the service */ - req = hrequest_new_from_buffer(header); - httpd_request_print(req); - - - rconn = (httpd_conn_t*)malloc(sizeof(httpd_conn_t)); - rconn->sock = conn->sock; - rconn->content_type[0] = '\0'; - - service = httpd_find_service(req->path); - if (service != NULL) { - log_verbose2("service '%s' found", req->path); - if (service->func != NULL) { - service->func(rconn, req); - } else { - sprintf(buffer, - "service '%s' not registered properly (func == NULL)", - req->path); - log_verbose1(buffer); - httpd_send_internal_error(rconn, buffer); - } - } else { - sprintf(buffer, "service '%s' not found", req->path); - log_verbose1(buffer); - httpd_send_internal_error(rconn, buffer); - } - - close(conn->sock); - - /* httpd_response_free(res);*/ - hrequest_free(req); - - pthread_exit(NULL); + conndata_t *conn = (conndata_t*)data; + const char *msg = "SESSION 1.0\n"; + int len = strlen(msg); + char ch[2]; + char buffer[256]; /* temp buffer for recv() */ + char header[4064]; /* received header */ + int total; /* result from recv() */ + int hindex; /* searching end of header */ + int headerreached =0; /* whether reach header "\n\n" */ + hrequest_t* req = NULL; /* only for test */ + httpd_conn_t *rconn; + hservice_t* service = NULL; + char *content_length_str; + long content_length = 0; + + header[0] = '\0'; + len = 0; + + + log_verbose1("starting httpd_session_main()"); + + while (len < 4064) { + /*printf("receiving ...\n");*/ + total = recv(conn->sock, ch, 1, 0); + if (total==0) break; + header[len] = ch[0]; + len++; + if (len > 3) { + if (!strncmp(&header[len-4], "\r\n\r\n", 4)) { + header[len] = '\0'; + break; + } + } + } + + /* log_verbose2("=== HEADER ===\n%s\n============\n", header);*/ + /* call the service */ + req = hrequest_new_from_buffer(header); + httpd_request_print(req); + + + rconn = (httpd_conn_t*)malloc(sizeof(httpd_conn_t)); + rconn->sock = conn->sock; + rconn->content_type[0] = '\0'; + + service = httpd_find_service(req->path); + if (service != NULL) { + log_verbose2("service '%s' found", req->path); + if (service->func != NULL) { + service->func(rconn, req); + } else { + sprintf(buffer, + "service '%s' not registered properly (func == NULL)", + req->path); + log_verbose1(buffer); + httpd_send_internal_error(rconn, buffer); + } + } else { + sprintf(buffer, "service '%s' not found", req->path); + log_verbose1(buffer); + httpd_send_internal_error(rconn, buffer); + } + + close(conn->sock); + + /* httpd_response_free(res);*/ + hrequest_free(req); + + pthread_exit(NULL); + return service; } /* ----------------------------------------------------- - FUNCTION: httpd_term +FUNCTION: httpd_term ----------------------------------------------------- */ void httpd_term(int sig) { - if (sig == _httpd_terminate_signal) - _httpd_run = 0; + if (sig == _httpd_terminate_signal) + _httpd_run = 0; } /* ----------------------------------------------------- - FUNCTION: httpd_run +FUNCTION: httpd_run ----------------------------------------------------- */ int httpd_run() { - conndata_t *conn; - pthread_t tid; - pthread_attr_t attr; - hsocket_t sockfd; - int err; - fd_set fds; - struct timeval timeout; - - pthread_attr_init(&attr); + conndata_t *conn; + pthread_t tid; + pthread_attr_t attr; + hsocket_t sockfd; + int err; + fd_set fds; + struct timeval timeout; + + pthread_attr_init(&attr); #ifdef PTHREAD_CREATE_DETACHED - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #endif - - log_verbose1("starting run routine"); - timeout.tv_sec = 1; - timeout.tv_usec = 0; - /* listen to port */ - err = hsocket_listen(_httpd_socket,15); - if (err != HSOCKET_OK) { - log_error2("httpd_run(): '%d'", err); - return err; - } + log_verbose1("starting run routine"); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + /* listen to port */ + err = hsocket_listen(_httpd_socket,15); + if (err != HSOCKET_OK) { + log_error2("httpd_run(): '%d'", err); + return err; + } - log_verbose2("registering termination signal handler (SIGNAL:%d)", _httpd_terminate_signal); - signal(_httpd_terminate_signal, httpd_term); + log_verbose2("registering termination signal handler (SIGNAL:%d)", _httpd_terminate_signal); + signal(_httpd_terminate_signal, httpd_term); + log_verbose2("listening to port '%d'", _httpd_port); - log_verbose2("listening to port '%d'", _httpd_port); - - fcntl(_httpd_socket, F_SETFL, O_NONBLOCK); +#ifndef WIN32 +#if HSOCKET_BLOCKMODE!=0 + fcntl(_httpd_socket, F_SETFL, O_NONBLOCK); +#endif +#else + unsigned long iMode=HSOCKET_BLOCKMODE; + if(ioctlsocket(_httpd_socket, FIONBIO, (u_long FAR*) &iMode) == INVALID_SOCKET) + { + log_error1("ioctlsocket error"); + return -1; + } +#endif - while (_httpd_run) { - - FD_ZERO(&fds); - FD_SET(_httpd_socket, &fds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; - { - timeout.tv_sec = 1; - timeout.tv_usec = 0; - select(1, &fds, NULL, NULL, &timeout); - } while (_httpd_run && (FD_ISSET(_httpd_socket, &fds))) + while (_httpd_run) { + + FD_ZERO(&fds); + FD_SET(_httpd_socket, &fds); + +#ifndef WIN32 + select(1, &fds, NULL, NULL, &timeout); +#else + if(select(1, &fds, NULL, NULL, &timeout)==SOCKET_ERROR) + { + err=WSAGetLastError(); + log_error1("select error"); + return -1; + } +#endif - if (!_httpd_run) - break; - - if (hsocket_accept(_httpd_socket, &sockfd) != HSOCKET_OK) { - continue; - } + while (_httpd_run && (FD_ISSET(_httpd_socket, &fds))) + if (!_httpd_run) + break; - conn = (conndata_t*)malloc(sizeof(conndata_t)); - conn->sock = sockfd; + if (hsocket_accept(_httpd_socket, &sockfd) != HSOCKET_OK) { + continue; + } - err = pthread_create(&tid, &attr, httpd_session_main, conn); - if (err) { - log_error2("Error creating thread: ('%d')", err); - } - } - return 0; + conn = (conndata_t*)malloc(sizeof(conndata_t)); + conn->sock = sockfd; + + err = pthread_create(&tid, &attr, httpd_session_main, conn); + if (err) { + log_error2("Error creating thread: ('%d')", err); + } + } + + return 0; } @@ -409,49 +437,49 @@ int httpd_run() char *httpd_get_postdata(httpd_conn_t *conn, hrequest_t *req, long *received, long max) { - char *content_length_str; - long content_length = 0; - long total = 0; - char *postdata = NULL; - - if (!strcmp(req->method, "POST")) { - - content_length_str = - hpairnode_get_ignore_case(req->header, HEADER_CONTENT_LENGTH); - - if (content_length_str != NULL) - content_length = atol(content_length_str); - - } else { - log_warn1("Not a POST method"); - return NULL; - } - - if (content_length > max && max != -1) - return NULL; - - if (content_length == 0) { - *received = 0; - postdata = (char*)malloc(1); - postdata[0] = '\0'; - return postdata; - } - - postdata = (char*)malloc(content_length+1); - if (postdata == NULL) { - log_error1("Not enough memory"); - return NULL; - } - - - if (hsocket_read(conn->sock, postdata, - (int)content_length, 1) == HSOCKET_OK) { - *received = content_length; - postdata[content_length] = '\0'; - return postdata; - } - - free (postdata); - return NULL; - + char *content_length_str; + long content_length = 0; + long total = 0; + char *postdata = NULL; + + if (!strcmp(req->method, "POST")) { + + content_length_str = + hpairnode_get_ignore_case(req->header, HEADER_CONTENT_LENGTH); + + if (content_length_str != NULL) + content_length = atol(content_length_str); + + } else { + log_warn1("Not a POST method"); + return NULL; + } + + if (content_length > max && max != -1) + return NULL; + + if (content_length == 0) { + *received = 0; + postdata = (char*)malloc(1); + postdata[0] = '\0'; + return postdata; + } + + postdata = (char*)malloc(content_length+1); + if (postdata == NULL) { + log_error1("Not enough memory"); + return NULL; + } + + + if (hsocket_read(conn->sock, postdata, + (int)content_length, 1) == HSOCKET_OK) { + *received = content_length; + postdata[content_length] = '\0'; + return postdata; + } + + free (postdata); + return NULL; + } diff --git a/nanohttp/nanohttp-socket.c b/nanohttp/nanohttp-socket.c index a555a7f..9b0e673 100644 --- a/nanohttp/nanohttp-socket.c +++ b/nanohttp/nanohttp-socket.c @@ -1,29 +1,37 @@ /****************************************************************** - * $Id: nanohttp-socket.c,v 1.8 2004/02/03 08:59:23 snowdrop Exp $ - * - * CSOAP Project: A http client/server library in C - * Copyright (C) 2003 Ferhat Ayaz - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Email: ayaz@jprogrammer.net - ******************************************************************/ +* $Id: nanohttp-socket.c,v 1.9 2004/08/26 17:07:47 rans Exp $ +* +* CSOAP Project: A http client/server library in C +* Copyright (C) 2003 Ferhat Ayaz +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +* +* Email: ayaz@jprogrammer.net +******************************************************************/ #include <nanohttp/nanohttp-socket.h> #include <nanohttp/nanohttp-common.h> +#ifdef WIN32 +#include "wsockcompat.h" +#include <winsock2.h> +#define close(s) closesocket(s) +typedef int ssize_t; +typedef int socklen_t; +#endif + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -52,339 +60,384 @@ #include <errno.h> /*-------------------------------------------------- - FUNCTION: hsocket_module_init +FUNCTION: hsocket_module_init ----------------------------------------------------*/ int hsocket_module_init() { - /* nothing to init for unix sockets */ - return 0; + /* nothing to init for unix sockets */ + return 0; } /*-------------------------------------------------- - FUNCTION: hsocket_module_destroy +FUNCTION: hsocket_module_destroy ----------------------------------------------------*/ void hsocket_module_destroy() { - /* nothing to destroy for unix sockets */ + /* nothing to destroy for unix sockets */ } /*-------------------------------------------------- - FUNCTION: hsocket_init +FUNCTION: hsocket_init ----------------------------------------------------*/ int hsocket_init(hsocket_t *sock) { - /* nothing to init for unix sockets */ - /* just set the descriptor to -1 */ - *sock = -1; - return 0; + /* nothing to init for unix sockets */ + /* just set the descriptor to -1 */ + *sock = -1; +#ifdef WIN32 + // WSACleanup(); + struct WSAData info; + WSAStartup(MAKEWORD(2,2), &info); +#endif + return 0; } /*-------------------------------------------------- - FUNCTION: hsocket_free +FUNCTION: hsocket_free ----------------------------------------------------*/ void hsocket_free(hsocket_t sock) { - /* nothing to free for unix sockets */ + /* nothing to free for unix sockets */ } /*-------------------------------------------------- - FUNCTION: hsocket_open +FUNCTION: hsocket_open ----------------------------------------------------*/ int hsocket_open(hsocket_t *dsock, const char* hostname, int port) { - int sock; - struct sockaddr_in address; - struct hostent* host; +#ifdef WIN32 + SOCKET sock; +#else + int sock; +#endif + char *ip; + struct sockaddr_in address; + struct hostent* host; - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock <= 0) return HSOCKET_CAN_NOT_CREATE; + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock <= 0) return HSOCKET_CAN_NOT_CREATE; - /* Get host data */ - host = gethostbyname(hostname); - if (host == NULL) return HSOCKET_CAN_NOT_GET_HOSTNAME; + /* Get host data */ + host = gethostbyname(hostname); + if (host == NULL) return HSOCKET_CAN_NOT_GET_HOSTNAME; - /* set server addresss */ - address.sin_family = host->h_addrtype; - address.sin_port = htons(port); - memcpy((char*)&address.sin_addr.s_addr, - host->h_addr_list[0], host->h_length); + ip = inet_ntoa (*(struct in_addr *)*host->h_addr_list); + address.sin_addr.s_addr = inet_addr(ip); - /* connect to the server */ - if (connect(sock, (struct sockaddr*) &address, sizeof(address)) != 0) - return HSOCKET_CAN_NOT_CONNECT; + /* set server addresss */ + address.sin_family = host->h_addrtype; + address.sin_port = htons(port); + /* connect to the server */ + if (connect(sock, (struct sockaddr*) &address, sizeof(address)) != 0) + return HSOCKET_CAN_NOT_CONNECT; - *dsock = sock; - return HSOCKET_OK; + *dsock = sock; + return HSOCKET_OK; } /*-------------------------------------------------- - FUNCTION: hsocket_close +FUNCTION: hsocket_close ----------------------------------------------------*/ int hsocket_bind(hsocket_t *dsock, int port) { - int sock; - struct sockaddr_in addr; - - /* create socket */ - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == -1) { - log_error2("Can not create socket: '%s'", strerror(errno)); - return HSOCKET_CAN_NOT_CREATE; - } - - /* bind socket */ - addr.sin_family = AF_INET; - addr.sin_port = htons(port); /* short, network byte order */ - addr.sin_addr.s_addr = INADDR_ANY; - memset(&(addr.sin_zero), '\0', 8); /* zero the rest of the struct */ - - if (bind(sock, (struct sockaddr *)&addr, - sizeof(struct sockaddr)) == -1) { - log_error2("Can not bind: '%s'", strerror(errno)); - return HSOCKET_CAN_NOT_BIND; - } - - *dsock = sock; - return HSOCKET_OK; +#ifdef WIN32 + SOCKET sock; +#else + int sock; +#endif + struct sockaddr_in addr; + + /* create socket */ + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + log_error2("Can not create socket: '%s'", strerror(errno)); + return HSOCKET_CAN_NOT_CREATE; + } + + /* bind socket */ + addr.sin_family = AF_INET; + addr.sin_port = htons(port); /* short, network byte order */ + addr.sin_addr.s_addr = INADDR_ANY; + memset(&(addr.sin_zero), '\0', 8); /* zero the rest of the struct */ + + if (bind(sock, (struct sockaddr *)&addr, + sizeof(struct sockaddr)) == -1) { + log_error2("Can not bind: '%s'", strerror(errno)); + return HSOCKET_CAN_NOT_BIND; + } + + *dsock = sock; +#ifdef WIN32 + // setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)true, sizeof(BOOL)); + // setsockopt(sock, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (char*)true, sizeof(BOOL)); +#endif + return HSOCKET_OK; } /*-------------------------------------------------- - FUNCTION: hsocket_listen +FUNCTION: hsocket_listen ----------------------------------------------------*/ int hsocket_listen(hsocket_t sock, int n) { - if (listen(sock, n) == -1) { - log_error2("Can not listen: '%s'", strerror(errno)); - return HSOCKET_CAN_NOT_LISTEN; - } - return HSOCKET_OK; + if (listen(sock, n) == -1) { + log_error2("Can not listen: '%s'", strerror(errno)); + return HSOCKET_CAN_NOT_LISTEN; + } + return HSOCKET_OK; } /*-------------------------------------------------- - FUNCTION: hsocket_listen +FUNCTION: hsocket_listen ----------------------------------------------------*/ int hsocket_accept(hsocket_t sock, hsocket_t *dest) { - socklen_t asize; - int sockfd; - struct sockaddr_in addr; - - asize = sizeof(struct sockaddr_in); - sockfd = accept(sock, (struct sockaddr *)&addr, &asize); - - if (sockfd == -1) { - //httpd_log("httpd_run(): '%s'\n", strerror(errno)); - return HSOCKET_CAN_NOT_ACCEPT; - } - - log_verbose3("accept new socket (%d) from '%s'", sockfd, - SAVE_STR(((char*)inet_ntoa(addr.sin_addr))) ); - - *dest = sockfd; - return HSOCKET_OK; + socklen_t asize; + SOCKET sockfd; + struct sockaddr_in addr; + + asize = sizeof(struct sockaddr_in); +#ifdef WIN32 + while(1) + { + sockfd = accept(sock, (struct sockaddr *)&addr, &asize); + if (sockfd == -1) { + if(WSAGetLastError()!=WSAEWOULDBLOCK) + { + return HSOCKET_CAN_NOT_ACCEPT; + } + } + else + { + break; + } + } +#else + sockfd = accept(sock, (struct sockaddr *)&addr, &asize); + if (sockfd == -1) { + //httpd_log("httpd_run(): '%s'\n", strerror(errno)); + return HSOCKET_CAN_NOT_ACCEPT; + } +#endif + log_verbose3("accept new socket (%d) from '%s'", sockfd, + SAVE_STR(((char*)inet_ntoa(addr.sin_addr))) ); + + *dest = sockfd; + return HSOCKET_OK; } /*-------------------------------------------------- - FUNCTION: hsocket_close +FUNCTION: hsocket_close ----------------------------------------------------*/ void hsocket_close(hsocket_t sock) { - close(sock); + close(sock); +#ifdef WIN32 + WSACleanup(); +#endif } /*-------------------------------------------------- - FUNCTION: hsocket_send +FUNCTION: hsocket_send ----------------------------------------------------*/ int hsocket_nsend(hsocket_t sock, const char* buffer, int n) { - int size; + int size; - size = send((int)sock, buffer, n, 0); - if (size == -1) - return HSOCKET_CAN_NOT_SEND; + size = send((int)sock, buffer, n, 0); + if (size == -1) + return HSOCKET_CAN_NOT_SEND; - return HSOCKET_OK; + return HSOCKET_OK; } /*-------------------------------------------------- - FUNCTION: hsocket_send +FUNCTION: hsocket_send ----------------------------------------------------*/ int hsocket_send(hsocket_t sock, const char* buffer) { - int size; - size = send((int)sock, buffer, strlen(buffer), 0); - if (size == -1) - return HSOCKET_CAN_NOT_SEND; + int size; + size = send((int)sock, buffer, strlen(buffer), 0); + if (size == -1) + return HSOCKET_CAN_NOT_SEND; - return HSOCKET_OK; + return HSOCKET_OK; } int hsocket_read(hsocket_t sock, char* buffer, int total, int force) { - int status; - int totalRead; - - totalRead = 0; - - do { - status = recv(sock, &buffer[totalRead], total - totalRead, 0); - if (!force) return status; - if (status > 0) { - totalRead += status; - } else { - return status; - } - if (totalRead >= total) - return 0; - } while (1); + int status; + int totalRead; + + totalRead = 0; + + do { + status = recv(sock, &buffer[totalRead], total - totalRead, 0); + if (!force) + { +#ifdef WIN32 + if(WSAGetLastError()!=WSAEWOULDBLOCK) + { + return status; + } +#else + return status; +#endif + } + if (status > 0) { + totalRead += status; + } else { +#ifdef WIN32 + if(WSAGetLastError()!=WSAEWOULDBLOCK) + { + return status; + } +#else + return status; +#endif + } + if (totalRead >= total) + return 0; + } while (1); } /*-------------------------------------------------- - FUNCTION: hsocket_recv +FUNCTION: hsocket_recv ----------------------------------------------------*/ int hsocket_recv(hsocket_t sock, char** buffer, int *totalSize) { - ssize_t size; - int chunk=1; - char tmp[HSOCKET_MAX_BUFSIZE+1]; - int fsize; - int bufSize; - - if (*totalSize > 0) { - bufSize = *totalSize; - } else { - bufSize = HSOCKET_MAX_BUFSIZE; - } - - *totalSize = 0; - - /* calculate first size for realloc */ - if (*buffer) { - fsize = strlen(*buffer); - } else { - fsize = 0; - } - - do { - - size = recv(sock, tmp, bufSize, 0); - bufSize = HSOCKET_MAX_BUFSIZE; - - if (size == -1) { - log_error1("Error reading from socket"); - return HSOCKET_CAN_NOT_RECEIVE; - } - - if (size == 0) { - break; - } - - *totalSize += size; - if (*buffer) { - log_verbose2("reallocation %d bytes",*totalSize+fsize+1); - *buffer = (char*)realloc((char*)*buffer, - (*totalSize)+fsize+HSOCKET_MAX_BUFSIZE); - strcat(*buffer, tmp); - } else { - *buffer = (char*)realloc(NULL, *totalSize+1); - strcpy(*buffer, tmp); - } - - (*buffer)[*totalSize+fsize] = '\0'; - chunk++; - } while (size > 0); - - return HSOCKET_OK; + ssize_t size; + int chunk=1; + char tmp[HSOCKET_MAX_BUFSIZE+1]; + int fsize; + int bufSize; + + if (*totalSize > 0) { + bufSize = *totalSize; + } else { + bufSize = HSOCKET_MAX_BUFSIZE; + } + + *totalSize = 0; + + /* calculate first size for realloc */ + if (*buffer) { + fsize = strlen(*buffer); + } else { + fsize = 0; + } + + do { + + size = recv(sock, tmp, bufSize, 0); + bufSize = HSOCKET_MAX_BUFSIZE; + + if (size == -1) { + log_error1("Error reading from socket"); + return HSOCKET_CAN_NOT_RECEIVE; + } + + if (size == 0) { + break; + } + + *totalSize += size; + if (*buffer) { + log_verbose2("reallocation %d bytes",*totalSize+fsize+1); + *buffer = (char*)realloc((char*)*buffer, + (*totalSize)+fsize+HSOCKET_MAX_BUFSIZE); + strcat(*buffer, tmp); + } else { + *buffer = (char*)realloc(NULL, *totalSize+1); + strcpy(*buffer, tmp); + } + + (*buffer)[*totalSize+fsize] = '\0'; + chunk++; + } while (size > 0); + + return HSOCKET_OK; } /*-------------------------------------------------- - FUNCTION: hsocket_recv +FUNCTION: hsocket_recv ----------------------------------------------------*/ int hsocket_recv_cb(hsocket_t sock, - hsocket_recv_callback cb, void *userdata) + hsocket_recv_callback cb, void *userdata) { - ssize_t size; - char tmp[HSOCKET_MAX_BUFSIZE+1]; - - do { - - size = recv(sock, tmp, HSOCKET_MAX_BUFSIZE, 0); - - if (size == -1) { - log_error1("Error reading from socket"); - return HSOCKET_CAN_NOT_RECEIVE; - } - - if (size == 0) { - break; - } - - tmp[size]='\0'; - if (!cb(sock, tmp, size, userdata)) { - break; - } - - } while (size > 0); - - return HSOCKET_OK; + ssize_t size; + char tmp[HSOCKET_MAX_BUFSIZE+1]; + + do { + + size = recv(sock, tmp, HSOCKET_MAX_BUFSIZE, 0); + + if (size == -1) { + log_error1("Error reading from socket"); + return HSOCKET_CAN_NOT_RECEIVE; + } + + if (size == 0) { + break; + } + + tmp[size]='\0'; + if (!cb(sock, tmp, size, userdata)) { + break; + } + + } while (size > 0); + + return HSOCKET_OK; } /*-------------------------------------------------- - FUNCTION: hbufsocket_read +FUNCTION: hbufsocket_read ----------------------------------------------------*/ int hbufsocket_read(hbufsocket_t *bufsock, char *buffer, int size) { - int status; - int tmpsize; - - if (bufsock->bufsize - bufsock->cur >= size) { - - log_verbose1("no need to read from socket"); - strncpy(buffer, &(bufsock->buffer[bufsock->cur]), size); - bufsock->cur += size; - return HSOCKET_OK; - - } else { - - tmpsize = bufsock->bufsize - bufsock->cur; - log_verbose2("tmpsize = %d", tmpsize); - - if (tmpsize > 0) - strncpy(buffer, &(bufsock->buffer[bufsock->cur]), tmpsize); - - size -= tmpsize; - - free(bufsock->buffer); - - status = hsocket_read(bufsock->sock, &buffer[tmpsize], size, 1); - if (status == size) { - bufsock->buffer = (char*)malloc(size+1); - strncpy(bufsock->buffer, &buffer[tmpsize], size); - bufsock->cur = size; - } else { - return status; - } - - return HSOCKET_OK; - } -} + int status; + int tmpsize; + if (bufsock->bufsize - bufsock->cur >= size) { + log_verbose1("no need to read from socket"); + strncpy(buffer, &(bufsock->buffer[bufsock->cur]), size); + bufsock->cur += size; + return HSOCKET_OK; + } else { + tmpsize = bufsock->bufsize - bufsock->cur; + log_verbose2("tmpsize = %d", tmpsize); + if (tmpsize > 0) + strncpy(buffer, &(bufsock->buffer[bufsock->cur]), tmpsize); + size -= tmpsize; + free(bufsock->buffer); + status = hsocket_read(bufsock->sock, &buffer[tmpsize], size, 1); + if (status == size) { + bufsock->buffer = (char*)malloc(size+1); + strncpy(bufsock->buffer, &buffer[tmpsize], size); + bufsock->cur = size; + } else { + return status; + } + + return HSOCKET_OK; + } +} diff --git a/nanohttp/nanohttp-socket.h b/nanohttp/nanohttp-socket.h index 12dc5d9..f86b149 100644 --- a/nanohttp/nanohttp-socket.h +++ b/nanohttp/nanohttp-socket.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-socket.h,v 1.5 2004/01/21 12:28:20 snowdrop Exp $ + * $Id: nanohttp-socket.h,v 1.6 2004/08/26 17:07:47 rans Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -24,7 +24,7 @@ #ifndef NANO_HTTP_SOCKET_H #define NANO_HTTP_SOCKET_H - +#define HSOCKET_BLOCKMODE 0 #define HSOCKET_OK 0 #define HSOCKET_CAN_NOT_CREATE 1001 #define HSOCKET_CAN_NOT_GET_HOSTNAME 1002 @@ -37,8 +37,12 @@ #define HSOCKET_MAX_BUFSIZE 1024 +#ifdef WIN32 +#include <winsock2.h> +typedef SOCKET hsocket_t; +#else typedef int hsocket_t; - +#endif /* PROTOTYPE: int my_recv_cb(hsocket_t sock, char *buffer, int size, void *userdata); diff --git a/nanohttp/nanohttp.vcproj b/nanohttp/nanohttp.vcproj new file mode 100644 index 0000000..82bb0cb --- /dev/null +++ b/nanohttp/nanohttp.vcproj @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="nanohttp" + ProjectGUID="{B935F0BE-F513-4F83-8A05-E0C0BE9A08BE}" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="4" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\,.\" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB" + MinimalRebuild="TRUE" + BasicRuntimeChecks="0" + RuntimeLibrary="5" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4" + CompileAs="2"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + AdditionalDependencies=" Ws2_32.lib" + OutputFile="$(OutDir)/nanohttp.lib" + AdditionalLibraryDirectories="" + IgnoreAllDefaultLibraries="TRUE" + IgnoreDefaultLibraryNames=""/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="4" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\,.\" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + RuntimeLibrary="4" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + AdditionalDependencies=" Ws2_32.lib" + OutputFile="$(OutDir)/nanohttp.lib"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + <File + RelativePath=".\nanohttp-client.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + CompileAs="2"/> + </FileConfiguration> + </File> + <File + RelativePath=".\nanohttp-common.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + CompileAs="2"/> + </FileConfiguration> + </File> + <File + RelativePath=".\nanohttp-server.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + CompileAs="2"/> + </FileConfiguration> + </File> + <File + RelativePath=".\nanohttp-socket.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + CompileAs="2"/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + <File + RelativePath=".\nanohttp-client.h"> + </File> + <File + RelativePath=".\nanohttp-common.h"> + </File> + <File + RelativePath=".\nanohttp-server.h"> + </File> + <File + RelativePath=".\nanohttp-socket.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + </Filter> + <File + RelativePath=".\readme.txt"> + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/nanohttp/pthread.h b/nanohttp/pthread.h new file mode 100644 index 0000000..729458c --- /dev/null +++ b/nanohttp/pthread.h @@ -0,0 +1,1345 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2003 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#ifdef _UWIN +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson <rpj@ise.canberra.edu.au> + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if defined(__MINGW32__) && defined(__cplusplus) +/* + * FIXME: The pthreadGCE.dll build gets linker unresolved errors + * on pthread_key_create() unless windows.h is included here. + * It appears to have something to do with an argument type mismatch. + * Looking at tsd.o with 'nm' shows this line: + * 00000000 T _pthread_key_create__FPP14pthread_key_t_PFPv_v + * instead of + * 00000000 T _pthread_key_create + */ +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#ifdef PTW32_INCLUDE_WINDOWS_H +#include <windows.h> +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* Try to avoid including windows.h */ +#if defined(__MINGW32__) && defined(__cplusplus) +/* + * FIXME: The pthreadGCE.dll build gets linker unresolved errors + * on pthread_key_create() unless windows.h is included here. + * It appears to have something to do with an argument type mismatch. + * Looking at tsd.o with 'nm' shows this line: + * 00000000 T _pthread_key_create__FPP14pthread_key_t_PFPv_v + * instead of + * 00000000 T _pthread_key_create + */ +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#ifdef PTW32_INCLUDE_WINDOWS_H +#include <windows.h> +#endif + +#ifndef NEED_FTIME +#include <time.h> +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if HAVE_SIGNAL_H +#include <signal.h> +#endif /* HAVE_SIGNAL_H */ + +#include <setjmp.h> +#include <limits.h> + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include <errno.h> +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define ENOTSUP. If not, we use + * the same value as Solaris. + */ +#ifndef ENOTSUP +# define ENOTSUP 48 +#endif + +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#include <sched.h> + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. I don't like the potential incompatibility that + * this creates with future versions of windows. + */ +#ifndef PTW32_INCLUDE_WINDOWS_H +#ifndef HANDLE +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#ifndef DWORD +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC */ + +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#ifndef SIG_SETMASK +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * _POSIX_THREADS (set) + * If set, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (set) + * If set, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (not set) + * If set, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (set) + * If set, you can use realtime scheduling. + * Indicates the availability of: + * pthread_attr_getinheritsched + * pthread_attr_getschedparam + * pthread_attr_getschedpolicy + * pthread_attr_getscope + * pthread_attr_setinheritsched + * pthread_attr_setschedparam + * pthread_attr_setschedpolicy + * pthread_attr_setscope + * pthread_getschedparam + * pthread_setschedparam + * sched_get_priority_max + * sched_get_priority_min + * sched_rr_set_interval + * + * _POSIX_THREAD_PRIO_INHERIT (not set) + * If set, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (not set) + * If set, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (not set) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (set) + * If set you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (set) + * If set, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (set) + * If set, you can use spin locks + * + * _POSIX_BARRIERS (set) + * If set, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * POSIX 1003.1-2001 Limits + * =========================== + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * _POSIX_SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (only defined if not already defined) + * + * _POSIX_SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (only defined if not already defined) + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#ifndef _POSIX_THREADS +#define _POSIX_THREADS +#endif + +#ifndef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS +#endif + +#ifndef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS +#endif + +#ifndef _POSIX_BARRIERS +#define _POSIX_BARRIERS +#endif + +#define _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_PRIORITY_SCHEDULING + +#if defined( KLUDGE ) +/* + * The following are not supported + */ +#define _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PROCESS_SHARED + +#endif /* KLUDGE */ + +/* + * POSIX Limits + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Standard states this must be at least + * 4. + * + * PTHREAD_KEYS_MAX + * WIN32 permits only 64 TLS keys per process. + * This limitation could be worked around by + * simply simulating keys. + * + * PTHREADS_STACK_MIN + * POSIX specifies 0 which is also the value WIN32 + * interprets as allowing the system to + * set the size to that of the main thread. The + * maximum stack size in Win32 is 1Meg. WIN32 + * allocates more stack as required up to the 1Meg + * limit. + * + * PTHREAD_THREADS_MAX + * Not documented by WIN32. Wrote a test program + * that kept creating threads until it failed + * revealed this approximate number (Windows NT). + * This number is somewhat less for Windows 9x + * and is effectively less than 64. Perhaps this + * constant should be set at DLL load time. + * + */ +#define PTHREAD_DESTRUCTOR_ITERATIONS 4 +#define PTHREAD_KEYS_MAX 64 +#define PTHREAD_STACK_MIN 0 +#define PTHREAD_THREADS_MAX 2019 +#ifndef _POSIX_SEM_NSEMS_MAX +/* Not used and only an arbitrary value. */ +# define _POSIX_SEM_NSEMS_MAX 1024 +#endif +#ifndef _POSIX_SEM_VALUE_MAX +# define _POSIX_SEM_VALUE_MAX (INT_MAX/2) +#endif + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifdef _DLL +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include <sys/types.h> +#else +typedef struct pthread_t_ *pthread_t; +typedef struct pthread_attr_t_ *pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ *pthread_key_t; +typedef struct pthread_mutex_t_ *pthread_mutex_t; +typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t; +typedef struct pthread_cond_t_ *pthread_cond_t; +typedef struct pthread_condattr_t_ *pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ *pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ *pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ *pthread_spinlock_t; +typedef struct pthread_barrier_t_ *pthread_barrier_t; +typedef struct pthread_barrierattr_t_ *pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, -1 } + +struct pthread_once_t_ +{ + int done; /* indicates if user function executed */ + long started; /* First thread to increment this value */ + /* to zero executes the user function */ +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && defined(__GNUC__) +#error ERROR [__FILE__, line __LINE__]: GNUC does not support SEH. +#endif + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#ifdef __CLEANUP_SEH + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(*start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (*init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + void (*routine) (void *), + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (*destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in <signal.h> but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#ifndef _UWIN +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# ifndef errno +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * WIN32 C runtime library had been made thread-safe + * without affecting the user interface. Provide + * mappings from the UNIX thread-safe versions to + * the standard C runtime library calls. + * Only provide function mappings for functions that + * actually exist on WIN32. + */ + +#if !defined(__MINGW32__) +#define strtok_r( _s, _sep, _lasts ) \ + ( *(_lasts) = strtok( (_s), (_sep) ) ) +#endif /* !__MINGW32__ */ + +#define asctime_r( _tm, _buf ) \ + ( strcpy( (_buf), asctime( (_tm) ) ), \ + (_buf) ) + +#define ctime_r( _clock, _buf ) \ + ( strcpy( (_buf), ctime( (_clock) ) ), \ + (_buf) ) + +#define gmtime_r( _clock, _result ) \ + ( *(_result) = *gmtime( (_clock) ), \ + (_result) ) + +#define localtime_r( _clock, _result ) \ + ( *(_result) = *localtime( (_clock) ), \ + (_result) ) + +#define rand_r( _seed ) \ + ( _seed == _seed? rand() : rand() ) + + +#ifdef __cplusplus + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#ifndef PTW32_BUILD + +#ifdef __CLEANUP_SEH + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_CXX + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#ifdef _MSC_VER + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#ifndef PtW32NoCatchWarn + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #ifdef PtW32CatchAll") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#ifdef PTW32__HANDLE_DEF +# undef HANDLE +#endif +#ifdef PTW32__DWORD_DEF +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* PTHREAD_H */ diff --git a/nanohttp/sched.h b/nanohttp/sched.h new file mode 100644 index 0000000..e6a0ee1 --- /dev/null +++ b/nanohttp/sched.h @@ -0,0 +1,174 @@ +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2003 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef _SCHED_H +#define _SCHED_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +#else +# define PTW32_DLLPORT __declspec (dllimport) +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include <errno.h> +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if defined(__MINGW32__) || defined(_UWIN) +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +/* For pid_t */ +# include <sys/types.h> +/* Required by Unix 98 */ +# include <time.h> +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ +#else +typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/nanohttp/semaphore.h b/nanohttp/semaphore.h new file mode 100644 index 0000000..f26417e --- /dev/null +++ b/nanohttp/semaphore.h @@ -0,0 +1,163 @@ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2003 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +#else +# define PTW32_DLLPORT __declspec (dllimport) +#endif + + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include <errno.h> +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef HAVE_MODE_T +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/nanohttp/wsockcompat.h b/nanohttp/wsockcompat.h new file mode 100644 index 0000000..690048c --- /dev/null +++ b/nanohttp/wsockcompat.h @@ -0,0 +1,61 @@ +/* include/wsockcompat.h + * Windows -> Berkeley Sockets compatibility things. + */ + +#if !defined __XML_WSOCKCOMPAT_H__ +#define __XML_WSOCKCOMPAT_H__ + +#ifdef _WIN32_WCE +#include <winsock.h> +#else +#undef HAVE_ERRNO_H +#include <winsock2.h> +#endif + +#if !defined SOCKLEN_T +#define SOCKLEN_T int +#endif + +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE +/* These cause conflicts with the codes from errno.h. Since they are + not used in the relevant code (nanoftp, nanohttp), we can leave + them disabled. +#define ENAMETOOLONG WSAENAMETOOLONG +#define ENOTEMPTY WSAENOTEMPTY +*/ + +#endif /* __XML_WSOCKCOMPAT_H__ */ |