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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
#include <rtthread.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <dfs_posix.h>
#include "netdb.h"
#define MAX_SERV 32 /* Maximum number of chargen services. Don't need too many */
#define CHARGEN_THREAD_NAME "chargen"
#if RT_THREAD_PRIORITY_MAX == 32
#define CHARGEN_PRIORITY 20 /* Really low priority */
#else
#define CHARGEN_PRIORITY 200 /* Really low priority */
#endif
#define CHARGEN_THREAD_STACKSIZE 1024
struct charcb
{
struct charcb *next;
int socket;
struct sockaddr_in cliaddr;
socklen_t clilen;
char nextchar;
};
static struct charcb *charcb_list = 0;
static int do_read(struct charcb *p_charcb);
static void close_chargen(struct charcb *p_charcb);
extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
/**************************************************************
* void chargen_thread(void *arg)
*
* chargen task. This server will wait for connections on well
* known TCP port number: 19. For every connection, the server will
* write as much data as possible to the tcp port.
**************************************************************/
static void chargen_thread(void *arg)
{
int listenfd;
struct sockaddr_in chargen_saddr;
fd_set readset;
fd_set writeset;
int i, maxfdp1;
struct charcb *p_charcb;
/* First acquire our socket for listening for connections */
listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0);
memset(&chargen_saddr, 0, sizeof(chargen_saddr));
chargen_saddr.sin_family = AF_INET;
chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY);
chargen_saddr.sin_port = htons(19); // Chargen server port
if (bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1)
LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0);
/* Put socket into listening mode */
if (listen(listenfd, MAX_SERV) == -1)
LWIP_ASSERT("chargen_thread(): Listen failed.", 0);
/* Wait forever for network input: This could be connections or data */
for (;;)
{
maxfdp1 = listenfd+1;
/* Determine what sockets need to be in readset */
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_SET(listenfd, &readset);
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
{
if (maxfdp1 < p_charcb->socket + 1)
maxfdp1 = p_charcb->socket + 1;
FD_SET(p_charcb->socket, &readset);
FD_SET(p_charcb->socket, &writeset);
}
/* Wait for data or a new connection */
i = select(maxfdp1, &readset, &writeset, 0, 0);
if (i == 0) continue;
/* At least one descriptor is ready */
if (FD_ISSET(listenfd, &readset))
{
/* We have a new connection request!!! */
/* Lets create a new control block */
p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb));
if (p_charcb)
{
p_charcb->socket = accept(listenfd,
(struct sockaddr *) &p_charcb->cliaddr,
&p_charcb->clilen);
if (p_charcb->socket < 0)
rt_free(p_charcb);
else
{
/* Keep this tecb in our list */
p_charcb->next = charcb_list;
charcb_list = p_charcb;
p_charcb->nextchar = 0x21;
}
}
else
{
/* No memory to accept connection. Just accept and then close */
int sock;
struct sockaddr cliaddr;
socklen_t clilen;
sock = accept(listenfd, &cliaddr, &clilen);
if (sock >= 0)
closesocket(sock);
}
}
/* Go through list of connected clients and process data */
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
{
if (FD_ISSET(p_charcb->socket, &readset))
{
/* This socket is ready for reading. This could be because someone typed
* some characters or it could be because the socket is now closed. Try reading
* some data to see. */
if (do_read(p_charcb) < 0)
break;
}
if (FD_ISSET(p_charcb->socket, &writeset))
{
char line[80];
char setchar = p_charcb->nextchar;
for( i = 0; i < 59; i++)
{
line[i] = setchar;
if (++setchar == 0x7f)
setchar = 0x21;
}
line[i] = 0;
strcat(line, "\n\r");
if (write(p_charcb->socket, line, strlen(line)) < 0)
{
close_chargen(p_charcb);
break;
}
if (++p_charcb->nextchar == 0x7f)
p_charcb->nextchar = 0x21;
}
}
}
}
/**************************************************************
* void close_chargen(struct charcb *p_charcb)
*
* Close the socket and remove this charcb from the list.
**************************************************************/
static void close_chargen(struct charcb *p_charcb)
{
struct charcb *p_search_charcb;
/* Either an error or tcp connection closed on other
* end. Close here */
closesocket(p_charcb->socket);
/* Free charcb */
if (charcb_list == p_charcb)
charcb_list = p_charcb->next;
else
for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next)
{
if (p_search_charcb->next == p_charcb)
{
p_search_charcb->next = p_charcb->next;
break;
}
}
rt_free(p_charcb);
}
/**************************************************************
* void do_read(struct charcb *p_charcb)
*
* Socket definitely is ready for reading. Read a buffer from the socket and
* discard the data. If no data is read, then the socket is closed and the
* charcb is removed from the list and freed.
**************************************************************/
static int do_read(struct charcb *p_charcb)
{
char buffer[80];
int readcount;
/* Read some data */
readcount = read(p_charcb->socket, &buffer, 80);
if (readcount <= 0)
{
close_chargen(p_charcb);
return -1;
}
return 0;
}
void chargen_init(void)
{
rt_thread_t chargen;
chargen = rt_thread_create(CHARGEN_THREAD_NAME,
chargen_thread, RT_NULL,
CHARGEN_THREAD_STACKSIZE,
CHARGEN_PRIORITY, 5);
if (chargen != RT_NULL) rt_thread_startup(chargen);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
void chargen()
{
chargen_init();
}
FINSH_FUNCTION_EXPORT(chargen, start chargen server);
#endif
|