1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "sysdeps.h"
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <errno.h>
17
18#define  PORT          8000
19#define  MAX_COUNTER   30
20#define  INITIAL_DELAY 1000
21#define  DELAY         5000
22
23static int  counter = 0;
24
25static void
26timer_func( void*  _timer )
27{
28    SysTimer  timer = _timer;
29    SysTime   now   = sys_time_ms();
30
31    ++counter;
32    printf( "tick %d/%d a %.2fs\n", counter, MAX_COUNTER, now/1000. );
33    if (counter < MAX_COUNTER)
34        sys_timer_set( timer, now + DELAY, timer_func, timer );
35    else
36        sys_timer_destroy( timer );
37}
38
39typedef struct {
40    SysChannel   channel;
41    char         in_buff[ 128 ];
42    int          in_pos;
43
44    char         out_buff[ 128 ];
45    int          out_pos;
46    int          out_size;
47} ClientRec, *Client;
48
49static Client
50client_alloc( SysChannel  channel )
51{
52    Client  client = calloc( sizeof(*client), 1 );
53
54    client->channel = channel;
55    return client;
56}
57
58static void
59client_free( Client  client )
60{
61    sys_channel_close( client->channel );
62    client->channel = NULL;
63    free( client );
64}
65
66static void
67client_append( Client  client, const char*  str, int len );
68
69static void
70client_handle_line( Client  client, const char*  cmd )
71{
72    char temp[256];
73    int  nn, mm = 0;
74
75    for (nn = 0; cmd[nn] != 0; nn++) {
76        int  c = cmd[nn];
77        if (c >= 32 && c <= 127)
78            temp[mm++] = c;
79        else if (c == '\n') {
80            strcat( temp+mm, "<LF>" );
81            mm += 4;
82        }
83        else if (c == '\r') {
84            strcat( temp+mm, "<CR>" );
85            mm += 4;
86        }
87        else {
88            sprintf( temp+mm, "\\x%02x", c );
89            mm += strlen( temp+mm );
90        }
91    }
92    temp[mm] = 0;
93    printf( "%p: << %s\n", client, temp );
94
95    if ( !strcmp( cmd, "quit" ) ) {
96        printf( "client %p quitting\n", client );
97        client_free( client );
98        return;
99    }
100    client_append( client, "type 'quit' to quit\n", -1 );
101}
102
103static void
104client_handler( void* _client, int  events )
105{
106    Client  client = _client;
107
108    if (events & SYS_EVENT_READ) {
109        int  ret;
110        /* read into buffer, one character at a time */
111        ret = sys_channel_read( client->channel, client->in_buff + client->in_pos, 1 );
112        if (ret != 1) {
113            fprintf(stderr, "client %p could not read byte, result = %d, error: %s\n",
114                    client, ret, strerror(errno) );
115            goto ExitClient;
116        }
117        if (client->in_buff[client->in_pos] == '\r' ||
118            client->in_buff[client->in_pos] == '\n' ) {
119            const char*  cmd = client->in_buff;
120            client->in_buff[client->in_pos] = 0;
121
122            /* eat leading cr and lf, maybe left-overs from previous line */
123            while (*cmd == '\r' || *cmd =='\n')
124                cmd++;
125
126            client_handle_line( client, cmd );
127            client->in_pos = 0;
128        } else
129            client->in_pos += 1;
130    }
131
132    if (events & SYS_EVENT_WRITE) {
133        int  ret;
134        /* write from output buffer, one char at a time */
135        ret = sys_channel_write( client->channel, client->out_buff + client->out_pos, 1 );
136        if (ret != 1) {
137            fprintf(stderr, "client %p could not write byte, result = %d, error: %s\n",
138                    client, ret, strerror(errno) );
139            goto ExitClient;
140        }
141        client->out_pos += 1;
142        if (client->out_pos == client->out_size) {
143            client->out_size = 0;
144            client->out_pos  = 0;
145            /* we don't need to write */
146            sys_channel_on( client->channel, SYS_EVENT_READ, client_handler, client );
147        }
148    }
149    return;
150
151ExitClient:
152    printf( "client %p exiting\n", client );
153    client_free( client );
154}
155
156static void
157client_append( Client  client, const char*  str, int len )
158{
159    int  avail;
160
161    if (len < 0)
162        len = strlen(str);
163
164    avail = sizeof(client->out_buff) - client->out_size;
165    if (len > avail)
166        len = avail;
167
168    memcpy( client->out_buff + client->out_size, str, len );
169    if (client->out_size == 0) {
170        sys_channel_on( client->channel, SYS_EVENT_READ | SYS_EVENT_WRITE, client_handler, client );
171    }
172    client->out_size += len;
173}
174
175
176static void
177accept_func( void*  _server, int  events )
178{
179    SysChannel  server  = _server;
180    SysChannel  handler;
181    Client      client;
182
183    printf( "connection accepted for server channel, getting handler socket\n" );
184    handler = sys_channel_create_tcp_handler( server );
185    printf( "got one. creating client\n" );
186    client  = client_alloc( handler );
187
188    events=events;
189    sys_channel_on( handler, SYS_EVENT_READ, client_handler, client );
190    client_append( client, "Welcome !\n", -1 );
191}
192
193
194int  main( void )
195{
196    SysTimer    timer;
197    SysChannel  server_channel;
198
199    /* initialize event subsystem */
200    sys_main_init();
201
202    /* create timer and register it */
203    timer = sys_timer_create();
204    sys_timer_set( timer, sys_time_ms() + INITIAL_DELAY, timer_func, timer );
205
206    server_channel = sys_channel_create_tcp_server( PORT );
207    printf( "listening on port %d with %p\n", PORT, server_channel );
208
209    sys_channel_on( server_channel, SYS_EVENT_READ, accept_func, server_channel );
210
211    printf("entering event loop\n");
212    sys_main_loop();
213    printf("exiting event loop\n" );
214    return 0;
215}
216