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