mirror of
https://gitlab.xiph.org/xiph/icecast-common.git
synced 2024-09-22 04:15:55 -04:00
Brendan was getting pissed off about inconsistent indentation styles.
Convert all tabs to 4 spaces. All code must now use 4 space indents. svn path=/trunk/avl/; revision=4492
This commit is contained in:
parent
6198c728e1
commit
d0cf9fe000
108
avl/avl.h
108
avl/avl.h
@ -2,7 +2,7 @@
|
|||||||
* Copyright (C) 1995 by Sam Rushing <rushing@nightmare.com>
|
* Copyright (C) 1995 by Sam Rushing <rushing@nightmare.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: avl.h,v 1.5 2003/03/09 22:56:46 karl Exp $ */
|
/* $Id: avl.h,v 1.6 2003/03/15 02:10:18 msmith Exp $ */
|
||||||
|
|
||||||
#ifndef __AVL_H
|
#ifndef __AVL_H
|
||||||
#define __AVL_H
|
#define __AVL_H
|
||||||
@ -22,24 +22,24 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct avl_node_tag {
|
typedef struct avl_node_tag {
|
||||||
void * key;
|
void * key;
|
||||||
struct avl_node_tag * left;
|
struct avl_node_tag * left;
|
||||||
struct avl_node_tag * right;
|
struct avl_node_tag * right;
|
||||||
struct avl_node_tag * parent;
|
struct avl_node_tag * parent;
|
||||||
/*
|
/*
|
||||||
* The lower 2 bits of <rank_and_balance> specify the balance
|
* The lower 2 bits of <rank_and_balance> specify the balance
|
||||||
* factor: 00==-1, 01==0, 10==+1.
|
* factor: 00==-1, 01==0, 10==+1.
|
||||||
* The rest of the bits are used for <rank>
|
* The rest of the bits are used for <rank>
|
||||||
*/
|
*/
|
||||||
unsigned long rank_and_balance;
|
unsigned long rank_and_balance;
|
||||||
#ifndef NO_THREAD
|
#ifndef NO_THREAD
|
||||||
rwlock_t rwlock;
|
rwlock_t rwlock;
|
||||||
#endif
|
#endif
|
||||||
} avl_node;
|
} avl_node;
|
||||||
|
|
||||||
#define AVL_GET_BALANCE(n) ((int)(((n)->rank_and_balance & 3) - 1))
|
#define AVL_GET_BALANCE(n) ((int)(((n)->rank_and_balance & 3) - 1))
|
||||||
|
|
||||||
#define AVL_GET_RANK(n) (((n)->rank_and_balance >> 2))
|
#define AVL_GET_RANK(n) (((n)->rank_and_balance >> 2))
|
||||||
|
|
||||||
#define AVL_SET_BALANCE(n,b) \
|
#define AVL_SET_BALANCE(n,b) \
|
||||||
((n)->rank_and_balance) = \
|
((n)->rank_and_balance) = \
|
||||||
@ -51,11 +51,11 @@ typedef struct avl_node_tag {
|
|||||||
|
|
||||||
struct _avl_tree;
|
struct _avl_tree;
|
||||||
|
|
||||||
typedef int (*avl_key_compare_fun_type) (void * compare_arg, void * a, void * b);
|
typedef int (*avl_key_compare_fun_type) (void * compare_arg, void * a, void * b);
|
||||||
typedef int (*avl_iter_fun_type) (void * key, void * iter_arg);
|
typedef int (*avl_iter_fun_type) (void * key, void * iter_arg);
|
||||||
typedef int (*avl_iter_index_fun_type) (unsigned long index, void * key, void * iter_arg);
|
typedef int (*avl_iter_index_fun_type) (unsigned long index, void * key, void * iter_arg);
|
||||||
typedef int (*avl_free_key_fun_type) (void * key);
|
typedef int (*avl_free_key_fun_type) (void * key);
|
||||||
typedef int (*avl_key_printer_fun_type) (char *, void *);
|
typedef int (*avl_key_printer_fun_type) (char *, void *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* <compare_fun> and <compare_arg> let us associate a particular compare
|
* <compare_fun> and <compare_arg> let us associate a particular compare
|
||||||
@ -63,11 +63,11 @@ typedef int (*avl_key_printer_fun_type) (char *, void *);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct _avl_tree {
|
typedef struct _avl_tree {
|
||||||
avl_node * root;
|
avl_node * root;
|
||||||
unsigned long height;
|
unsigned long height;
|
||||||
unsigned long length;
|
unsigned long length;
|
||||||
avl_key_compare_fun_type compare_fun;
|
avl_key_compare_fun_type compare_fun;
|
||||||
void * compare_arg;
|
void * compare_arg;
|
||||||
#ifndef NO_THREAD
|
#ifndef NO_THREAD
|
||||||
rwlock_t rwlock;
|
rwlock_t rwlock;
|
||||||
#endif
|
#endif
|
||||||
@ -77,66 +77,66 @@ avl_tree * avl_tree_new (avl_key_compare_fun_type compare_fun, void * compare_ar
|
|||||||
avl_node * avl_node_new (void * key, avl_node * parent);
|
avl_node * avl_node_new (void * key, avl_node * parent);
|
||||||
|
|
||||||
void avl_tree_free (
|
void avl_tree_free (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
avl_free_key_fun_type free_key_fun
|
avl_free_key_fun_type free_key_fun
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_insert (
|
int avl_insert (
|
||||||
avl_tree * ob,
|
avl_tree * ob,
|
||||||
void * key
|
void * key
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_delete (
|
int avl_delete (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
void * key,
|
void * key,
|
||||||
avl_free_key_fun_type free_key_fun
|
avl_free_key_fun_type free_key_fun
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_get_by_index (
|
int avl_get_by_index (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
unsigned long index,
|
unsigned long index,
|
||||||
void ** value_address
|
void ** value_address
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_get_by_key (
|
int avl_get_by_key (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
void * key,
|
void * key,
|
||||||
void ** value_address
|
void ** value_address
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_iterate_inorder (
|
int avl_iterate_inorder (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
avl_iter_fun_type iter_fun,
|
avl_iter_fun_type iter_fun,
|
||||||
void * iter_arg
|
void * iter_arg
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_iterate_index_range (
|
int avl_iterate_index_range (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
avl_iter_index_fun_type iter_fun,
|
avl_iter_index_fun_type iter_fun,
|
||||||
unsigned long low,
|
unsigned long low,
|
||||||
unsigned long high,
|
unsigned long high,
|
||||||
void * iter_arg
|
void * iter_arg
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_get_span_by_key (
|
int avl_get_span_by_key (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
void * key,
|
void * key,
|
||||||
unsigned long * low,
|
unsigned long * low,
|
||||||
unsigned long * high
|
unsigned long * high
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_get_span_by_two_keys (
|
int avl_get_span_by_two_keys (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
void * key_a,
|
void * key_a,
|
||||||
void * key_b,
|
void * key_b,
|
||||||
unsigned long * low,
|
unsigned long * low,
|
||||||
unsigned long * high
|
unsigned long * high
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_verify (avl_tree * tree);
|
int avl_verify (avl_tree * tree);
|
||||||
|
|
||||||
void avl_print_tree (
|
void avl_print_tree (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
avl_key_printer_fun_type key_printer
|
avl_key_printer_fun_type key_printer
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -149,15 +149,15 @@ avl_node *avl_get_next(avl_node * node);
|
|||||||
/* These two are from David Ascher <david_ascher@brown.edu> */
|
/* These two are from David Ascher <david_ascher@brown.edu> */
|
||||||
|
|
||||||
int avl_get_item_by_key_most (
|
int avl_get_item_by_key_most (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
void * key,
|
void * key,
|
||||||
void ** value_address
|
void ** value_address
|
||||||
);
|
);
|
||||||
|
|
||||||
int avl_get_item_by_key_least (
|
int avl_get_item_by_key_least (
|
||||||
avl_tree * tree,
|
avl_tree * tree,
|
||||||
void * key,
|
void * key,
|
||||||
void ** value_address
|
void ** value_address
|
||||||
);
|
);
|
||||||
|
|
||||||
/* optional locking stuff */
|
/* optional locking stuff */
|
||||||
|
86
avl/test.c
86
avl/test.c
@ -11,75 +11,75 @@ int _printer(char *buff, void *key);
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i, max_nodes;
|
int i, max_nodes;
|
||||||
avl_tree *tree;
|
avl_tree *tree;
|
||||||
avl_node *node;
|
avl_node *node;
|
||||||
|
|
||||||
max_nodes = 25;
|
max_nodes = 25;
|
||||||
|
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
max_nodes = atoi(argv[1]);
|
max_nodes = atoi(argv[1]);
|
||||||
if (max_nodes == 0)
|
if (max_nodes == 0)
|
||||||
max_nodes = 10;
|
max_nodes = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("avl test... max_nodes = %d...\n", max_nodes);
|
printf("avl test... max_nodes = %d...\n", max_nodes);
|
||||||
|
|
||||||
tree = avl_tree_new(_compare, NULL);
|
tree = avl_tree_new(_compare, NULL);
|
||||||
|
|
||||||
printf("Filling tree...\n");
|
printf("Filling tree...\n");
|
||||||
for (i = 0; i < max_nodes; i++) {
|
for (i = 0; i < max_nodes; i++) {
|
||||||
avl_insert(tree, (void *)rand());
|
avl_insert(tree, (void *)rand());
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Traversing tree...\n");
|
printf("Traversing tree...\n");
|
||||||
node = avl_get_first(tree);
|
node = avl_get_first(tree);
|
||||||
while (node) {
|
while (node) {
|
||||||
i = (int)node->key;
|
i = (int)node->key;
|
||||||
|
|
||||||
printf("...%5d\n", i);
|
printf("...%5d\n", i);
|
||||||
|
|
||||||
node = avl_get_next(node);
|
node = avl_get_next(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Trying to go backwards...\n");
|
printf("Trying to go backwards...\n");
|
||||||
node = tree->root->right;
|
node = tree->root->right;
|
||||||
while (node) {
|
while (node) {
|
||||||
i = (int)node->key;
|
i = (int)node->key;
|
||||||
printf("...%5d\n", i);
|
printf("...%5d\n", i);
|
||||||
node = avl_get_prev(node);
|
node = avl_get_prev(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Printing tree...\n");
|
printf("Printing tree...\n");
|
||||||
avl_print_tree(tree, _printer);
|
avl_print_tree(tree, _printer);
|
||||||
|
|
||||||
avl_tree_free(tree, _free);
|
avl_tree_free(tree, _free);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _compare(void *compare_arg, void *a, void *b)
|
int _compare(void *compare_arg, void *a, void *b)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
i = (int)a;
|
i = (int)a;
|
||||||
j = (int)b;
|
j = (int)b;
|
||||||
|
|
||||||
if (i > j)
|
if (i > j)
|
||||||
return 1;
|
return 1;
|
||||||
if (j > i)
|
if (j > i)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _free(void *key)
|
int _free(void *key)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _printer(char *buff, void *key)
|
int _printer(char *buff, void *key)
|
||||||
{
|
{
|
||||||
return snprintf(buff, 25, "%d", (int)key);
|
return snprintf(buff, 25, "%d", (int)key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
730
httpp/httpp.c
730
httpp/httpp.c
@ -33,50 +33,50 @@ int _free_vars(void *key);
|
|||||||
|
|
||||||
http_parser_t *httpp_create_parser(void)
|
http_parser_t *httpp_create_parser(void)
|
||||||
{
|
{
|
||||||
return (http_parser_t *)malloc(sizeof(http_parser_t));
|
return (http_parser_t *)malloc(sizeof(http_parser_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
|
void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
|
||||||
{
|
{
|
||||||
http_varlist_t *list;
|
http_varlist_t *list;
|
||||||
|
|
||||||
parser->req_type = httpp_req_none;
|
parser->req_type = httpp_req_none;
|
||||||
parser->uri = NULL;
|
parser->uri = NULL;
|
||||||
parser->vars = avl_tree_new(_compare_vars, NULL);
|
parser->vars = avl_tree_new(_compare_vars, NULL);
|
||||||
parser->queryvars = avl_tree_new(_compare_vars, NULL);
|
parser->queryvars = avl_tree_new(_compare_vars, NULL);
|
||||||
|
|
||||||
/* now insert the default variables */
|
/* now insert the default variables */
|
||||||
list = defaults;
|
list = defaults;
|
||||||
while (list != NULL) {
|
while (list != NULL) {
|
||||||
httpp_setvar(parser, list->var.name, list->var.value);
|
httpp_setvar(parser, list->var.name, list->var.value);
|
||||||
list = list->next;
|
list = list->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int split_headers(char *data, unsigned long len, char **line)
|
static int split_headers(char *data, unsigned long len, char **line)
|
||||||
{
|
{
|
||||||
/* first we count how many lines there are
|
/* first we count how many lines there are
|
||||||
** and set up the line[] array
|
** and set up the line[] array
|
||||||
*/
|
*/
|
||||||
int lines = 0;
|
int lines = 0;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
line[lines] = data;
|
line[lines] = data;
|
||||||
for (i = 0; i < len && lines < MAX_HEADERS; i++) {
|
for (i = 0; i < len && lines < MAX_HEADERS; i++) {
|
||||||
if (data[i] == '\r')
|
if (data[i] == '\r')
|
||||||
data[i] = '\0';
|
data[i] = '\0';
|
||||||
if (data[i] == '\n') {
|
if (data[i] == '\n') {
|
||||||
lines++;
|
lines++;
|
||||||
data[i] = '\0';
|
data[i] = '\0';
|
||||||
if (i + 1 < len) {
|
if (i + 1 < len) {
|
||||||
if (data[i + 1] == '\n' || data[i + 1] == '\r')
|
if (data[i + 1] == '\n' || data[i + 1] == '\r')
|
||||||
break;
|
break;
|
||||||
line[lines] = &data[i + 1];
|
line[lines] = &data[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
while (data[i] == '\n') i++;
|
while (data[i] == '\n') i++;
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
@ -84,194 +84,194 @@ static int split_headers(char *data, unsigned long len, char **line)
|
|||||||
static void parse_headers(http_parser_t *parser, char **line, int lines)
|
static void parse_headers(http_parser_t *parser, char **line, int lines)
|
||||||
{
|
{
|
||||||
int i,l;
|
int i,l;
|
||||||
int whitespace, where, slen;
|
int whitespace, where, slen;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
char *value = NULL;
|
char *value = NULL;
|
||||||
|
|
||||||
/* parse the name: value lines. */
|
/* parse the name: value lines. */
|
||||||
for (l = 1; l < lines; l++) {
|
for (l = 1; l < lines; l++) {
|
||||||
where = 0;
|
where = 0;
|
||||||
whitespace = 0;
|
whitespace = 0;
|
||||||
name = line[l];
|
name = line[l];
|
||||||
value = NULL;
|
value = NULL;
|
||||||
slen = strlen(line[l]);
|
slen = strlen(line[l]);
|
||||||
for (i = 0; i < slen; i++) {
|
for (i = 0; i < slen; i++) {
|
||||||
if (line[l][i] == ':') {
|
if (line[l][i] == ':') {
|
||||||
whitespace = 1;
|
whitespace = 1;
|
||||||
line[l][i] = '\0';
|
line[l][i] = '\0';
|
||||||
} else {
|
} else {
|
||||||
if (whitespace) {
|
if (whitespace) {
|
||||||
whitespace = 0;
|
whitespace = 0;
|
||||||
while (i < slen && line[l][i] == ' ')
|
while (i < slen && line[l][i] == ' ')
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (i < slen)
|
if (i < slen)
|
||||||
value = &line[l][i];
|
value = &line[l][i];
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != NULL && value != NULL) {
|
if (name != NULL && value != NULL) {
|
||||||
httpp_setvar(parser, _lowercase(name), value);
|
httpp_setvar(parser, _lowercase(name), value);
|
||||||
name = NULL;
|
name = NULL;
|
||||||
value = NULL;
|
value = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int httpp_parse_response(http_parser_t *parser, char *http_data, unsigned long len, char *uri)
|
int httpp_parse_response(http_parser_t *parser, char *http_data, unsigned long len, char *uri)
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
char *line[MAX_HEADERS];
|
char *line[MAX_HEADERS];
|
||||||
int lines, slen,i, whitespace=0, where=0,code;
|
int lines, slen,i, whitespace=0, where=0,code;
|
||||||
char *version=NULL, *resp_code=NULL, *message=NULL;
|
char *version=NULL, *resp_code=NULL, *message=NULL;
|
||||||
|
|
||||||
if(http_data == NULL)
|
if(http_data == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* make a local copy of the data, including 0 terminator */
|
/* make a local copy of the data, including 0 terminator */
|
||||||
data = (char *)malloc(len+1);
|
data = (char *)malloc(len+1);
|
||||||
if (data == NULL) return 0;
|
if (data == NULL) return 0;
|
||||||
memcpy(data, http_data, len);
|
memcpy(data, http_data, len);
|
||||||
data[len] = 0;
|
data[len] = 0;
|
||||||
|
|
||||||
lines = split_headers(data, len, line);
|
lines = split_headers(data, len, line);
|
||||||
|
|
||||||
/* In this case, the first line contains:
|
/* In this case, the first line contains:
|
||||||
* VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
|
* VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
|
||||||
*/
|
*/
|
||||||
slen = strlen(line[0]);
|
slen = strlen(line[0]);
|
||||||
version = line[0];
|
version = line[0];
|
||||||
for(i=0; i < slen; i++) {
|
for(i=0; i < slen; i++) {
|
||||||
if(line[0][i] == ' ') {
|
if(line[0][i] == ' ') {
|
||||||
line[0][i] = 0;
|
line[0][i] = 0;
|
||||||
whitespace = 1;
|
whitespace = 1;
|
||||||
} else if(whitespace) {
|
} else if(whitespace) {
|
||||||
whitespace = 0;
|
whitespace = 0;
|
||||||
where++;
|
where++;
|
||||||
if(where == 1)
|
if(where == 1)
|
||||||
resp_code = &line[0][i];
|
resp_code = &line[0][i];
|
||||||
else {
|
else {
|
||||||
message = &line[0][i];
|
message = &line[0][i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(version == NULL || resp_code == NULL || message == NULL) {
|
if(version == NULL || resp_code == NULL || message == NULL) {
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
|
httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
|
||||||
code = atoi(resp_code);
|
code = atoi(resp_code);
|
||||||
if(code < 200 || code >= 300) {
|
if(code < 200 || code >= 300) {
|
||||||
httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
|
httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
httpp_setvar(parser, HTTPP_VAR_URI, uri);
|
httpp_setvar(parser, HTTPP_VAR_URI, uri);
|
||||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");
|
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");
|
||||||
|
|
||||||
parse_headers(parser, line, lines);
|
parse_headers(parser, line, lines);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hex(char c)
|
static int hex(char c)
|
||||||
{
|
{
|
||||||
if(c >= '0' && c <= '9')
|
if(c >= '0' && c <= '9')
|
||||||
return c - '0';
|
return c - '0';
|
||||||
else if(c >= 'A' && c <= 'F')
|
else if(c >= 'A' && c <= 'F')
|
||||||
return c - 'A' + 10;
|
return c - 'A' + 10;
|
||||||
else if(c >= 'a' && c <= 'f')
|
else if(c >= 'a' && c <= 'f')
|
||||||
return c - 'a' + 10;
|
return c - 'a' + 10;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *url_escape(char *src)
|
static char *url_escape(char *src)
|
||||||
{
|
{
|
||||||
int len = strlen(src);
|
int len = strlen(src);
|
||||||
unsigned char *decoded;
|
unsigned char *decoded;
|
||||||
int i;
|
int i;
|
||||||
char *dst;
|
char *dst;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
|
||||||
decoded = calloc(1, len + 1);
|
decoded = calloc(1, len + 1);
|
||||||
|
|
||||||
dst = decoded;
|
dst = decoded;
|
||||||
|
|
||||||
for(i=0; i < len; i++) {
|
for(i=0; i < len; i++) {
|
||||||
switch(src[i]) {
|
switch(src[i]) {
|
||||||
case '%':
|
case '%':
|
||||||
if(i+2 >= len) {
|
if(i+2 >= len) {
|
||||||
free(decoded);
|
free(decoded);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
|
if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
|
||||||
free(decoded);
|
free(decoded);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst++ = hex(src[i+1]) * 16 + hex(src[i+2]);
|
*dst++ = hex(src[i+1]) * 16 + hex(src[i+2]);
|
||||||
i+= 2;
|
i+= 2;
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
done = 1;
|
done = 1;
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
free(decoded);
|
free(decoded);
|
||||||
return NULL;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*dst++ = src[i];
|
*dst++ = src[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(done)
|
if(done)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst = 0; /* null terminator */
|
*dst = 0; /* null terminator */
|
||||||
|
|
||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** TODO: This is almost certainly buggy in some cases */
|
/** TODO: This is almost certainly buggy in some cases */
|
||||||
static void parse_query(http_parser_t *parser, char *query)
|
static void parse_query(http_parser_t *parser, char *query)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
int i=0;
|
int i=0;
|
||||||
char *key = query;
|
char *key = query;
|
||||||
char *val=NULL;
|
char *val=NULL;
|
||||||
|
|
||||||
if(!query || !*query)
|
if(!query || !*query)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
len = strlen(query);
|
len = strlen(query);
|
||||||
|
|
||||||
while(i<len) {
|
while(i<len) {
|
||||||
switch(query[i]) {
|
switch(query[i]) {
|
||||||
case '&':
|
case '&':
|
||||||
query[i] = 0;
|
query[i] = 0;
|
||||||
if(val && key)
|
if(val && key)
|
||||||
httpp_set_query_param(parser, key, val);
|
httpp_set_query_param(parser, key, val);
|
||||||
key = query+i+1;
|
key = query+i+1;
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
query[i] = 0;
|
query[i] = 0;
|
||||||
val = query+i+1;
|
val = query+i+1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(val && key) {
|
if(val && key) {
|
||||||
httpp_set_query_param(parser, key, val);
|
httpp_set_query_param(parser, key, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The old shoutcast procotol. Don't look at this, it's really nasty */
|
/* The old shoutcast procotol. Don't look at this, it's really nasty */
|
||||||
@ -288,7 +288,7 @@ int httpp_parse_icy(http_parser_t *parser, char *http_data, unsigned long len)
|
|||||||
memcpy(data, http_data, len);
|
memcpy(data, http_data, len);
|
||||||
data[len] = 0;
|
data[len] = 0;
|
||||||
|
|
||||||
lines = split_headers(data, len, line);
|
lines = split_headers(data, len, line);
|
||||||
|
|
||||||
/* Now, this protocol looks like:
|
/* Now, this protocol looks like:
|
||||||
* sourcepassword\n
|
* sourcepassword\n
|
||||||
@ -313,261 +313,261 @@ int httpp_parse_icy(http_parser_t *parser, char *http_data, unsigned long len)
|
|||||||
|
|
||||||
int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len)
|
int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len)
|
||||||
{
|
{
|
||||||
char *data, *tmp;
|
char *data, *tmp;
|
||||||
char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
|
char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
|
||||||
int i;
|
int i;
|
||||||
int lines;
|
int lines;
|
||||||
char *req_type = NULL;
|
char *req_type = NULL;
|
||||||
char *uri = NULL;
|
char *uri = NULL;
|
||||||
char *version = NULL;
|
char *version = NULL;
|
||||||
int whitespace, where, slen;
|
int whitespace, where, slen;
|
||||||
|
|
||||||
if (http_data == NULL)
|
if (http_data == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* make a local copy of the data, including 0 terminator */
|
/* make a local copy of the data, including 0 terminator */
|
||||||
data = (char *)malloc(len+1);
|
data = (char *)malloc(len+1);
|
||||||
if (data == NULL) return 0;
|
if (data == NULL) return 0;
|
||||||
memcpy(data, http_data, len);
|
memcpy(data, http_data, len);
|
||||||
data[len] = 0;
|
data[len] = 0;
|
||||||
|
|
||||||
lines = split_headers(data, len, line);
|
lines = split_headers(data, len, line);
|
||||||
|
|
||||||
/* parse the first line special
|
/* parse the first line special
|
||||||
** the format is:
|
** the format is:
|
||||||
** REQ_TYPE URI VERSION
|
** REQ_TYPE URI VERSION
|
||||||
** eg:
|
** eg:
|
||||||
** GET /index.html HTTP/1.0
|
** GET /index.html HTTP/1.0
|
||||||
*/
|
*/
|
||||||
where = 0;
|
where = 0;
|
||||||
whitespace = 0;
|
whitespace = 0;
|
||||||
slen = strlen(line[0]);
|
slen = strlen(line[0]);
|
||||||
req_type = line[0];
|
req_type = line[0];
|
||||||
for (i = 0; i < slen; i++) {
|
for (i = 0; i < slen; i++) {
|
||||||
if (line[0][i] == ' ') {
|
if (line[0][i] == ' ') {
|
||||||
whitespace = 1;
|
whitespace = 1;
|
||||||
line[0][i] = '\0';
|
line[0][i] = '\0';
|
||||||
} else {
|
} else {
|
||||||
/* we're just past the whitespace boundry */
|
/* we're just past the whitespace boundry */
|
||||||
if (whitespace) {
|
if (whitespace) {
|
||||||
whitespace = 0;
|
whitespace = 0;
|
||||||
where++;
|
where++;
|
||||||
switch (where) {
|
switch (where) {
|
||||||
case 1:
|
case 1:
|
||||||
uri = &line[0][i];
|
uri = &line[0][i];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
version = &line[0][i];
|
version = &line[0][i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp("GET", req_type) == 0) {
|
if (strcasecmp("GET", req_type) == 0) {
|
||||||
parser->req_type = httpp_req_get;
|
parser->req_type = httpp_req_get;
|
||||||
} else if (strcasecmp("POST", req_type) == 0) {
|
} else if (strcasecmp("POST", req_type) == 0) {
|
||||||
parser->req_type = httpp_req_post;
|
parser->req_type = httpp_req_post;
|
||||||
} else if (strcasecmp("HEAD", req_type) == 0) {
|
} else if (strcasecmp("HEAD", req_type) == 0) {
|
||||||
parser->req_type = httpp_req_head;
|
parser->req_type = httpp_req_head;
|
||||||
} else if (strcasecmp("SOURCE", req_type) == 0) {
|
} else if (strcasecmp("SOURCE", req_type) == 0) {
|
||||||
parser->req_type = httpp_req_source;
|
parser->req_type = httpp_req_source;
|
||||||
} else if (strcasecmp("PLAY", req_type) == 0) {
|
} else if (strcasecmp("PLAY", req_type) == 0) {
|
||||||
parser->req_type = httpp_req_play;
|
parser->req_type = httpp_req_play;
|
||||||
} else if (strcasecmp("STATS", req_type) == 0) {
|
} else if (strcasecmp("STATS", req_type) == 0) {
|
||||||
parser->req_type = httpp_req_stats;
|
parser->req_type = httpp_req_stats;
|
||||||
} else {
|
} else {
|
||||||
parser->req_type = httpp_req_unknown;
|
parser->req_type = httpp_req_unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri != NULL && strlen(uri) > 0) {
|
if (uri != NULL && strlen(uri) > 0) {
|
||||||
char *query;
|
char *query;
|
||||||
if((query = strchr(uri, '?')) != NULL) {
|
if((query = strchr(uri, '?')) != NULL) {
|
||||||
*query = 0;
|
*query = 0;
|
||||||
query++;
|
query++;
|
||||||
parse_query(parser, query);
|
parse_query(parser, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser->uri = strdup(uri);
|
parser->uri = strdup(uri);
|
||||||
} else {
|
} else {
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
|
if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
|
||||||
tmp[0] = '\0';
|
tmp[0] = '\0';
|
||||||
if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
|
if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
|
||||||
httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
|
httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
|
||||||
httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
|
httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
|
||||||
} else {
|
} else {
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
|
if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
|
||||||
switch (parser->req_type) {
|
switch (parser->req_type) {
|
||||||
case httpp_req_get:
|
case httpp_req_get:
|
||||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
|
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
|
||||||
break;
|
break;
|
||||||
case httpp_req_post:
|
case httpp_req_post:
|
||||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
|
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
|
||||||
break;
|
break;
|
||||||
case httpp_req_head:
|
case httpp_req_head:
|
||||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
|
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
|
||||||
break;
|
break;
|
||||||
case httpp_req_source:
|
case httpp_req_source:
|
||||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
|
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
|
||||||
break;
|
break;
|
||||||
case httpp_req_play:
|
case httpp_req_play:
|
||||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
|
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
|
||||||
break;
|
break;
|
||||||
case httpp_req_stats:
|
case httpp_req_stats:
|
||||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
|
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser->uri != NULL) {
|
if (parser->uri != NULL) {
|
||||||
httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
|
httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
|
||||||
} else {
|
} else {
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_headers(parser, line, lines);
|
parse_headers(parser, line, lines);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpp_setvar(http_parser_t *parser, char *name, char *value)
|
void httpp_setvar(http_parser_t *parser, char *name, char *value)
|
||||||
{
|
{
|
||||||
http_var_t *var;
|
http_var_t *var;
|
||||||
|
|
||||||
if (name == NULL || value == NULL)
|
if (name == NULL || value == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var = (http_var_t *)malloc(sizeof(http_var_t));
|
var = (http_var_t *)malloc(sizeof(http_var_t));
|
||||||
if (var == NULL) return;
|
if (var == NULL) return;
|
||||||
|
|
||||||
var->name = strdup(name);
|
var->name = strdup(name);
|
||||||
var->value = strdup(value);
|
var->value = strdup(value);
|
||||||
|
|
||||||
if (httpp_getvar(parser, name) == NULL) {
|
if (httpp_getvar(parser, name) == NULL) {
|
||||||
avl_insert(parser->vars, (void *)var);
|
avl_insert(parser->vars, (void *)var);
|
||||||
} else {
|
} else {
|
||||||
avl_delete(parser->vars, (void *)var, _free_vars);
|
avl_delete(parser->vars, (void *)var, _free_vars);
|
||||||
avl_insert(parser->vars, (void *)var);
|
avl_insert(parser->vars, (void *)var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *httpp_getvar(http_parser_t *parser, char *name)
|
char *httpp_getvar(http_parser_t *parser, char *name)
|
||||||
{
|
{
|
||||||
http_var_t var;
|
http_var_t var;
|
||||||
http_var_t *found;
|
http_var_t *found;
|
||||||
|
|
||||||
var.name = name;
|
var.name = name;
|
||||||
var.value = NULL;
|
var.value = NULL;
|
||||||
|
|
||||||
if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0)
|
if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0)
|
||||||
return found->value;
|
return found->value;
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpp_set_query_param(http_parser_t *parser, char *name, char *value)
|
void httpp_set_query_param(http_parser_t *parser, char *name, char *value)
|
||||||
{
|
{
|
||||||
http_var_t *var;
|
http_var_t *var;
|
||||||
|
|
||||||
if (name == NULL || value == NULL)
|
if (name == NULL || value == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var = (http_var_t *)malloc(sizeof(http_var_t));
|
var = (http_var_t *)malloc(sizeof(http_var_t));
|
||||||
if (var == NULL) return;
|
if (var == NULL) return;
|
||||||
|
|
||||||
var->name = strdup(name);
|
var->name = strdup(name);
|
||||||
var->value = url_escape(value);
|
var->value = url_escape(value);
|
||||||
|
|
||||||
if (httpp_get_query_param(parser, name) == NULL) {
|
if (httpp_get_query_param(parser, name) == NULL) {
|
||||||
avl_insert(parser->queryvars, (void *)var);
|
avl_insert(parser->queryvars, (void *)var);
|
||||||
} else {
|
} else {
|
||||||
avl_delete(parser->queryvars, (void *)var, _free_vars);
|
avl_delete(parser->queryvars, (void *)var, _free_vars);
|
||||||
avl_insert(parser->queryvars, (void *)var);
|
avl_insert(parser->queryvars, (void *)var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *httpp_get_query_param(http_parser_t *parser, char *name)
|
char *httpp_get_query_param(http_parser_t *parser, char *name)
|
||||||
{
|
{
|
||||||
http_var_t var;
|
http_var_t var;
|
||||||
http_var_t *found;
|
http_var_t *found;
|
||||||
|
|
||||||
var.name = name;
|
var.name = name;
|
||||||
var.value = NULL;
|
var.value = NULL;
|
||||||
|
|
||||||
if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0)
|
if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0)
|
||||||
return found->value;
|
return found->value;
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpp_clear(http_parser_t *parser)
|
void httpp_clear(http_parser_t *parser)
|
||||||
{
|
{
|
||||||
parser->req_type = httpp_req_none;
|
parser->req_type = httpp_req_none;
|
||||||
if (parser->uri)
|
if (parser->uri)
|
||||||
free(parser->uri);
|
free(parser->uri);
|
||||||
parser->uri = NULL;
|
parser->uri = NULL;
|
||||||
avl_tree_free(parser->vars, _free_vars);
|
avl_tree_free(parser->vars, _free_vars);
|
||||||
avl_tree_free(parser->queryvars, _free_vars);
|
avl_tree_free(parser->queryvars, _free_vars);
|
||||||
parser->vars = NULL;
|
parser->vars = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpp_destroy(http_parser_t *parser)
|
void httpp_destroy(http_parser_t *parser)
|
||||||
{
|
{
|
||||||
httpp_clear(parser);
|
httpp_clear(parser);
|
||||||
free(parser);
|
free(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *_lowercase(char *str)
|
char *_lowercase(char *str)
|
||||||
{
|
{
|
||||||
long i;
|
long i;
|
||||||
for (i = 0; i < strlen(str); i++)
|
for (i = 0; i < strlen(str); i++)
|
||||||
str[i] = tolower(str[i]);
|
str[i] = tolower(str[i]);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _compare_vars(void *compare_arg, void *a, void *b)
|
int _compare_vars(void *compare_arg, void *a, void *b)
|
||||||
{
|
{
|
||||||
http_var_t *vara, *varb;
|
http_var_t *vara, *varb;
|
||||||
|
|
||||||
vara = (http_var_t *)a;
|
vara = (http_var_t *)a;
|
||||||
varb = (http_var_t *)b;
|
varb = (http_var_t *)b;
|
||||||
|
|
||||||
return strcmp(vara->name, varb->name);
|
return strcmp(vara->name, varb->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _free_vars(void *key)
|
int _free_vars(void *key)
|
||||||
{
|
{
|
||||||
http_var_t *var;
|
http_var_t *var;
|
||||||
|
|
||||||
var = (http_var_t *)key;
|
var = (http_var_t *)key;
|
||||||
|
|
||||||
if (var->name)
|
if (var->name)
|
||||||
free(var->name);
|
free(var->name);
|
||||||
if (var->value)
|
if (var->value)
|
||||||
free(var->value);
|
free(var->value);
|
||||||
free(var);
|
free(var);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,25 +17,25 @@
|
|||||||
#define HTTPP_VAR_ICYPASSWORD "__icy_password"
|
#define HTTPP_VAR_ICYPASSWORD "__icy_password"
|
||||||
|
|
||||||
typedef enum httpp_request_type_tag {
|
typedef enum httpp_request_type_tag {
|
||||||
httpp_req_none, httpp_req_get, httpp_req_post, httpp_req_head,
|
httpp_req_none, httpp_req_get, httpp_req_post, httpp_req_head,
|
||||||
httpp_req_source, httpp_req_play, httpp_req_stats, httpp_req_unknown
|
httpp_req_source, httpp_req_play, httpp_req_stats, httpp_req_unknown
|
||||||
} httpp_request_type_e;
|
} httpp_request_type_e;
|
||||||
|
|
||||||
typedef struct http_var_tag {
|
typedef struct http_var_tag {
|
||||||
char *name;
|
char *name;
|
||||||
char *value;
|
char *value;
|
||||||
} http_var_t;
|
} http_var_t;
|
||||||
|
|
||||||
typedef struct http_varlist_tag {
|
typedef struct http_varlist_tag {
|
||||||
http_var_t var;
|
http_var_t var;
|
||||||
struct http_varlist_tag *next;
|
struct http_varlist_tag *next;
|
||||||
} http_varlist_t;
|
} http_varlist_t;
|
||||||
|
|
||||||
typedef struct http_parser_tag {
|
typedef struct http_parser_tag {
|
||||||
httpp_request_type_e req_type;
|
httpp_request_type_e req_type;
|
||||||
char *uri;
|
char *uri;
|
||||||
avl_tree *vars;
|
avl_tree *vars;
|
||||||
avl_tree *queryvars;
|
avl_tree *queryvars;
|
||||||
} http_parser_t;
|
} http_parser_t;
|
||||||
|
|
||||||
http_parser_t *httpp_create_parser(void);
|
http_parser_t *httpp_create_parser(void);
|
||||||
|
82
httpp/test.c
82
httpp/test.c
@ -6,54 +6,54 @@
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char buff[8192];
|
char buff[8192];
|
||||||
int readed;
|
int readed;
|
||||||
http_parser_t parser;
|
http_parser_t parser;
|
||||||
avl_node *node;
|
avl_node *node;
|
||||||
http_var_t *var;
|
http_var_t *var;
|
||||||
|
|
||||||
httpp_initialize(&parser, NULL);
|
httpp_initialize(&parser, NULL);
|
||||||
|
|
||||||
readed = fread(buff, 1, 8192, stdin);
|
readed = fread(buff, 1, 8192, stdin);
|
||||||
if (httpp_parse(&parser, buff, readed)) {
|
if (httpp_parse(&parser, buff, readed)) {
|
||||||
printf("Parse succeeded...\n\n");
|
printf("Parse succeeded...\n\n");
|
||||||
printf("Request was ");
|
printf("Request was ");
|
||||||
switch (parser.req_type) {
|
switch (parser.req_type) {
|
||||||
case httpp_req_none:
|
case httpp_req_none:
|
||||||
printf(" none\n");
|
printf(" none\n");
|
||||||
break;
|
break;
|
||||||
case httpp_req_unknown:
|
case httpp_req_unknown:
|
||||||
printf(" unknown\n");
|
printf(" unknown\n");
|
||||||
break;
|
break;
|
||||||
case httpp_req_get:
|
case httpp_req_get:
|
||||||
printf(" get\n");
|
printf(" get\n");
|
||||||
break;
|
break;
|
||||||
case httpp_req_post:
|
case httpp_req_post:
|
||||||
printf(" post\n");
|
printf(" post\n");
|
||||||
break;
|
break;
|
||||||
case httpp_req_head:
|
case httpp_req_head:
|
||||||
printf(" head\n");
|
printf(" head\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
printf("Version was 1.%d\n", parser.version);
|
printf("Version was 1.%d\n", parser.version);
|
||||||
|
|
||||||
node = avl_get_first(parser.vars);
|
node = avl_get_first(parser.vars);
|
||||||
while (node) {
|
while (node) {
|
||||||
var = (http_var_t *)node->key;
|
var = (http_var_t *)node->key;
|
||||||
|
|
||||||
if (var)
|
if (var)
|
||||||
printf("Iterating variable(s): %s = %s\n", var->name, var->value);
|
printf("Iterating variable(s): %s = %s\n", var->name, var->value);
|
||||||
|
|
||||||
node = avl_get_next(node);
|
node = avl_get_next(node);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("Parse failed...\n");
|
printf("Parse failed...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Destroying parser...\n");
|
printf("Destroying parser...\n");
|
||||||
httpp_destroy(&parser);
|
httpp_destroy(&parser);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
192
log/log.c
192
log/log.c
@ -28,12 +28,12 @@ static int _initialized = 0;
|
|||||||
|
|
||||||
typedef struct log_tag
|
typedef struct log_tag
|
||||||
{
|
{
|
||||||
int in_use;
|
int in_use;
|
||||||
|
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
char *filename;
|
char *filename;
|
||||||
FILE *logfile;
|
FILE *logfile;
|
||||||
|
|
||||||
char *buffer;
|
char *buffer;
|
||||||
} log_t;
|
} log_t;
|
||||||
@ -47,26 +47,26 @@ static void _unlock_logger();
|
|||||||
|
|
||||||
void log_initialize()
|
void log_initialize()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (_initialized) return;
|
if (_initialized) return;
|
||||||
|
|
||||||
for (i = 0; i < LOG_MAXLOGS; i++) {
|
for (i = 0; i < LOG_MAXLOGS; i++) {
|
||||||
loglist[i].in_use = 0;
|
loglist[i].in_use = 0;
|
||||||
loglist[i].level = 2;
|
loglist[i].level = 2;
|
||||||
loglist[i].filename = NULL;
|
loglist[i].filename = NULL;
|
||||||
loglist[i].logfile = NULL;
|
loglist[i].logfile = NULL;
|
||||||
loglist[i].buffer = NULL;
|
loglist[i].buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize mutexes */
|
/* initialize mutexes */
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_init(&_logger_mutex, NULL);
|
pthread_mutex_init(&_logger_mutex, NULL);
|
||||||
#else
|
#else
|
||||||
InitializeCriticalSection(&_logger_mutex);
|
InitializeCriticalSection(&_logger_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_initialized = 1;
|
_initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int log_open_file(FILE *file)
|
int log_open_file(FILE *file)
|
||||||
@ -75,34 +75,34 @@ int log_open_file(FILE *file)
|
|||||||
|
|
||||||
if(file == NULL) return LOG_EINSANE;
|
if(file == NULL) return LOG_EINSANE;
|
||||||
|
|
||||||
log_id = _get_log_id();
|
log_id = _get_log_id();
|
||||||
if (log_id < 0) return LOG_ENOMORELOGS;
|
if (log_id < 0) return LOG_ENOMORELOGS;
|
||||||
|
|
||||||
loglist[log_id].logfile = file;
|
loglist[log_id].logfile = file;
|
||||||
if (loglist[log_id].logfile != NULL) {
|
if (loglist[log_id].logfile != NULL) {
|
||||||
loglist[log_id].filename = NULL;
|
loglist[log_id].filename = NULL;
|
||||||
} else {
|
} else {
|
||||||
_release_log_id(log_id);
|
_release_log_id(log_id);
|
||||||
return LOG_ECANTOPEN;
|
return LOG_ECANTOPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
return log_id;
|
return log_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int log_open(const char *filename)
|
int log_open(const char *filename)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
if (filename == NULL) return LOG_EINSANE;
|
if (filename == NULL) return LOG_EINSANE;
|
||||||
if (strcmp(filename, "") == 0) return LOG_EINSANE;
|
if (strcmp(filename, "") == 0) return LOG_EINSANE;
|
||||||
|
|
||||||
file = fopen(filename, "a");
|
file = fopen(filename, "a");
|
||||||
|
|
||||||
ret = log_open_file(file);
|
ret = log_open_file(file);
|
||||||
|
|
||||||
if(ret >= 0)
|
if(ret >= 0)
|
||||||
setvbuf(file, NULL, IO_BUFFER_TYPE, 0);
|
setvbuf(file, NULL, IO_BUFFER_TYPE, 0);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -110,151 +110,151 @@ int log_open(const char *filename)
|
|||||||
|
|
||||||
int log_open_with_buffer(const char *filename, int size)
|
int log_open_with_buffer(const char *filename, int size)
|
||||||
{
|
{
|
||||||
/* not implemented */
|
/* not implemented */
|
||||||
return LOG_ENOTIMPL;
|
return LOG_ENOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_set_level(int log_id, int level)
|
void log_set_level(int log_id, int level)
|
||||||
{
|
{
|
||||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||||
if (loglist[log_id].in_use == 0) return;
|
if (loglist[log_id].in_use == 0) return;
|
||||||
|
|
||||||
loglist[log_id].level = level;
|
loglist[log_id].level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_flush(int log_id)
|
void log_flush(int log_id)
|
||||||
{
|
{
|
||||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||||
if (loglist[log_id].in_use == 0) return;
|
if (loglist[log_id].in_use == 0) return;
|
||||||
|
|
||||||
fflush(loglist[log_id].logfile);
|
fflush(loglist[log_id].logfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_reopen(int log_id)
|
void log_reopen(int log_id)
|
||||||
{
|
{
|
||||||
/* not implemented yet */
|
/* not implemented yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_close(int log_id)
|
void log_close(int log_id)
|
||||||
{
|
{
|
||||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||||
if (loglist[log_id].in_use == 0) return;
|
if (loglist[log_id].in_use == 0) return;
|
||||||
|
|
||||||
loglist[log_id].in_use = 0;
|
loglist[log_id].in_use = 0;
|
||||||
loglist[log_id].level = 2;
|
loglist[log_id].level = 2;
|
||||||
if (loglist[log_id].filename) free(loglist[log_id].filename);
|
if (loglist[log_id].filename) free(loglist[log_id].filename);
|
||||||
if (loglist[log_id].buffer) free(loglist[log_id].buffer);
|
if (loglist[log_id].buffer) free(loglist[log_id].buffer);
|
||||||
fclose(loglist[log_id].logfile);
|
fclose(loglist[log_id].logfile);
|
||||||
loglist[log_id].logfile = NULL;
|
loglist[log_id].logfile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_shutdown()
|
void log_shutdown()
|
||||||
{
|
{
|
||||||
/* destroy mutexes */
|
/* destroy mutexes */
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_destroy(&_logger_mutex);
|
pthread_mutex_destroy(&_logger_mutex);
|
||||||
#else
|
#else
|
||||||
DeleteCriticalSection(&_logger_mutex);
|
DeleteCriticalSection(&_logger_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_initialized = 0;
|
_initialized = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_write(int log_id, int priority, const char *cat, const char *func,
|
void log_write(int log_id, int priority, const char *cat, const char *func,
|
||||||
const char *fmt, ...)
|
const char *fmt, ...)
|
||||||
{
|
{
|
||||||
static char prior[4][5] = { "EROR\0", "WARN\0", "INFO\0", "DBUG\0" };
|
static char prior[4][5] = { "EROR\0", "WARN\0", "INFO\0", "DBUG\0" };
|
||||||
char tyme[128];
|
char tyme[128];
|
||||||
char pre[256];
|
char pre[256];
|
||||||
char line[LOG_MAXLINELEN];
|
char line[LOG_MAXLINELEN];
|
||||||
time_t now;
|
time_t now;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
if (log_id < 0) return;
|
if (log_id < 0) return;
|
||||||
if (log_id > LOG_MAXLOGS) return; /* Bad log number */
|
if (log_id > LOG_MAXLOGS) return; /* Bad log number */
|
||||||
if (loglist[log_id].level < priority) return;
|
if (loglist[log_id].level < priority) return;
|
||||||
if (priority > 4) return; /* Bad priority */
|
if (priority > 4) return; /* Bad priority */
|
||||||
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
||||||
|
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
|
|
||||||
/* localtime() isn't threadsafe, localtime_r isn't portable enough... */
|
/* localtime() isn't threadsafe, localtime_r isn't portable enough... */
|
||||||
_lock_logger();
|
_lock_logger();
|
||||||
strftime(tyme, 128, "[%Y-%m-%d %H:%M:%S]", localtime(&now));
|
strftime(tyme, 128, "[%Y-%m-%d %H:%M:%S]", localtime(&now));
|
||||||
_unlock_logger();
|
_unlock_logger();
|
||||||
|
|
||||||
snprintf(pre, 256, "%s %s%s", prior[priority-1], cat, func);
|
snprintf(pre, 256, "%s %s%s", prior[priority-1], cat, func);
|
||||||
|
|
||||||
fprintf(loglist[log_id].logfile, "%s %s %s\n", tyme, pre, line);
|
fprintf(loglist[log_id].logfile, "%s %s %s\n", tyme, pre, line);
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_write_direct(int log_id, const char *fmt, ...)
|
void log_write_direct(int log_id, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char line[LOG_MAXLINELEN];
|
char line[LOG_MAXLINELEN];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
if (log_id < 0) return;
|
if (log_id < 0) return;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
||||||
fprintf(loglist[log_id].logfile, "%s\n", line);
|
fprintf(loglist[log_id].logfile, "%s\n", line);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
fflush(loglist[log_id].logfile);
|
fflush(loglist[log_id].logfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _get_log_id()
|
int _get_log_id()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int id = -1;
|
int id = -1;
|
||||||
|
|
||||||
/* lock mutex */
|
/* lock mutex */
|
||||||
_lock_logger();
|
_lock_logger();
|
||||||
|
|
||||||
for (i = 0; i < LOG_MAXLOGS; i++)
|
for (i = 0; i < LOG_MAXLOGS; i++)
|
||||||
if (loglist[i].in_use == 0) {
|
if (loglist[i].in_use == 0) {
|
||||||
loglist[i].in_use = 1;
|
loglist[i].in_use = 1;
|
||||||
id = i;
|
id = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unlock mutex */
|
/* unlock mutex */
|
||||||
_unlock_logger();
|
_unlock_logger();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _release_log_id(int log_id)
|
void _release_log_id(int log_id)
|
||||||
{
|
{
|
||||||
/* lock mutex */
|
/* lock mutex */
|
||||||
_lock_logger();
|
_lock_logger();
|
||||||
|
|
||||||
loglist[log_id].in_use = 0;
|
loglist[log_id].in_use = 0;
|
||||||
|
|
||||||
/* unlock mutex */
|
/* unlock mutex */
|
||||||
_unlock_logger();
|
_unlock_logger();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _lock_logger()
|
static void _lock_logger()
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_lock(&_logger_mutex);
|
pthread_mutex_lock(&_logger_mutex);
|
||||||
#else
|
#else
|
||||||
EnterCriticalSection(&_logger_mutex);
|
EnterCriticalSection(&_logger_mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _unlock_logger()
|
static void _unlock_logger()
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_unlock(&_logger_mutex);
|
pthread_mutex_unlock(&_logger_mutex);
|
||||||
#else
|
#else
|
||||||
LeaveCriticalSection(&_logger_mutex);
|
LeaveCriticalSection(&_logger_mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
log/test.c
12
log/test.c
@ -7,15 +7,15 @@
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int lid;
|
int lid;
|
||||||
|
|
||||||
log_initialize();
|
log_initialize();
|
||||||
|
|
||||||
lid = log_open("test.log");
|
lid = log_open("test.log");
|
||||||
|
|
||||||
LOG_ERR(lid, "The log id is %d, damnit...", lid);
|
LOG_ERR(lid, "The log id is %d, damnit...", lid);
|
||||||
|
|
||||||
log_close(lid);
|
log_close(lid);
|
||||||
|
|
||||||
log_shutdown();
|
log_shutdown();
|
||||||
}
|
}
|
||||||
|
286
net/sock.c
286
net/sock.c
@ -47,7 +47,7 @@
|
|||||||
#define ENOTSOCK WSAENOTSOCK
|
#define ENOTSOCK WSAENOTSOCK
|
||||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
#define EALREADY WSAEALREADY
|
#define EALREADY WSAEALREADY
|
||||||
#define socklen_t int
|
#define socklen_t int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
@ -61,11 +61,11 @@
|
|||||||
void sock_initialize(void)
|
void sock_initialize(void)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSADATA wsad;
|
WSADATA wsad;
|
||||||
WSAStartup(0x0101, &wsad);
|
WSAStartup(0x0101, &wsad);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
resolver_initialize();
|
resolver_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sock_shutdown
|
/* sock_shutdown
|
||||||
@ -76,7 +76,7 @@ void sock_initialize(void)
|
|||||||
void sock_shutdown(void)
|
void sock_shutdown(void)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,15 +89,15 @@ void sock_shutdown(void)
|
|||||||
*/
|
*/
|
||||||
char *sock_get_localip(char *buff, int len)
|
char *sock_get_localip(char *buff, int len)
|
||||||
{
|
{
|
||||||
char temp[1024];
|
char temp[1024];
|
||||||
|
|
||||||
if (gethostname(temp, 1024) != 0)
|
if (gethostname(temp, 1024) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (resolver_getip(temp, buff, len))
|
if (resolver_getip(temp, buff, len))
|
||||||
return buff;
|
return buff;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sock_error
|
/* sock_error
|
||||||
@ -107,9 +107,9 @@ char *sock_get_localip(char *buff, int len)
|
|||||||
int sock_error(void)
|
int sock_error(void)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return WSAGetLastError();
|
return WSAGetLastError();
|
||||||
#else
|
#else
|
||||||
return errno;
|
return errno;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,15 +163,15 @@ int sock_valid_socket(sock_t sock)
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int inet_aton(const char *s, struct in_addr *a)
|
int inet_aton(const char *s, struct in_addr *a)
|
||||||
{
|
{
|
||||||
int lsb, b2, b3, msb;
|
int lsb, b2, b3, msb;
|
||||||
|
|
||||||
if (sscanf(s, "%d.%d.%d.%d", &lsb, &b2, &b3, &msb) < 4) {
|
if (sscanf(s, "%d.%d.%d.%d", &lsb, &b2, &b3, &msb) < 4) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a->s_addr = inet_addr(s);
|
a->s_addr = inet_addr(s);
|
||||||
|
|
||||||
return (a->s_addr != INADDR_NONE);
|
return (a->s_addr != INADDR_NONE);
|
||||||
}
|
}
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
@ -184,23 +184,23 @@ int inet_aton(const char *s, struct in_addr *a)
|
|||||||
int sock_set_blocking(sock_t sock, const int block)
|
int sock_set_blocking(sock_t sock, const int block)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int varblock = block;
|
int varblock = block;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((!sock_valid_socket(sock)) || (block < 0) || (block > 1))
|
if ((!sock_valid_socket(sock)) || (block < 0) || (block > 1))
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return ioctlsocket(sock, FIONBIO, &varblock);
|
return ioctlsocket(sock, FIONBIO, &varblock);
|
||||||
#else
|
#else
|
||||||
return fcntl(sock, F_SETFL, (block == SOCK_BLOCK) ? 0 : O_NONBLOCK);
|
return fcntl(sock, F_SETFL, (block == SOCK_BLOCK) ? 0 : O_NONBLOCK);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_set_nolinger(sock_t sock)
|
int sock_set_nolinger(sock_t sock)
|
||||||
{
|
{
|
||||||
struct linger lin = { 0, 0 };
|
struct linger lin = { 0, 0 };
|
||||||
return setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&lin,
|
return setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&lin,
|
||||||
sizeof(struct linger));
|
sizeof(struct linger));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,8 +214,8 @@ int sock_set_nodelay(sock_t sock)
|
|||||||
|
|
||||||
int sock_set_keepalive(sock_t sock)
|
int sock_set_keepalive(sock_t sock)
|
||||||
{
|
{
|
||||||
int keepalive = 1;
|
int keepalive = 1;
|
||||||
return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
|
return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
|
||||||
sizeof(int));
|
sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,9 +226,9 @@ int sock_set_keepalive(sock_t sock)
|
|||||||
int sock_close(sock_t sock)
|
int sock_close(sock_t sock)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return closesocket(sock);
|
return closesocket(sock);
|
||||||
#else
|
#else
|
||||||
return close(sock);
|
return close(sock);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,16 +278,16 @@ ssize_t sock_writev (int sock, const struct iovec *iov, const size_t count)
|
|||||||
*/
|
*/
|
||||||
int sock_write_bytes(sock_t sock, const void *buff, const size_t len)
|
int sock_write_bytes(sock_t sock, const void *buff, const size_t len)
|
||||||
{
|
{
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (!buff) {
|
if (!buff) {
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
} else if (len <= 0) {
|
} else if (len <= 0) {
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
} /*else if (!sock_valid_socket(sock)) {
|
} /*else if (!sock_valid_socket(sock)) {
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
return send(sock, buff, len, 0);
|
return send(sock, buff, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sock_write_string
|
/* sock_write_string
|
||||||
@ -297,7 +297,7 @@ int sock_write_bytes(sock_t sock, const void *buff, const size_t len)
|
|||||||
*/
|
*/
|
||||||
int sock_write_string(sock_t sock, const char *buff)
|
int sock_write_string(sock_t sock, const char *buff)
|
||||||
{
|
{
|
||||||
return (sock_write_bytes(sock, buff, strlen(buff)) > 0);
|
return (sock_write_bytes(sock, buff, strlen(buff)) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sock_write
|
/* sock_write
|
||||||
@ -308,14 +308,14 @@ int sock_write_string(sock_t sock, const char *buff)
|
|||||||
*/
|
*/
|
||||||
int sock_write(sock_t sock, const char *fmt, ...)
|
int sock_write(sock_t sock, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char buff[1024];
|
char buff[1024];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(buff, 1024, fmt, ap);
|
vsnprintf(buff, 1024, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return sock_write_bytes(sock, buff, strlen(buff));
|
return sock_write_bytes(sock, buff, strlen(buff));
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_write_fmt(sock_t sock, char *fmt, va_list ap)
|
int sock_write_fmt(sock_t sock, char *fmt, va_list ap)
|
||||||
@ -330,11 +330,11 @@ int sock_write_fmt(sock_t sock, char *fmt, va_list ap)
|
|||||||
int sock_read_bytes(sock_t sock, char *buff, const int len)
|
int sock_read_bytes(sock_t sock, char *buff, const int len)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*if (!sock_valid_socket(sock)) return 0; */
|
/*if (!sock_valid_socket(sock)) return 0; */
|
||||||
if (!buff) return 0;
|
if (!buff) return 0;
|
||||||
if (len <= 0) return 0;
|
if (len <= 0) return 0;
|
||||||
|
|
||||||
return recv(sock, buff, len, 0);
|
return recv(sock, buff, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sock_read_line
|
/* sock_read_line
|
||||||
@ -347,36 +347,36 @@ int sock_read_bytes(sock_t sock, char *buff, const int len)
|
|||||||
*/
|
*/
|
||||||
int sock_read_line(sock_t sock, char *buff, const int len)
|
int sock_read_line(sock_t sock, char *buff, const int len)
|
||||||
{
|
{
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
int read_bytes, pos;
|
int read_bytes, pos;
|
||||||
|
|
||||||
/*if (!sock_valid_socket(sock)) {
|
/*if (!sock_valid_socket(sock)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else*/ if (!buff) {
|
} else*/ if (!buff) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (len <= 0) {
|
} else if (len <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
read_bytes = recv(sock, &c, 1, 0);
|
read_bytes = recv(sock, &c, 1, 0);
|
||||||
|
|
||||||
if (read_bytes < 0) {
|
if (read_bytes < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((c != '\n') && (pos < len) && (read_bytes == 1)) {
|
while ((c != '\n') && (pos < len) && (read_bytes == 1)) {
|
||||||
if (c != '\r')
|
if (c != '\r')
|
||||||
buff[pos++] = c;
|
buff[pos++] = c;
|
||||||
read_bytes = recv(sock, &c, 1, 0);
|
read_bytes = recv(sock, &c, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_bytes == 1) {
|
if (read_bytes == 1) {
|
||||||
buff[pos] = '\0';
|
buff[pos] = '\0';
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see if a connection can be written to
|
/* see if a connection can be written to
|
||||||
@ -588,99 +588,99 @@ sock_t sock_connect_wto(const char *hostname, const int port, const int timeout)
|
|||||||
sock_t sock_get_server_socket(const int port, char *sinterface)
|
sock_t sock_get_server_socket(const int port, char *sinterface)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
struct sockaddr_storage sa;
|
struct sockaddr_storage sa;
|
||||||
#else
|
#else
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
#endif
|
#endif
|
||||||
int sa_family, sa_len, error, opt;
|
int sa_family, sa_len, error, opt;
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
char ip[MAX_ADDR_LEN];
|
char ip[MAX_ADDR_LEN];
|
||||||
|
|
||||||
if (port < 0)
|
if (port < 0)
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
|
|
||||||
/* defaults */
|
/* defaults */
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa_family = AF_INET;
|
sa_family = AF_INET;
|
||||||
sa_len = sizeof(struct sockaddr_in);
|
sa_len = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
/* set the interface to bind to if specified */
|
/* set the interface to bind to if specified */
|
||||||
if (sinterface != NULL) {
|
if (sinterface != NULL) {
|
||||||
if (!resolver_getip(sinterface, ip, sizeof (ip)))
|
if (!resolver_getip(sinterface, ip, sizeof (ip)))
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (inet_pton(AF_INET, ip, &((struct sockaddr_in*)&sa)->sin_addr) > 0) {
|
if (inet_pton(AF_INET, ip, &((struct sockaddr_in*)&sa)->sin_addr) > 0) {
|
||||||
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
||||||
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
||||||
} else if (inet_pton(AF_INET6, ip,
|
} else if (inet_pton(AF_INET6, ip,
|
||||||
&((struct sockaddr_in6*)&sa)->sin6_addr) > 0) {
|
&((struct sockaddr_in6*)&sa)->sin6_addr) > 0) {
|
||||||
sa_family = AF_INET6;
|
sa_family = AF_INET6;
|
||||||
sa_len = sizeof (struct sockaddr_in6);
|
sa_len = sizeof (struct sockaddr_in6);
|
||||||
((struct sockaddr_in6*)&sa)->sin6_family = AF_INET6;
|
((struct sockaddr_in6*)&sa)->sin6_family = AF_INET6;
|
||||||
((struct sockaddr_in6*)&sa)->sin6_port = htons(port);
|
((struct sockaddr_in6*)&sa)->sin6_port = htons(port);
|
||||||
} else {
|
} else {
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (!inet_aton(ip, &sa.sin_addr)) {
|
if (!inet_aton(ip, &sa.sin_addr)) {
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
} else {
|
} else {
|
||||||
sa.sin_family = AF_INET;
|
sa.sin_family = AF_INET;
|
||||||
sa.sin_port = htons(port);
|
sa.sin_port = htons(port);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
((struct sockaddr_in*)&sa)->sin_addr.s_addr = INADDR_ANY;
|
((struct sockaddr_in*)&sa)->sin_addr.s_addr = INADDR_ANY;
|
||||||
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
||||||
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a socket */
|
/* get a socket */
|
||||||
sock = socket(sa_family, SOCK_STREAM, 0);
|
sock = socket(sa_family, SOCK_STREAM, 0);
|
||||||
if (sock == -1)
|
if (sock == -1)
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
|
|
||||||
/* reuse it if we can */
|
/* reuse it if we can */
|
||||||
opt = 1;
|
opt = 1;
|
||||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(int));
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(int));
|
||||||
|
|
||||||
/* bind socket to port */
|
/* bind socket to port */
|
||||||
error = bind(sock, (struct sockaddr *)&sa, sa_len);
|
error = bind(sock, (struct sockaddr *)&sa, sa_len);
|
||||||
if (error == -1)
|
if (error == -1)
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
|
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_listen(sock_t serversock, int backlog)
|
int sock_listen(sock_t serversock, int backlog)
|
||||||
{
|
{
|
||||||
if (!sock_valid_socket(serversock))
|
if (!sock_valid_socket(serversock))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (backlog <= 0)
|
if (backlog <= 0)
|
||||||
backlog = 10;
|
backlog = 10;
|
||||||
|
|
||||||
return (listen(serversock, backlog) == 0);
|
return (listen(serversock, backlog) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_accept(sock_t serversock, char *ip, int len)
|
int sock_accept(sock_t serversock, char *ip, int len)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
struct sockaddr_storage sa;
|
struct sockaddr_storage sa;
|
||||||
#else
|
#else
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
#endif
|
#endif
|
||||||
int ret;
|
int ret;
|
||||||
socklen_t slen;
|
socklen_t slen;
|
||||||
|
|
||||||
if (!sock_valid_socket(serversock))
|
if (!sock_valid_socket(serversock))
|
||||||
return SOCK_ERROR;
|
return SOCK_ERROR;
|
||||||
|
|
||||||
slen = sizeof(sa);
|
slen = sizeof(sa);
|
||||||
ret = accept(serversock, (struct sockaddr *)&sa, &slen);
|
ret = accept(serversock, (struct sockaddr *)&sa, &slen);
|
||||||
|
|
||||||
if (ret >= 0 && ip != NULL) {
|
if (ret >= 0 && ip != NULL) {
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if(((struct sockaddr_in *)&sa)->sin_family == AF_INET)
|
if(((struct sockaddr_in *)&sa)->sin_family == AF_INET)
|
||||||
inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
|
inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
|
||||||
@ -694,12 +694,12 @@ int sock_accept(sock_t serversock, char *ip, int len)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* inet_ntoa is not reentrant, we should protect this */
|
/* inet_ntoa is not reentrant, we should protect this */
|
||||||
strncpy(ip, inet_ntoa(sa.sin_addr), len);
|
strncpy(ip, inet_ntoa(sa.sin_addr), len);
|
||||||
#endif
|
#endif
|
||||||
sock_set_nolinger(ret);
|
sock_set_nolinger(ret);
|
||||||
sock_set_keepalive(ret);
|
sock_set_keepalive(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
char buff[1024];
|
char buff[1024];
|
||||||
|
|
||||||
resolver_initialize();
|
resolver_initialize();
|
||||||
|
|
||||||
printf("I got %s, when looking up %s.\n", resolver_getip("bach.greenwitch.com", buff, 1024), "bach.greenwitch.com");
|
printf("I got %s, when looking up %s.\n", resolver_getip("bach.greenwitch.com", buff, 1024), "bach.greenwitch.com");
|
||||||
printf("I got %s, when looking up %s.\n", resolver_getname("207.181.249.14", buff, 1024), "207.181.249.14");
|
printf("I got %s, when looking up %s.\n", resolver_getname("207.181.249.14", buff, 1024), "207.181.249.14");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
622
thread/thread.c
622
thread/thread.c
@ -74,18 +74,18 @@
|
|||||||
|
|
||||||
/* thread starting structure */
|
/* thread starting structure */
|
||||||
typedef struct thread_start_tag {
|
typedef struct thread_start_tag {
|
||||||
/* the real start routine and arg */
|
/* the real start routine and arg */
|
||||||
void *(*start_routine)(void *);
|
void *(*start_routine)(void *);
|
||||||
void *arg;
|
void *arg;
|
||||||
|
|
||||||
/* whether to create the threaded in detached state */
|
/* whether to create the threaded in detached state */
|
||||||
int detached;
|
int detached;
|
||||||
|
|
||||||
/* the other stuff we need to make sure this thread is inserted into
|
/* the other stuff we need to make sure this thread is inserted into
|
||||||
** the thread tree
|
** the thread tree
|
||||||
*/
|
*/
|
||||||
thread_type *thread;
|
thread_type *thread;
|
||||||
pthread_t sys_thread;
|
pthread_t sys_thread;
|
||||||
} thread_start_t;
|
} thread_start_t;
|
||||||
|
|
||||||
static long _next_thread_id = 0;
|
static long _next_thread_id = 0;
|
||||||
@ -143,69 +143,69 @@ static void _block_signals(void);
|
|||||||
|
|
||||||
void thread_initialize(void)
|
void thread_initialize(void)
|
||||||
{
|
{
|
||||||
thread_type *thread;
|
thread_type *thread;
|
||||||
|
|
||||||
/* set up logging */
|
/* set up logging */
|
||||||
|
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
log_initialize();
|
log_initialize();
|
||||||
_logid = log_open("thread.log");
|
_logid = log_open("thread.log");
|
||||||
log_set_level(_logid, THREAD_DEBUG);
|
log_set_level(_logid, THREAD_DEBUG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
/* create all the internal mutexes, and initialize the mutex tree */
|
/* create all the internal mutexes, and initialize the mutex tree */
|
||||||
|
|
||||||
_mutextree = avl_tree_new(_compare_mutexes, NULL);
|
_mutextree = avl_tree_new(_compare_mutexes, NULL);
|
||||||
|
|
||||||
/* we have to create this one by hand, because there's no
|
/* we have to create this one by hand, because there's no
|
||||||
** mutextree_mutex to lock yet!
|
** mutextree_mutex to lock yet!
|
||||||
*/
|
*/
|
||||||
_mutex_create(&_mutextree_mutex);
|
_mutex_create(&_mutextree_mutex);
|
||||||
|
|
||||||
_mutextree_mutex.mutex_id = _next_mutex_id++;
|
_mutextree_mutex.mutex_id = _next_mutex_id++;
|
||||||
avl_insert(_mutextree, (void *)&_mutextree_mutex);
|
avl_insert(_mutextree, (void *)&_mutextree_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
thread_mutex_create(&_threadtree_mutex);
|
thread_mutex_create(&_threadtree_mutex);
|
||||||
thread_mutex_create(&_library_mutex);
|
thread_mutex_create(&_library_mutex);
|
||||||
|
|
||||||
/* initialize the thread tree and insert the main thread */
|
/* initialize the thread tree and insert the main thread */
|
||||||
|
|
||||||
_threadtree = avl_tree_new(_compare_threads, NULL);
|
_threadtree = avl_tree_new(_compare_threads, NULL);
|
||||||
|
|
||||||
thread = (thread_type *)malloc(sizeof(thread_type));
|
thread = (thread_type *)malloc(sizeof(thread_type));
|
||||||
|
|
||||||
thread->thread_id = _next_thread_id++;
|
thread->thread_id = _next_thread_id++;
|
||||||
thread->line = 0;
|
thread->line = 0;
|
||||||
thread->file = strdup("main.c");
|
thread->file = strdup("main.c");
|
||||||
thread->sys_thread = pthread_self();
|
thread->sys_thread = pthread_self();
|
||||||
thread->create_time = time(NULL);
|
thread->create_time = time(NULL);
|
||||||
thread->name = strdup("Main Thread");
|
thread->name = strdup("Main Thread");
|
||||||
|
|
||||||
avl_insert(_threadtree, (void *)thread);
|
avl_insert(_threadtree, (void *)thread);
|
||||||
|
|
||||||
_catch_signals();
|
_catch_signals();
|
||||||
|
|
||||||
_initialized = 1;
|
_initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_shutdown(void)
|
void thread_shutdown(void)
|
||||||
{
|
{
|
||||||
if (_initialized == 1) {
|
if (_initialized == 1) {
|
||||||
thread_mutex_destroy(&_library_mutex);
|
thread_mutex_destroy(&_library_mutex);
|
||||||
thread_mutex_destroy(&_threadtree_mutex);
|
thread_mutex_destroy(&_threadtree_mutex);
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
thread_mutex_destroy(&_mutextree_mutex);
|
thread_mutex_destroy(&_mutextree_mutex);
|
||||||
|
|
||||||
avl_tree_free(_mutextree, _free_mutex);
|
avl_tree_free(_mutextree, _free_mutex);
|
||||||
#endif
|
#endif
|
||||||
avl_tree_free(_threadtree, _free_thread);
|
avl_tree_free(_threadtree, _free_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
log_close(_logid);
|
log_close(_logid);
|
||||||
log_shutdown();
|
log_shutdown();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -268,44 +268,44 @@ static void _catch_signals(void)
|
|||||||
thread_type *thread_create_c(char *name, void *(*start_routine)(void *),
|
thread_type *thread_create_c(char *name, void *(*start_routine)(void *),
|
||||||
void *arg, int detached, int line, char *file)
|
void *arg, int detached, int line, char *file)
|
||||||
{
|
{
|
||||||
int created;
|
int created;
|
||||||
thread_type *thread;
|
thread_type *thread;
|
||||||
thread_start_t *start;
|
thread_start_t *start;
|
||||||
|
|
||||||
thread = (thread_type *)malloc(sizeof(thread_type));
|
thread = (thread_type *)malloc(sizeof(thread_type));
|
||||||
start = (thread_start_t *)malloc(sizeof(thread_start_t));
|
start = (thread_start_t *)malloc(sizeof(thread_start_t));
|
||||||
thread->line = line;
|
thread->line = line;
|
||||||
thread->file = strdup(file);
|
thread->file = strdup(file);
|
||||||
|
|
||||||
_mutex_lock(&_threadtree_mutex);
|
_mutex_lock(&_threadtree_mutex);
|
||||||
thread->thread_id = _next_thread_id++;
|
thread->thread_id = _next_thread_id++;
|
||||||
_mutex_unlock(&_threadtree_mutex);
|
_mutex_unlock(&_threadtree_mutex);
|
||||||
|
|
||||||
thread->name = strdup(name);
|
thread->name = strdup(name);
|
||||||
thread->create_time = time(NULL);
|
thread->create_time = time(NULL);
|
||||||
thread->detached = 0;
|
thread->detached = 0;
|
||||||
|
|
||||||
start->start_routine = start_routine;
|
start->start_routine = start_routine;
|
||||||
start->arg = arg;
|
start->arg = arg;
|
||||||
start->thread = thread;
|
start->thread = thread;
|
||||||
start->detached = detached;
|
start->detached = detached;
|
||||||
|
|
||||||
created = 0;
|
created = 0;
|
||||||
if (pthread_create(&thread->sys_thread, NULL, _start_routine, start) == 0)
|
if (pthread_create(&thread->sys_thread, NULL, _start_routine, start) == 0)
|
||||||
created = 1;
|
created = 1;
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
else
|
else
|
||||||
LOG_ERROR("Could not create new thread");
|
LOG_ERROR("Could not create new thread");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (created == 0) {
|
if (created == 0) {
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
LOG_ERROR("System won't let me create more threads, giving up");
|
LOG_ERROR("System won't let me create more threads, giving up");
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _mutex_create
|
/* _mutex_create
|
||||||
@ -315,193 +315,193 @@ thread_type *thread_create_c(char *name, void *(*start_routine)(void *),
|
|||||||
static void _mutex_create(mutex_t *mutex)
|
static void _mutex_create(mutex_t *mutex)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
mutex->thread_id = MUTEX_STATE_NEVERLOCKED;
|
mutex->thread_id = MUTEX_STATE_NEVERLOCKED;
|
||||||
mutex->line = -1;
|
mutex->line = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_init(&mutex->sys_mutex, NULL);
|
pthread_mutex_init(&mutex->sys_mutex, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_mutex_create_c(mutex_t *mutex, int line, char *file)
|
void thread_mutex_create_c(mutex_t *mutex, int line, char *file)
|
||||||
{
|
{
|
||||||
_mutex_create(mutex);
|
_mutex_create(mutex);
|
||||||
|
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
_mutex_lock(&_mutextree_mutex);
|
_mutex_lock(&_mutextree_mutex);
|
||||||
mutex->mutex_id = _next_mutex_id++;
|
mutex->mutex_id = _next_mutex_id++;
|
||||||
avl_insert(_mutextree, (void *)mutex);
|
avl_insert(_mutextree, (void *)mutex);
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_mutex_destroy (mutex_t *mutex)
|
void thread_mutex_destroy (mutex_t *mutex)
|
||||||
{
|
{
|
||||||
pthread_mutex_destroy(&mutex->sys_mutex);
|
pthread_mutex_destroy(&mutex->sys_mutex);
|
||||||
|
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
_mutex_lock(&_mutextree_mutex);
|
_mutex_lock(&_mutextree_mutex);
|
||||||
avl_delete(_mutextree, mutex, _free_mutex);
|
avl_delete(_mutextree, mutex, _free_mutex);
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_mutex_lock_c(mutex_t *mutex, int line, char *file)
|
void thread_mutex_lock_c(mutex_t *mutex, int line, char *file)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
thread_type *th = thread_self();
|
thread_type *th = thread_self();
|
||||||
|
|
||||||
if (!th) LOG_WARN("No mt record for %u in lock [%s:%d]", thread_self(), file, line);
|
if (!th) LOG_WARN("No mt record for %u in lock [%s:%d]", thread_self(), file, line);
|
||||||
|
|
||||||
LOG_DEBUG5("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
LOG_DEBUG5("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
||||||
|
|
||||||
# ifdef CHECK_MUTEXES
|
# ifdef CHECK_MUTEXES
|
||||||
/* Just a little sanity checking to make sure that we're locking
|
/* Just a little sanity checking to make sure that we're locking
|
||||||
** mutexes correctly
|
** mutexes correctly
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (th) {
|
if (th) {
|
||||||
int locks = 0;
|
int locks = 0;
|
||||||
avl_node *node;
|
avl_node *node;
|
||||||
mutex_t *tmutex;
|
mutex_t *tmutex;
|
||||||
|
|
||||||
_mutex_lock(&_mutextree_mutex);
|
_mutex_lock(&_mutextree_mutex);
|
||||||
|
|
||||||
node = avl_get_first (_mutextree);
|
node = avl_get_first (_mutextree);
|
||||||
|
|
||||||
while (node) {
|
while (node) {
|
||||||
tmutex = (mutex_t *)node->key;
|
tmutex = (mutex_t *)node->key;
|
||||||
|
|
||||||
if (tmutex->mutex_id == mutex->mutex_id) {
|
if (tmutex->mutex_id == mutex->mutex_id) {
|
||||||
if (tmutex->thread_id == th->thread_id) {
|
if (tmutex->thread_id == th->thread_id) {
|
||||||
/* Deadlock, same thread can't lock the same mutex twice */
|
/* Deadlock, same thread can't lock the same mutex twice */
|
||||||
LOG_ERROR7("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]",
|
LOG_ERROR7("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]",
|
||||||
tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
||||||
|
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (tmutex->thread_id == th->thread_id) {
|
} else if (tmutex->thread_id == th->thread_id) {
|
||||||
/* Mutex locked by this thread (not this mutex) */
|
/* Mutex locked by this thread (not this mutex) */
|
||||||
locks++;
|
locks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = avl_get_next(node);
|
node = avl_get_next(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locks > 0) {
|
if (locks > 0) {
|
||||||
/* Has already got a mutex locked */
|
/* Has already got a mutex locked */
|
||||||
if (_multi_mutex.thread_id != th->thread_id) {
|
if (_multi_mutex.thread_id != th->thread_id) {
|
||||||
/* Tries to lock two mutexes, but has not got the double mutex, norty boy! */
|
/* Tries to lock two mutexes, but has not got the double mutex, norty boy! */
|
||||||
LOG_WARN("(%d != %d) Thread %d [%s] tries to lock a second mutex [%s] in file %s line %d, without locking double mutex!",
|
LOG_WARN("(%d != %d) Thread %d [%s] tries to lock a second mutex [%s] in file %s line %d, without locking double mutex!",
|
||||||
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
}
|
}
|
||||||
# endif /* CHECK_MUTEXES */
|
# endif /* CHECK_MUTEXES */
|
||||||
|
|
||||||
_mutex_lock(mutex);
|
_mutex_lock(mutex);
|
||||||
|
|
||||||
_mutex_lock(&_mutextree_mutex);
|
_mutex_lock(&_mutextree_mutex);
|
||||||
|
|
||||||
LOG_DEBUG2("Locked %p by thread %d", mutex, th ? th->thread_id : -1);
|
LOG_DEBUG2("Locked %p by thread %d", mutex, th ? th->thread_id : -1);
|
||||||
mutex->line = line;
|
mutex->line = line;
|
||||||
if (th) {
|
if (th) {
|
||||||
mutex->thread_id = th->thread_id;
|
mutex->thread_id = th->thread_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
#else
|
#else
|
||||||
_mutex_lock(mutex);
|
_mutex_lock(mutex);
|
||||||
#endif /* DEBUG_MUTEXES */
|
#endif /* DEBUG_MUTEXES */
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_mutex_unlock_c(mutex_t *mutex, int line, char *file)
|
void thread_mutex_unlock_c(mutex_t *mutex, int line, char *file)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
thread_type *th = thread_self();
|
thread_type *th = thread_self();
|
||||||
|
|
||||||
if (!th) {
|
if (!th) {
|
||||||
LOG_ERROR3("No record for %u in unlock [%s:%d]", thread_self(), file, line);
|
LOG_ERROR3("No record for %u in unlock [%s:%d]", thread_self(), file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG5("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
LOG_DEBUG5("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
||||||
|
|
||||||
mutex->line = line;
|
mutex->line = line;
|
||||||
|
|
||||||
# ifdef CHECK_MUTEXES
|
# ifdef CHECK_MUTEXES
|
||||||
if (th) {
|
if (th) {
|
||||||
int locks = 0;
|
int locks = 0;
|
||||||
avl_node *node;
|
avl_node *node;
|
||||||
mutex_t *tmutex;
|
mutex_t *tmutex;
|
||||||
|
|
||||||
_mutex_lock(&_mutextree_mutex);
|
_mutex_lock(&_mutextree_mutex);
|
||||||
|
|
||||||
while (node) {
|
while (node) {
|
||||||
tmutex = (mutex_t *)node->key;
|
tmutex = (mutex_t *)node->key;
|
||||||
|
|
||||||
if (tmutex->mutex_id == mutex->mutex_id) {
|
if (tmutex->mutex_id == mutex->mutex_id) {
|
||||||
if (tmutex->thread_id != th->thread_id) {
|
if (tmutex->thread_id != th->thread_id) {
|
||||||
LOG_ERROR7("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id,
|
LOG_ERROR7("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id,
|
||||||
mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (tmutex->thread_id == th->thread_id) {
|
} else if (tmutex->thread_id == th->thread_id) {
|
||||||
locks++;
|
locks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = avl_get_next (node);
|
node = avl_get_next (node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((locks > 0) && (_multi_mutex.thread_id != th->thread_id)) {
|
if ((locks > 0) && (_multi_mutex.thread_id != th->thread_id)) {
|
||||||
/* Don't have double mutex, has more than this mutex left */
|
/* Don't have double mutex, has more than this mutex left */
|
||||||
|
|
||||||
LOG_WARN("(%d != %d) Thread %d [%s] tries to unlock a mutex [%s] in file %s line %d, without owning double mutex!",
|
LOG_WARN("(%d != %d) Thread %d [%s] tries to unlock a mutex [%s] in file %s line %d, without owning double mutex!",
|
||||||
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
}
|
}
|
||||||
# endif /* CHECK_MUTEXES */
|
# endif /* CHECK_MUTEXES */
|
||||||
|
|
||||||
_mutex_unlock(mutex);
|
_mutex_unlock(mutex);
|
||||||
|
|
||||||
_mutex_lock(&_mutextree_mutex);
|
_mutex_lock(&_mutextree_mutex);
|
||||||
|
|
||||||
LOG_DEBUG2("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1);
|
LOG_DEBUG2("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1);
|
||||||
mutex->line = -1;
|
mutex->line = -1;
|
||||||
if (mutex->thread_id == th->thread_id) {
|
if (mutex->thread_id == th->thread_id) {
|
||||||
mutex->thread_id = MUTEX_STATE_NOTLOCKED;
|
mutex->thread_id = MUTEX_STATE_NOTLOCKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
#else
|
#else
|
||||||
_mutex_unlock(mutex);
|
_mutex_unlock(mutex);
|
||||||
#endif /* DEBUG_MUTEXES */
|
#endif /* DEBUG_MUTEXES */
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_cond_create_c(cond_t *cond, int line, char *file)
|
void thread_cond_create_c(cond_t *cond, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_cond_init(&cond->sys_cond, NULL);
|
pthread_cond_init(&cond->sys_cond, NULL);
|
||||||
pthread_mutex_init(&cond->cond_mutex, NULL);
|
pthread_mutex_init(&cond->cond_mutex, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_cond_destroy(cond_t *cond)
|
void thread_cond_destroy(cond_t *cond)
|
||||||
{
|
{
|
||||||
pthread_mutex_destroy(&cond->cond_mutex);
|
pthread_mutex_destroy(&cond->cond_mutex);
|
||||||
pthread_cond_destroy(&cond->sys_cond);
|
pthread_cond_destroy(&cond->sys_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_cond_signal_c(cond_t *cond, int line, char *file)
|
void thread_cond_signal_c(cond_t *cond, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_cond_signal(&cond->sys_cond);
|
pthread_cond_signal(&cond->sys_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_cond_broadcast_c(cond_t *cond, int line, char *file)
|
void thread_cond_broadcast_c(cond_t *cond, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_cond_broadcast(&cond->sys_cond);
|
pthread_cond_broadcast(&cond->sys_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file)
|
void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file)
|
||||||
@ -518,223 +518,223 @@ void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file)
|
|||||||
|
|
||||||
void thread_cond_wait_c(cond_t *cond, int line, char *file)
|
void thread_cond_wait_c(cond_t *cond, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&cond->cond_mutex);
|
pthread_mutex_lock(&cond->cond_mutex);
|
||||||
pthread_cond_wait(&cond->sys_cond, &cond->cond_mutex);
|
pthread_cond_wait(&cond->sys_cond, &cond->cond_mutex);
|
||||||
pthread_mutex_unlock(&cond->cond_mutex);
|
pthread_mutex_unlock(&cond->cond_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_rwlock_create_c(rwlock_t *rwlock, int line, char *file)
|
void thread_rwlock_create_c(rwlock_t *rwlock, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_rwlock_init(&rwlock->sys_rwlock, NULL);
|
pthread_rwlock_init(&rwlock->sys_rwlock, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_rwlock_destroy(rwlock_t *rwlock)
|
void thread_rwlock_destroy(rwlock_t *rwlock)
|
||||||
{
|
{
|
||||||
pthread_rwlock_destroy(&rwlock->sys_rwlock);
|
pthread_rwlock_destroy(&rwlock->sys_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_rwlock_rlock_c(rwlock_t *rwlock, int line, char *file)
|
void thread_rwlock_rlock_c(rwlock_t *rwlock, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_rwlock_rdlock(&rwlock->sys_rwlock);
|
pthread_rwlock_rdlock(&rwlock->sys_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_rwlock_wlock_c(rwlock_t *rwlock, int line, char *file)
|
void thread_rwlock_wlock_c(rwlock_t *rwlock, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_rwlock_wrlock(&rwlock->sys_rwlock);
|
pthread_rwlock_wrlock(&rwlock->sys_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_rwlock_unlock_c(rwlock_t *rwlock, int line, char *file)
|
void thread_rwlock_unlock_c(rwlock_t *rwlock, int line, char *file)
|
||||||
{
|
{
|
||||||
pthread_rwlock_unlock(&rwlock->sys_rwlock);
|
pthread_rwlock_unlock(&rwlock->sys_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_exit_c(int val, int line, char *file)
|
void thread_exit_c(int val, int line, char *file)
|
||||||
{
|
{
|
||||||
thread_type *th = thread_self();
|
thread_type *th = thread_self();
|
||||||
|
|
||||||
#if defined(DEBUG_MUTEXES) && defined(CHECK_MUTEXES)
|
#if defined(DEBUG_MUTEXES) && defined(CHECK_MUTEXES)
|
||||||
if (th) {
|
if (th) {
|
||||||
avl_node *node;
|
avl_node *node;
|
||||||
mutex_t *tmutex;
|
mutex_t *tmutex;
|
||||||
char name[40];
|
char name[40];
|
||||||
|
|
||||||
_mutex_lock(&_mutextree_mutex);
|
_mutex_lock(&_mutextree_mutex);
|
||||||
|
|
||||||
while (node) {
|
while (node) {
|
||||||
tmutex = (mutex_t *)node->key;
|
tmutex = (mutex_t *)node->key;
|
||||||
|
|
||||||
if (tmutex->thread_id == th->thread_id) {
|
if (tmutex->thread_id == th->thread_id) {
|
||||||
LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]",
|
LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]",
|
||||||
th->thread_id, th->name, file, line, mutex_to_string(tmutex, name));
|
th->thread_id, th->name, file, line, mutex_to_string(tmutex, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
node = avl_get_next (node);
|
node = avl_get_next (node);
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock(&_mutextree_mutex);
|
_mutex_unlock(&_mutextree_mutex);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (th) {
|
if (th) {
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
LOG_INFO4("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line);
|
LOG_INFO4("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_mutex_lock(&_threadtree_mutex);
|
_mutex_lock(&_threadtree_mutex);
|
||||||
avl_delete(_threadtree, th, _free_thread_if_detached);
|
avl_delete(_threadtree, th, _free_thread_if_detached);
|
||||||
_mutex_unlock(&_threadtree_mutex);
|
_mutex_unlock(&_threadtree_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit((void *)val);
|
pthread_exit((void *)val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sleep for a number of microseconds */
|
/* sleep for a number of microseconds */
|
||||||
void thread_sleep(unsigned long len)
|
void thread_sleep(unsigned long len)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Sleep(len / 1000);
|
Sleep(len / 1000);
|
||||||
#else
|
#else
|
||||||
# ifdef HAVE_NANOSLEEP
|
# ifdef HAVE_NANOSLEEP
|
||||||
struct timespec time_sleep;
|
struct timespec time_sleep;
|
||||||
struct timespec time_remaining;
|
struct timespec time_remaining;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
time_sleep.tv_sec = len / 1000000;
|
time_sleep.tv_sec = len / 1000000;
|
||||||
time_sleep.tv_nsec = (len % 1000000) * 1000;
|
time_sleep.tv_nsec = (len % 1000000) * 1000;
|
||||||
|
|
||||||
ret = nanosleep(&time_sleep, &time_remaining);
|
ret = nanosleep(&time_sleep, &time_remaining);
|
||||||
while (ret != 0 && errno == EINTR) {
|
while (ret != 0 && errno == EINTR) {
|
||||||
time_sleep.tv_sec = time_remaining.tv_sec;
|
time_sleep.tv_sec = time_remaining.tv_sec;
|
||||||
time_sleep.tv_nsec = time_remaining.tv_nsec;
|
time_sleep.tv_nsec = time_remaining.tv_nsec;
|
||||||
|
|
||||||
ret = nanosleep(&time_sleep, &time_remaining);
|
ret = nanosleep(&time_sleep, &time_remaining);
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
tv.tv_sec = len / 1000000;
|
tv.tv_sec = len / 1000000;
|
||||||
tv.tv_usec = (len % 1000000);
|
tv.tv_usec = (len % 1000000);
|
||||||
|
|
||||||
select(0, NULL, NULL, NULL, &tv);
|
select(0, NULL, NULL, NULL, &tv);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *_start_routine(void *arg)
|
static void *_start_routine(void *arg)
|
||||||
{
|
{
|
||||||
thread_start_t *start = (thread_start_t *)arg;
|
thread_start_t *start = (thread_start_t *)arg;
|
||||||
void *(*start_routine)(void *) = start->start_routine;
|
void *(*start_routine)(void *) = start->start_routine;
|
||||||
void *real_arg = start->arg;
|
void *real_arg = start->arg;
|
||||||
thread_type *thread = start->thread;
|
thread_type *thread = start->thread;
|
||||||
int detach = start->detached;
|
int detach = start->detached;
|
||||||
|
|
||||||
_block_signals();
|
_block_signals();
|
||||||
|
|
||||||
free(start);
|
free(start);
|
||||||
|
|
||||||
/* insert thread into thread tree here */
|
/* insert thread into thread tree here */
|
||||||
_mutex_lock(&_threadtree_mutex);
|
_mutex_lock(&_threadtree_mutex);
|
||||||
thread->sys_thread = pthread_self();
|
thread->sys_thread = pthread_self();
|
||||||
avl_insert(_threadtree, (void *)thread);
|
avl_insert(_threadtree, (void *)thread);
|
||||||
_mutex_unlock(&_threadtree_mutex);
|
_mutex_unlock(&_threadtree_mutex);
|
||||||
|
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
LOG_INFO4("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line);
|
LOG_INFO4("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (detach) {
|
if (detach) {
|
||||||
pthread_detach(thread->sys_thread);
|
pthread_detach(thread->sys_thread);
|
||||||
thread->detached = 1;
|
thread->detached = 1;
|
||||||
}
|
}
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||||
|
|
||||||
/* call the real start_routine and start the thread
|
/* call the real start_routine and start the thread
|
||||||
** this should never exit!
|
** this should never exit!
|
||||||
*/
|
*/
|
||||||
(start_routine)(real_arg);
|
(start_routine)(real_arg);
|
||||||
|
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
LOG_WARN("Thread x should never exit from here!!!");
|
LOG_WARN("Thread x should never exit from here!!!");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_type *thread_self(void)
|
thread_type *thread_self(void)
|
||||||
{
|
{
|
||||||
avl_node *node;
|
avl_node *node;
|
||||||
thread_type *th;
|
thread_type *th;
|
||||||
pthread_t sys_thread = pthread_self();
|
pthread_t sys_thread = pthread_self();
|
||||||
|
|
||||||
_mutex_lock(&_threadtree_mutex);
|
_mutex_lock(&_threadtree_mutex);
|
||||||
|
|
||||||
if (_threadtree == NULL) {
|
if (_threadtree == NULL) {
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
LOG_WARN("Thread tree is empty, this must be wrong!");
|
LOG_WARN("Thread tree is empty, this must be wrong!");
|
||||||
#endif
|
#endif
|
||||||
_mutex_unlock(&_threadtree_mutex);
|
_mutex_unlock(&_threadtree_mutex);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = avl_get_first(_threadtree);
|
node = avl_get_first(_threadtree);
|
||||||
|
|
||||||
while (node) {
|
while (node) {
|
||||||
th = (thread_type *)node->key;
|
th = (thread_type *)node->key;
|
||||||
|
|
||||||
if (th && pthread_equal(sys_thread, th->sys_thread)) {
|
if (th && pthread_equal(sys_thread, th->sys_thread)) {
|
||||||
_mutex_unlock(&_threadtree_mutex);
|
_mutex_unlock(&_threadtree_mutex);
|
||||||
return th;
|
return th;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = avl_get_next(node);
|
node = avl_get_next(node);
|
||||||
}
|
}
|
||||||
_mutex_unlock(&_threadtree_mutex);
|
_mutex_unlock(&_threadtree_mutex);
|
||||||
|
|
||||||
|
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
LOG_ERROR("Nonexistant thread alive...");
|
LOG_ERROR("Nonexistant thread alive...");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_rename(const char *name)
|
void thread_rename(const char *name)
|
||||||
{
|
{
|
||||||
thread_type *th;
|
thread_type *th;
|
||||||
|
|
||||||
th = thread_self();
|
th = thread_self();
|
||||||
if (th->name) free(th->name);
|
if (th->name) free(th->name);
|
||||||
|
|
||||||
th->name = strdup(name);
|
th->name = strdup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _mutex_lock(mutex_t *mutex)
|
static void _mutex_lock(mutex_t *mutex)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&mutex->sys_mutex);
|
pthread_mutex_lock(&mutex->sys_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _mutex_unlock(mutex_t *mutex)
|
static void _mutex_unlock(mutex_t *mutex)
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&mutex->sys_mutex);
|
pthread_mutex_unlock(&mutex->sys_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void thread_library_lock(void)
|
void thread_library_lock(void)
|
||||||
{
|
{
|
||||||
_mutex_lock(&_library_mutex);
|
_mutex_lock(&_library_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_library_unlock(void)
|
void thread_library_unlock(void)
|
||||||
{
|
{
|
||||||
_mutex_unlock(&_library_mutex);
|
_mutex_unlock(&_library_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_join(thread_type *thread)
|
void thread_join(thread_type *thread)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = pthread_join(thread->sys_thread, &ret);
|
i = pthread_join(thread->sys_thread, &ret);
|
||||||
_mutex_lock(&_threadtree_mutex);
|
_mutex_lock(&_threadtree_mutex);
|
||||||
avl_delete(_threadtree, thread, _free_thread);
|
avl_delete(_threadtree, thread, _free_thread);
|
||||||
_mutex_unlock(&_threadtree_mutex);
|
_mutex_unlock(&_threadtree_mutex);
|
||||||
@ -745,65 +745,65 @@ void thread_join(thread_type *thread)
|
|||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
static int _compare_mutexes(void *compare_arg, void *a, void *b)
|
static int _compare_mutexes(void *compare_arg, void *a, void *b)
|
||||||
{
|
{
|
||||||
mutex_t *m1, *m2;
|
mutex_t *m1, *m2;
|
||||||
|
|
||||||
m1 = (mutex_t *)a;
|
m1 = (mutex_t *)a;
|
||||||
m2 = (mutex_t *)b;
|
m2 = (mutex_t *)b;
|
||||||
|
|
||||||
if (m1->mutex_id > m2->mutex_id)
|
if (m1->mutex_id > m2->mutex_id)
|
||||||
return 1;
|
return 1;
|
||||||
if (m1->mutex_id < m2->mutex_id)
|
if (m1->mutex_id < m2->mutex_id)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int _compare_threads(void *compare_arg, void *a, void *b)
|
static int _compare_threads(void *compare_arg, void *a, void *b)
|
||||||
{
|
{
|
||||||
thread_type *t1, *t2;
|
thread_type *t1, *t2;
|
||||||
|
|
||||||
t1 = (thread_type *)a;
|
t1 = (thread_type *)a;
|
||||||
t2 = (thread_type *)b;
|
t2 = (thread_type *)b;
|
||||||
|
|
||||||
if (t1->thread_id > t2->thread_id)
|
if (t1->thread_id > t2->thread_id)
|
||||||
return 1;
|
return 1;
|
||||||
if (t1->thread_id < t2->thread_id)
|
if (t1->thread_id < t2->thread_id)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
static int _free_mutex(void *key)
|
static int _free_mutex(void *key)
|
||||||
{
|
{
|
||||||
mutex_t *m;
|
mutex_t *m;
|
||||||
|
|
||||||
m = (mutex_t *)key;
|
m = (mutex_t *)key;
|
||||||
|
|
||||||
if (m && m->file) {
|
if (m && m->file) {
|
||||||
free(m->file);
|
free(m->file);
|
||||||
m->file = NULL;
|
m->file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* all mutexes are static. don't need to free them */
|
/* all mutexes are static. don't need to free them */
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int _free_thread(void *key)
|
static int _free_thread(void *key)
|
||||||
{
|
{
|
||||||
thread_type *t;
|
thread_type *t;
|
||||||
|
|
||||||
t = (thread_type *)key;
|
t = (thread_type *)key;
|
||||||
|
|
||||||
if (t->file)
|
if (t->file)
|
||||||
free(t->file);
|
free(t->file);
|
||||||
if (t->name)
|
if (t->name)
|
||||||
free(t->name);
|
free(t->name);
|
||||||
|
|
||||||
free(t);
|
free(t);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _free_thread_if_detached(void *key)
|
static int _free_thread_if_detached(void *key)
|
||||||
|
@ -27,67 +27,67 @@
|
|||||||
/* renamed from thread_t due to conflict on OS X */
|
/* renamed from thread_t due to conflict on OS X */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* the local id for the thread, and it's name */
|
/* the local id for the thread, and it's name */
|
||||||
long thread_id;
|
long thread_id;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
/* the time the thread was created */
|
/* the time the thread was created */
|
||||||
time_t create_time;
|
time_t create_time;
|
||||||
|
|
||||||
/* the file and line which created this thread */
|
/* the file and line which created this thread */
|
||||||
char *file;
|
char *file;
|
||||||
int line;
|
int line;
|
||||||
|
|
||||||
/* is the thread running detached? */
|
/* is the thread running detached? */
|
||||||
int detached;
|
int detached;
|
||||||
|
|
||||||
/* the system specific thread */
|
/* the system specific thread */
|
||||||
pthread_t sys_thread;
|
pthread_t sys_thread;
|
||||||
} thread_type;
|
} thread_type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
#ifdef DEBUG_MUTEXES
|
#ifdef DEBUG_MUTEXES
|
||||||
/* the local id and name of the mutex */
|
/* the local id and name of the mutex */
|
||||||
long mutex_id;
|
long mutex_id;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
/* the thread which is currently locking this mutex */
|
/* the thread which is currently locking this mutex */
|
||||||
long thread_id;
|
long thread_id;
|
||||||
|
|
||||||
/* the file and line where the mutex was locked */
|
/* the file and line where the mutex was locked */
|
||||||
char *file;
|
char *file;
|
||||||
int line;
|
int line;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* the system specific mutex */
|
/* the system specific mutex */
|
||||||
pthread_mutex_t sys_mutex;
|
pthread_mutex_t sys_mutex;
|
||||||
} mutex_t;
|
} mutex_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
long cond_id;
|
long cond_id;
|
||||||
char *name;
|
char *name;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_t cond_mutex;
|
pthread_mutex_t cond_mutex;
|
||||||
pthread_cond_t sys_cond;
|
pthread_cond_t sys_cond;
|
||||||
} cond_t;
|
} cond_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
#ifdef THREAD_DEBUG
|
#ifdef THREAD_DEBUG
|
||||||
long rwlock_id;
|
long rwlock_id;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
/* information on which thread and where in the code
|
/* information on which thread and where in the code
|
||||||
** this rwlock was write locked
|
** this rwlock was write locked
|
||||||
*/
|
*/
|
||||||
long thread_id;
|
long thread_id;
|
||||||
char *file;
|
char *file;
|
||||||
int line;
|
int line;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_rwlock_t sys_rwlock;
|
pthread_rwlock_t sys_rwlock;
|
||||||
} rwlock_t;
|
} rwlock_t;
|
||||||
|
|
||||||
#define thread_create(n,x,y,z) thread_create_c(n,x,y,z,__LINE__,__FILE__)
|
#define thread_create(n,x,y,z) thread_create_c(n,x,y,z,__LINE__,__FILE__)
|
||||||
|
@ -28,27 +28,27 @@
|
|||||||
uint64_t timing_get_time(void)
|
uint64_t timing_get_time(void)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return timeGetTime();
|
return timeGetTime();
|
||||||
#else
|
#else
|
||||||
struct timeval mtv;
|
struct timeval mtv;
|
||||||
|
|
||||||
gettimeofday(&mtv, NULL);
|
gettimeofday(&mtv, NULL);
|
||||||
|
|
||||||
return (uint64_t)(mtv.tv_sec) * 1000 + (uint64_t)(mtv.tv_usec) / 1000;
|
return (uint64_t)(mtv.tv_sec) * 1000 + (uint64_t)(mtv.tv_usec) / 1000;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void timing_sleep(uint64_t sleeptime)
|
void timing_sleep(uint64_t sleeptime)
|
||||||
{
|
{
|
||||||
struct timeval sleeper;
|
struct timeval sleeper;
|
||||||
|
|
||||||
sleeper.tv_sec = sleeptime / 1000;
|
sleeper.tv_sec = sleeptime / 1000;
|
||||||
sleeper.tv_usec = (sleeptime % 1000) * 1000;
|
sleeper.tv_usec = (sleeptime % 1000) * 1000;
|
||||||
|
|
||||||
/* NOTE:
|
/* NOTE:
|
||||||
* This should be 0 for the first argument. The linux manpage
|
* This should be 0 for the first argument. The linux manpage
|
||||||
* says so. The solaris manpage also says this is a legal
|
* says so. The solaris manpage also says this is a legal
|
||||||
* value. If you think differerntly, please provide references.
|
* value. If you think differerntly, please provide references.
|
||||||
*/
|
*/
|
||||||
select(0, NULL, NULL, NULL, &sleeper);
|
select(0, NULL, NULL, NULL, &sleeper);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user