1/** \file
2 *  \brief Example lwip socket application
3 */
4
5/*
6 * Copyright (c) 2010, 2012, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#include <stdio.h>
15#include <string.h>
16#include <errno.h>
17#include <unistd.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <lwip/sockets.h>
21#include <lwip/init.h>
22#include <lwip/tcpip.h>
23#include <barrelfish/barrelfish.h>
24#include <barrelfish/waitset.h>
25#include <barrelfish/spawn_client.h>
26#include <posixcompat.h>
27#include <vfs/vfs.h>
28#include <arpa/inet.h>
29
30#define NET_DRIVER "rtl8029"
31#define SERVER_PORT 8080
32#define LISTENQ 1024
33
34//#define UDP_TEST 1
35
36void network_polling_loop(void);
37
38static int poll_loop(void *args)
39{
40    network_polling_loop();
41    return 0;
42}
43
44static errval_t spawn_child(int rfd)
45
46{
47    errval_t err;
48    char *argv[2] = { "net-test", NULL };
49    struct capref new_domain;
50    coreid_t core = 0;
51    struct capref fdcap;
52
53    err = spawn_setup_fds(&fdcap, rfd);
54    if (err_is_fail(err)) {
55        USER_PANIC_ERR(err, "spawn_setup_fds");
56    }
57
58    struct capref inheritcn_cap;
59    err = alloc_inheritcn_with_caps(&inheritcn_cap, fdcap, NULL_CAP, NULL_CAP);
60    if (err_is_fail(err)) {
61        USER_PANIC_ERR(err, "failed to setup inheritcn");
62    }
63
64    err = spawn_program_with_caps(core, argv[0], argv, NULL, inheritcn_cap,
65                                  NULL_CAP, SPAWN_FLAGS_NEW_DOMAIN, &new_domain);
66
67    if (err_is_fail(err)) {
68        DEBUG_ERR(err, "failed spawn on core %d", core);
69        return err;
70    }
71
72    return SYS_ERR_OK;
73
74}
75
76#ifndef UDP_TEST
77static void debug_uipaddr_print(u32_t addr)
78{
79
80    debug_printf("%"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
81                 (u16_t)((ntohl(addr) >> 24) & 0xff),
82                 (u16_t)((ntohl(addr) >> 16) & 0xff),
83                 (u16_t)((ntohl(addr) >> 8) & 0xff),
84                 (u16_t)(ntohl(addr) & 0xff));
85}
86
87
88static void debug_sin_print(struct sockaddr_in *inaddr) {
89    u32_t addr = inaddr->sin_addr.s_addr;
90    debug_uipaddr_print(addr);
91}
92#endif // UDP_TEST
93
94
95
96#define BUF_SIZE 1024
97static int FORKING_SERVER = 1;
98
99/* Following variables are needed for networking */
100static struct thread_mutex my_mutex = THREAD_MUTEX_INITIALIZER;
101static struct waitset lwip_waitset;
102static struct thread *t;
103
104static void provide_echo_service(int sock, int iterations)
105{
106    // and echo incoming data
107    char buf[BUF_SIZE];
108    int ret;
109
110    debug_printf("[%"PRIuDOMAINID"]provide_echo_service(): Starting %d iterations on socket %d\n",
111            disp_get_domain_id(), iterations, sock);
112
113
114    for(int i = 0; i < iterations; ++i) {
115        debug_printf("[%"PRIuDOMAINID"]provide_echo_service(%d): calling read on the socket %d\n",
116                disp_get_domain_id(), i, sock);
117
118        ret = read(sock, buf, BUF_SIZE);
119        if(ret < 0) {
120            printf("[%"PRIuDOMAINID"]provide_echo_service(%d): ERROR: read failed\n",
121                    disp_get_domain_id(), i);
122            return;
123        }
124
125        debug_printf("[%"PRIuDOMAINID"]provide_echo_service(%d): read %d bytes (%s)\n",
126                disp_get_domain_id(), i, ret, buf);
127        ret = write(sock, buf, ret);
128        debug_printf("[%"PRIuDOMAINID"]provide_echo_service(%d): sent %d bytes\n",
129                disp_get_domain_id(), i, ret);
130
131        if(ret < 0) {
132            printf("[%"PRIuDOMAINID"]provide_echo_service(%d): ERROR: write failed\n",
133                    disp_get_domain_id(), i);
134            return;
135        }
136    } // end for: for each iteration
137    debug_printf("[%"PRIuDOMAINID"]provide_echo_service(): Done with %d iterations on socket %d\n",
138            disp_get_domain_id(), iterations, sock);
139
140} // end function: provide_echo_service
141
142
143static void network_setup_helper(void)
144{
145    debug_printf("[%"PRIuDOMAINID"]network_setup_helper():###### init lwip\n",
146            disp_get_domain_id());
147
148    waitset_init(&lwip_waitset);
149    thread_mutex_lock(&my_mutex);
150    // FIXME: replaced lwip_init_auto_ex with lwip_init_auto without testing
151//    lwip_init_auto_ex(&lwip_waitset, &my_mutex);
152
153    // lwip_init_auto();
154    tcpip_init(NULL, NULL); // FIXME: serious problem: why is it called after
155                        // calling lwip_init_auto? henc lwip_init_auto is
156                        // commented out (without testing!!!)
157    lwip_socket_init();
158    thread_mutex_unlock(&my_mutex);
159
160    debug_printf("[%"PRIuDOMAINID"]network_setup_helper():######### lwip initialized\n",
161            disp_get_domain_id());
162
163    // start an event dispatch thread
164
165    t = thread_create(poll_loop, NULL);
166    assert(t != NULL);
167
168    debug_printf("[%"PRIuDOMAINID"]network_setup_helper():######### polling thread created\n",
169            disp_get_domain_id());
170
171} // end function: network_setup_helper
172
173static void do_server(void)
174{
175    errval_t err;
176
177    int l_sock; // for listening
178    int c_sock; // for a connection
179    short int port = SERVER_PORT;
180    struct sockaddr_in servaddr;
181#ifndef UDP_TEST
182    struct sockaddr_in conn_addr;
183    socklen_t conn_addrlen = sizeof(conn_addr);
184#endif // UDP_TEST
185
186    debug_printf("[%"PRIuDOMAINID"]do_server(): Server started\n", disp_get_domain_id());
187    network_setup_helper();
188
189    debug_printf("[%"PRIuDOMAINID"]do_server(): server going to init lwip\n",
190            disp_get_domain_id());
191
192#ifndef UDP_TEST
193    // setup a server socket (tcp)
194    l_sock = socket(AF_INET, SOCK_STREAM, 0);
195#else
196    l_sock = socket(AF_INET, SOCK_DGRAM, 0);
197#endif // UDP_TEST
198
199    if (l_sock < 0) {
200        debug_printf("[%"PRIuDOMAINID"]do_server(): socket failed: %d errno: %d\n",
201                disp_get_domain_id(), l_sock, errno);
202        exit(EXIT_FAILURE);
203    }
204
205    debug_printf("[%"PRIuDOMAINID"]do_server(): listen socket created %d\n",
206            disp_get_domain_id(), l_sock);
207
208    // bind
209    memset(&servaddr, 0, sizeof(servaddr));
210    servaddr.sin_family      = AF_INET;
211    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
212    servaddr.sin_port        = htons(port);
213
214    if (bind(l_sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
215        debug_printf("[%"PRIuDOMAINID"]do_server(): Error calling bind() errno: %d\n",
216                disp_get_domain_id(), errno);
217        exit(EXIT_FAILURE);
218    }
219
220    debug_printf("[%"PRIuDOMAINID"]do_server(): ^^^^^^^^  listen socket bound to %d, now starting listen\n",
221            disp_get_domain_id(), port);
222
223
224#ifndef UDP_TEST
225    // listen
226    if (listen(l_sock, LISTENQ) < 0 ) {
227        debug_printf("[%"PRIuDOMAINID"]do_server(): Error calling listen() errno: %d\n",
228                disp_get_domain_id(), errno);
229        exit(EXIT_FAILURE);
230    }
231
232    debug_printf("[%"PRIuDOMAINID"]do_server(): listen socket listening\n",
233            disp_get_domain_id());
234
235    debug_printf("[%"PRIuDOMAINID"]do_server(): ^^^^^^^^^^^^^^^^^^^ calling accept on listen socket\n",
236            disp_get_domain_id());
237
238
239    while(1) {
240        // wait for connections
241        //    c_sock = lwip_accept(l_sock, NULL, NULL);
242        c_sock = accept(l_sock, (struct sockaddr*)&conn_addr, &conn_addrlen);
243        if (c_sock < 0) {
244            debug_printf("[%"PRIuDOMAINID"]do_server(): Error calling accept() errno: %d\n",
245                    disp_get_domain_id(), errno);
246            exit(EXIT_FAILURE);
247        }
248
249        debug_printf("[%"PRIuDOMAINID"]do_server(): ^^^^^^^^^^^^^^^^^^^ accepted a connection on socket %d\n",
250                disp_get_domain_id(), c_sock);
251        debug_printf("[%"PRIuDOMAINID"]do_server(): c_sock connected to: \n",
252                disp_get_domain_id());
253        debug_sin_print(&conn_addr);
254        debug_printf("[%"PRIuDOMAINID"]do_server(): port: %u\n",
255                disp_get_domain_id(), ntohs(conn_addr.sin_port));
256    #else
257        c_sock = l_sock;
258    #endif // UDP_TEST
259
260        // now echo incoming data
261        //        provide_echo_service(c_sock, 1);
262
263        if(FORKING_SERVER) {
264            debug_printf("[%"PRIuDOMAINID"]do_server(): ^^^^^^^^^^^^^^^^ ##### server_1: Forking\n",
265                    disp_get_domain_id());
266            err = spawn_child(c_sock);
267            if (err_is_fail(err)) {
268                debug_printf("[%"PRIuDOMAINID"]do_server(): failed to spawn child\n",
269                        disp_get_domain_id());
270                return;
271            }
272            debug_printf("[%"PRIuDOMAINID"]do_server(): ^^^^^^^^^^ ################ child spawned\n",
273                    disp_get_domain_id());
274        } // end if: FORKING_SERVER
275
276
277        debug_printf("[%"PRIuDOMAINID"]do_server(): closing connected socket %d\n",
278                disp_get_domain_id(), c_sock);
279        close(c_sock);
280
281
282    } // end while : infinite
283
284    // basically wait forever
285    thread_join(t, NULL);
286} // end function: do_server
287
288
289static void do_child(void)
290{
291    /* errval_t err; */
292    /* struct lwip_sockinfo si; */
293    debug_printf("[%"PRIuDOMAINID"]do_child():############# child  ###############\n",
294            disp_get_domain_id());
295
296    network_setup_helper(); // perform the basic network setup
297    posixcompat_unpack_fds(); // deserialize moved socket info into new sockets
298
299    debug_printf("[%"PRIuDOMAINID"]do_child():################ starting echo service\n",
300            disp_get_domain_id());
301
302    int c_sock = 4; // Socket which is a copy of accepted socket
303    provide_echo_service(c_sock, 10);
304
305    // basically wait forever
306    debug_printf("[%"PRIuDOMAINID"]do_child():####### waiting to join thread\n",
307                disp_get_domain_id());
308    thread_join(t, NULL);
309} // end function : do_child
310
311
312
313int main(int argc, char *argv[])
314{
315    coreid_t mycore = disp_get_core_id();
316
317    vfs_init();
318
319    debug_printf("[%"PRIuDOMAINID"]main(): This is %s on core %d with %d args\n",
320            disp_get_domain_id(), argv[0], mycore, argc);
321
322    if (argc > 1) {
323        do_server();
324    } else {
325        do_child();
326    }
327
328    debug_printf("[%"PRIuDOMAINID"]main(): Finished with everything, Exiting...\n",
329            disp_get_domain_id());
330
331    return EXIT_SUCCESS;
332} // end function : main
333