OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [lwip_tcpip/] [current/] [tests/] [httpd_simple.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      httpd_simple.c
4
//
5
//      A simple HTTP server using raw tcp pcbs in 'Simple' mode.
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 2008 Free Software Foundation
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
// -------------------------------------------
36
//####ECOSGPLCOPYRIGHTEND####
37
//==========================================================================
38
//#####DESCRIPTIONBEGIN####
39
//
40
// Author(s):    Simon Kallweit
41
// Contributors:
42
// Date:         2008-12-01
43
// Purpose:
44
// Description:  A simple HTTP server using raw tcp pcbs in 'Simple' mode.
45
//
46
//####DESCRIPTIONEND####
47
//
48
//==========================================================================
49
 
50
#include <cyg/hal/hal_arch.h>
51
#include <cyg/infra/diag.h>
52
#include <cyg/infra/testcase.h>
53
#include <cyg/kernel/kapi.h>
54
 
55
#include <lwip.h>
56
#include <lwip/init.h>
57
 
58
#ifdef CYGFUN_LWIP_MODE_SIMPLE
59
#if LWIP_TCP
60
 
61
struct http_state {
62
    char buf[256];
63
    char *file;
64
    u32_t left;
65
    u8_t retries;
66
};
67
 
68
static int request_counter = 1;
69
 
70
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
71
 
72
static char main_stack[STACK_SIZE];
73
static cyg_thread main_thread;
74
static cyg_handle_t main_handle;
75
 
76
 
77
// Appends text to the buffer.
78
static void
79
buf_append_text(char *buf, const char *text)
80
{
81
    char *dst = buf;
82
    const char *src = text;
83
 
84
    while (*dst != '\0')
85
        dst++;
86
 
87
    while (*src != '\0')
88
        *dst++ = *src++;
89
 
90
    *dst = '\0';
91
}
92
 
93
// Appends a decimal value to the buffer.
94
static void
95
buf_append_dec(char *buf, int value)
96
{
97
    char *dst = buf;
98
    char tmp[16];
99
    int i = 0;
100
 
101
    while (*dst != '\0')
102
        dst++;
103
 
104
    do {
105
        tmp[i++] = '0' + value % 10;
106
        value /= 10;
107
    } while (value > 0);
108
 
109
    while (i-- > 0)
110
        *dst++ = tmp[i];
111
 
112
    *dst = '\0';
113
}
114
 
115
// Returns the length of the buffer.
116
static size_t
117
buf_length(char *buf)
118
{
119
    size_t len = 0;
120
 
121
    while (*buf++ != '\0')
122
        len++;
123
 
124
    return len;
125
}
126
 
127
// Prepares the HTTP page.
128
static void
129
prepare_page(struct http_state *hs)
130
{
131
    hs->buf[0] = '\0';
132
    buf_append_text(hs->buf, "HTTP/1.0 200 OK\r\n");
133
    buf_append_text(hs->buf, "Content-Type: text/html\r\n");
134
    buf_append_text(hs->buf, "\r\n");
135
    buf_append_text(hs->buf, "<html>\r\n");
136
    buf_append_text(hs->buf, "<h1>eCos - HTTP test server running on lwIP</h1>\r\n");
137
    buf_append_text(hs->buf, "<table><tr><td>Version:</td><td>");
138
    buf_append_dec(hs->buf, LWIP_VERSION_MAJOR);
139
    buf_append_text(hs->buf, ".");
140
    buf_append_dec(hs->buf, LWIP_VERSION_MINOR);
141
    buf_append_text(hs->buf, ".");
142
    buf_append_dec(hs->buf, LWIP_VERSION_REVISION);
143
    if (LWIP_VERSION_IS_RELEASE)
144
        buf_append_text(hs->buf, " (release)");
145
    if (LWIP_VERSION_IS_DEVELOPMENT)
146
        buf_append_text(hs->buf, " (development)");
147
    if (LWIP_VERSION_IS_RC)
148
        buf_append_text(hs->buf, " (rc)");
149
    buf_append_text(hs->buf, "</td></tr><tr><td>Requests:</td><td>");
150
    buf_append_dec(hs->buf, request_counter++);
151
    buf_append_text(hs->buf, "</td></tr></table>\r\n");
152
    buf_append_text(hs->buf, "</html>");
153
 
154
    hs->file = hs->buf;
155
    hs->left = buf_length(hs->buf);
156
}
157
 
158
// Called when an error occured. Frees the allocated resources.
159
static void
160
http_err(void *arg, err_t err)
161
{
162
    struct http_state *hs;
163
 
164
    CYG_TEST_INFO("Connection error");
165
 
166
    hs = arg;
167
    mem_free(hs);
168
}
169
 
170
// Closes the TCP connection and frees the allocated resources.
171
static void
172
close_conn(struct tcp_pcb *pcb, struct http_state *hs)
173
{
174
    CYG_TEST_INFO("Closing connection");
175
 
176
    tcp_arg(pcb, NULL);
177
    tcp_sent(pcb, NULL);
178
    tcp_recv(pcb, NULL);
179
    mem_free(hs);
180
    tcp_close(pcb);
181
}
182
 
183
// Sends the next chunk of data.
184
static void
185
send_data(struct tcp_pcb *pcb, struct http_state *hs)
186
{
187
    err_t err;
188
    u16_t len;
189
 
190
    CYG_TEST_INFO("Sending data");
191
 
192
    // We cannot send more data than space available in the send buffer
193
    len = tcp_sndbuf(pcb) < hs->left ? tcp_sndbuf(pcb) : hs->left;
194
 
195
    do {
196
        err = tcp_write(pcb, hs->file, len, 0);
197
        if (err == ERR_MEM) {
198
            len /= 2;
199
        }
200
    } while (err == ERR_MEM && len > 1);
201
 
202
    if (err == ERR_OK) {
203
        hs->file += len;
204
        hs->left -= len;
205
    }
206
}
207
 
208
// Called in a regular interval. Implements retries.
209
static err_t
210
http_poll(void *arg, struct tcp_pcb *pcb)
211
{
212
    struct http_state *hs;
213
 
214
    CYG_TEST_INFO("Polling");
215
 
216
    hs = arg;
217
 
218
    if (hs == NULL) {
219
        tcp_abort(pcb);
220
        return ERR_ABRT;
221
    } else {
222
        ++hs->retries;
223
        if (hs->retries == 4) {
224
            tcp_abort(pcb);
225
            return ERR_ABRT;
226
        }
227
        send_data(pcb, hs);
228
    }
229
 
230
    return ERR_OK;
231
}
232
 
233
// Called when data has been sent.
234
static err_t
235
http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
236
{
237
    struct http_state *hs;
238
 
239
    CYG_TEST_INFO("Sent data");
240
 
241
    hs = arg;
242
 
243
    hs->retries = 0;
244
 
245
    if (hs->left > 0) {
246
        send_data(pcb, hs);
247
    } else {
248
        close_conn(pcb, hs);
249
    }
250
 
251
    return ERR_OK;
252
}
253
 
254
// Called when data has been received. Checks for HTTP requests.
255
static err_t
256
http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
257
{
258
    int i;
259
    char *data;
260
    struct http_state *hs;
261
 
262
    CYG_TEST_INFO("Received data");
263
 
264
    hs = arg;
265
 
266
    if (err == ERR_OK && p != NULL) {
267
        // Inform TCP that we have taken the data
268
        tcp_recved(pcb, p->tot_len);
269
 
270
        // Check for HTTP requests
271
        if (hs->file == NULL) {
272
            data = p->payload;
273
 
274
            if (*data == 'G') {
275
                for (i = 0; i < 40; i++) {
276
                    if (((char *) data + 4)[i] == ' ' ||
277
                        ((char *) data + 4)[i] == '\r' ||
278
                        ((char *) data + 4)[i] == '\n') {
279
                        ((char *)data + 4)[i] = 0;
280
                    }
281
                }
282
 
283
                prepare_page(hs);
284
 
285
                pbuf_free(p);
286
                send_data(pcb, hs);
287
 
288
                // Tell TCP that we wish be to informed of data that has been
289
                // successfully sent by a call to the http_sent() function.
290
                tcp_sent(pcb, http_sent);
291
            } else {
292
                pbuf_free(p);
293
                close_conn(pcb, hs);
294
            }
295
        } else {
296
            pbuf_free(p);
297
        }
298
    }
299
 
300
    if (err == ERR_OK && p == NULL) {
301
        close_conn(pcb, hs);
302
    }
303
 
304
    return ERR_OK;
305
}
306
 
307
// Called when a new connection was accepted.
308
static err_t
309
http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
310
{
311
    struct http_state *hs;
312
 
313
    CYG_TEST_INFO("Incoming connection");
314
 
315
    tcp_setprio(pcb, TCP_PRIO_MIN);
316
 
317
    // Allocate memory for the structure that holds the state of the connection
318
    hs = mem_malloc(sizeof(struct http_state));
319
    if (hs == NULL)
320
        return ERR_MEM;
321
 
322
    // Initialize the structure
323
    hs->file = NULL;
324
    hs->left = 0;
325
    hs->retries = 0;
326
 
327
    // Tell TCP that this is the structure we wish to be passed for our
328
    // callbacks
329
    tcp_arg(pcb, hs);
330
 
331
    // Register callbacks
332
    tcp_recv(pcb, http_recv);
333
    tcp_err(pcb, http_err);
334
    tcp_poll(pcb, http_poll, 4);
335
 
336
    CYG_TEST_INFO("Connection accepted");
337
 
338
    return ERR_OK;
339
}
340
 
341
// Main thread.
342
void
343
main_thread_entry(cyg_addrword_t p)
344
{
345
    struct tcp_pcb *pcb;
346
 
347
    CYG_TEST_INFO("Initializing lwIP");
348
    cyg_lwip_simple_init();
349
 
350
    CYG_TEST_INFO("Initializing tcb");
351
    pcb = tcp_new();
352
    tcp_bind(pcb, IP_ADDR_ANY, 80);
353
    pcb = tcp_listen(pcb);
354
    tcp_accept(pcb, http_accept);
355
 
356
    CYG_TEST_INFO("Running");
357
    while (1) {
358
        cyg_lwip_simple_poll();
359
        cyg_thread_delay(1);
360
    }
361
}
362
 
363
void
364
httpd_main(void)
365
{
366
    CYG_TEST_INIT();
367
    CYG_TEST_INFO("Testing httpd");
368
 
369
    cyg_thread_create(
370
        10,                 // Priority
371
        main_thread_entry,  // Entry
372
        0,                  // Entry parameter
373
        "main",             // Name
374
        main_stack,         // Stack
375
        STACK_SIZE,         // Size
376
        &main_handle,       // Handle
377
        &main_thread        // Thread data structure
378
    );
379
    cyg_thread_resume(main_handle);
380
    cyg_scheduler_start();
381
 
382
    CYG_TEST_FAIL_FINISH("Not reached");
383
}
384
 
385
externC void
386
cyg_start(void)
387
{
388
    httpd_main();
389
}
390
 
391
#else // LWIP_TCP
392
#define N_A_MSG "TCP support disabled"
393
#endif // LWIP_TCP
394
 
395
#else // CYGFUN_LWIP_MODE_SIMPLE
396
#define N_A_MSG "Not configured in 'Simple' mode"
397
#endif // CYGFUN_LWIP_MODE_SIMPLE
398
 
399
#ifdef N_A_MSG
400
externC void
401
cyg_start(void)
402
{
403
    CYG_TEST_INIT();
404
    CYG_TEST_NA(N_A_MSG);
405
}
406
#endif // N_A_MSG

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.