1 /*
2 * Copyright (c) 2014 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <app.h>
9 #include <lk/err.h>
10 #include <lk/debug.h>
11 #include <lk/trace.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <lk/compiler.h>
15 #include <kernel/thread.h>
16 #include <lib/minip.h>
17 #include <lib/tftp.h>
18 #include <lib/cksum.h>
19 #include <platform.h>
20
21 #include "inetsrv.h"
22
chargen_worker(void * socket)23 static int chargen_worker(void *socket) {
24 uint64_t count = 0;
25 tcp_socket_t *s = socket;
26
27 /* enough buffer to hold an entire defacto chargen sequences */
28 #define CHARGEN_BUFSIZE (0x5f * 0x5f) // 9025 bytes
29
30 uint8_t *buf = malloc(CHARGEN_BUFSIZE);
31 if (!buf)
32 return ERR_NO_MEMORY;
33
34 /* generate the sequence */
35 uint8_t c = '!';
36 for (size_t i = 0; i < CHARGEN_BUFSIZE; i++) {
37 buf[i] = c++;
38 if (c == 0x7f)
39 c = ' ';
40 }
41
42 lk_time_t t = current_time();
43 for (;;) {
44 ssize_t ret = tcp_write(s, buf, CHARGEN_BUFSIZE);
45 //TRACEF("tcp_write returns %d\n", ret);
46 if (ret < 0)
47 break;
48
49 count += ret;
50 }
51 t = current_time() - t;
52
53 TRACEF("chargen worker exiting, wrote %llu bytes in %u msecs (%llu bytes/sec)\n",
54 count, (uint32_t)t, count * 1000 / t);
55 free(buf);
56 tcp_close(s);
57
58 return 0;
59 }
60
chargen_server(void * arg)61 static int chargen_server(void *arg) {
62 status_t err;
63 tcp_socket_t *listen_socket;
64
65 err = tcp_open_listen(&listen_socket, 19);
66 if (err < 0) {
67 TRACEF("error opening chargen listen socket\n");
68 return -1;
69 }
70
71 for (;;) {
72 tcp_socket_t *accept_socket;
73
74 err = tcp_accept(listen_socket, &accept_socket);
75 TRACEF("tcp_accept returns returns %d, handle %p\n", err, accept_socket);
76 if (err < 0) {
77 TRACEF("error accepting socket, retrying\n");
78 continue;
79 }
80
81 TRACEF("starting chargen worker\n");
82 thread_detach_and_resume(thread_create("chargen_worker", &chargen_worker, accept_socket, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
83 }
84 }
85
discard_worker(void * socket)86 static int discard_worker(void *socket) {
87 uint64_t count = 0;
88 uint32_t crc = 0;
89 tcp_socket_t *s = socket;
90
91 #define DISCARD_BUFSIZE 1024
92
93 uint8_t *buf = malloc(DISCARD_BUFSIZE);
94 if (!buf) {
95 TRACEF("error allocating buffer\n");
96 }
97
98 lk_time_t t = current_time();
99 for (;;) {
100 ssize_t ret = tcp_read(s, buf, DISCARD_BUFSIZE);
101 if (ret <= 0)
102 break;
103
104 crc = crc32(crc, buf, ret);
105
106 count += ret;
107 }
108 t = current_time() - t;
109
110 TRACEF("discard worker exiting, read %llu bytes in %u msecs (%llu bytes/sec), crc32 0x%x\n",
111 count, (uint32_t)t, count * 1000 / t, crc);
112 tcp_close(s);
113
114 free(buf);
115
116 return 0;
117 }
118
discard_server(void * arg)119 static int discard_server(void *arg) {
120 status_t err;
121 tcp_socket_t *listen_socket;
122
123 err = tcp_open_listen(&listen_socket, 9);
124 if (err < 0) {
125 TRACEF("error opening discard listen socket\n");
126 return -1;
127 }
128
129 for (;;) {
130 tcp_socket_t *accept_socket;
131
132 err = tcp_accept(listen_socket, &accept_socket);
133 TRACEF("tcp_accept returns returns %d, handle %p\n", err, accept_socket);
134 if (err < 0) {
135 TRACEF("error accepting socket, retrying\n");
136 continue;
137 }
138
139 TRACEF("starting discard worker\n");
140 thread_detach_and_resume(thread_create("discard_worker", &discard_worker, accept_socket, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
141 }
142 }
143
echo_worker(void * socket)144 static int echo_worker(void *socket) {
145 tcp_socket_t *s = socket;
146
147 #define ECHO_BUFSIZE 1024
148
149 uint8_t *buf = malloc(ECHO_BUFSIZE);
150 if (!buf) {
151 TRACEF("error allocating buffer\n");
152 return ERR_NO_MEMORY;
153 }
154
155 for (;;) {
156 ssize_t ret = tcp_read(s, buf, sizeof(buf));
157 if (ret <= 0)
158 break;
159
160 tcp_write(s, buf, ret);
161 if (ret <= 0)
162 break;
163 }
164
165 TRACEF("echo worker exiting\n");
166 tcp_close(s);
167 free(buf);
168
169 return 0;
170 }
171
echo_server(void * arg)172 static int echo_server(void *arg) {
173 status_t err;
174 tcp_socket_t *listen_socket;
175
176 err = tcp_open_listen(&listen_socket, 7);
177 if (err < 0) {
178 TRACEF("error opening echo listen socket\n");
179 return -1;
180 }
181
182 for (;;) {
183 tcp_socket_t *accept_socket;
184
185 err = tcp_accept(listen_socket, &accept_socket);
186 TRACEF("tcp_accept returns returns %d, handle %p\n", err, accept_socket);
187 if (err < 0) {
188 TRACEF("error accepting socket, retrying\n");
189 continue;
190 }
191
192 TRACEF("starting echo worker\n");
193 thread_detach_and_resume(thread_create("echo_worker", &echo_worker, accept_socket, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
194 }
195 }
196
inetsrv_init(const struct app_descriptor * app)197 static void inetsrv_init(const struct app_descriptor *app) {
198 }
199
inetsrv_entry(const struct app_descriptor * app,void * args)200 static void inetsrv_entry(const struct app_descriptor *app, void *args) {
201 /* XXX wait for the stack to initialize */
202
203 printf("starting internet servers\n");
204
205 thread_detach_and_resume(thread_create("chargen", &chargen_server, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
206 thread_detach_and_resume(thread_create("discard", &discard_server, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
207 thread_detach_and_resume(thread_create("echo", &echo_server, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
208 tftp_server_init(NULL);
209 }
210
211 APP_START(inetsrv)
212 .init = inetsrv_init,
213 .entry = inetsrv_entry,
214 .flags = 0,
215 APP_END
216