forked from zorxx/microhttpd
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.c
More file actions
128 lines (109 loc) · 3.52 KB
/
client.c
File metadata and controls
128 lines (109 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*! \copyright 2018 Zorxx Software. All rights reserved.
* \license This file is released under the MIT License. See the LICENSE file for details.
* \file client.c
* \brief microhttpd client Implementation
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "helpers.h"
#include "client.h"
int microhttpd_NewClient(struct md_context *ctx, int nSocket, struct sockaddr_in *socket_info)
{
struct md_client *client;
uint8_t *addr = (uint8_t *) &socket_info->sin_addr.s_addr;
uint16_t port = ntohs(socket_info->sin_port);
client = (struct md_client *) malloc(sizeof(*client));
if(NULL == client)
return -1;
memset(client, 0, sizeof(*client));
snprintf(client->source_address, sizeof(client->source_address) - 1,
"%u.%u.%u.%u:%u", addr[0], addr[1], addr[2], addr[3], port);
DBG("%s: New client connected from %s\n", __func__, client->source_address);
client->socket = nSocket;
memcpy(&client->socket_info, socket_info, sizeof(client->socket_info));
client->rx_buffer_size = ctx->params.rx_buffer_size;
client->rx_buffer = malloc(client->rx_buffer_size);
if(client->rx_buffer == NULL)
{
DBG("%s: Failed to allocate receive buffer\n", __func__);
free(client);
return -1;
}
client->ctx = ctx;
microhttpd_ResetState(client);
client->next = ctx->client_list;
ctx->client_list = client;
return 0;
}
int microhttpd_RemoveClient(struct md_context *ctx, struct md_client *client)
{
struct md_client *cur, *prev;
close(client->socket);
for(prev = NULL, cur = ctx->client_list; cur != NULL; prev = cur, cur = cur->next)
{
if(cur == client)
{
if(prev != NULL)
prev->next = cur->next;
else
ctx->client_list = cur->next;
}
}
microhttpd_ResetState(client);
free(client->rx_buffer);
free(client);
return 0;
}
int microhttpd_HandleClientReceive(struct md_context *ctx, struct md_client *client)
{
int32_t space_left = client->rx_buffer_size - client->rx_size;
int32_t length;
uint32_t consumed;
bool error, cont;
if(space_left <= 0)
{
DBG("%s: Invalid space remaining (%d)\n", __func__, space_left);
return microhttpd_RemoveClient(ctx, client);
}
DBG("%s: Receive at offset %u, %u bytes reamining\n",
__func__, client->rx_size, space_left);
length = read(client->socket, &client->rx_buffer[client->rx_size], space_left);
if(length <= 0)
{
DBG("%s: Read failed (%d)\n", __func__, length);
return microhttpd_RemoveClient(ctx, client);
}
client->rx_size += length;
DBG("%s: Received %u bytes (total now %u)\n", __func__, length, client->rx_size);
cont = true;
do
{
consumed = 0;
error = false;
cont = client->state(client, &consumed, &error);
if(error)
{
DBG("%s: State machine error\n", __func__);
return microhttpd_RemoveClient(ctx, client);
}
if(consumed > 0)
{
if(client->rx_size < consumed)
{
DBG("%s: Rx buffer underrun (consumed %u of %u bytes)\n",
__func__, consumed, client->rx_size);
return microhttpd_RemoveClient(ctx, client);
}
string_shift(client->rx_buffer, consumed, client->rx_size);
client->rx_size -= consumed;
}
} while(cont);
return 0;
}
int microhttpd_HandleClientError(struct md_context *ctx, struct md_client *client)
{
DBG("%s: Socket error\n", __func__);
return microhttpd_RemoveClient(ctx, client);
}