1/* $NetBSD: sock_test.c,v 1.2.6.1 2012/06/05 21:15:19 bouyer Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1998-2001 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* Id: sock_test.c,v 1.55 2008/07/23 23:27:54 marka Exp */ 21 22#include <config.h> 23 24#include <stdlib.h> 25#include <string.h> 26#include <unistd.h> 27 28#include <isc/mem.h> 29#include <isc/print.h> 30#include <isc/task.h> 31#include <isc/socket.h> 32#include <isc/timer.h> 33#include <isc/util.h> 34 35isc_mem_t *mctx; 36isc_taskmgr_t *manager; 37 38static void 39my_shutdown(isc_task_t *task, isc_event_t *event) { 40 char *name = event->ev_arg; 41 42 printf("shutdown %s (%p)\n", name, task); 43 fflush(stdout); 44 isc_event_free(&event); 45} 46 47static void 48my_send(isc_task_t *task, isc_event_t *event) { 49 isc_socket_t *sock; 50 isc_socketevent_t *dev; 51 52 sock = event->ev_sender; 53 dev = (isc_socketevent_t *)event; 54 55 printf("my_send: %s task %p\n\t(sock %p, base %p, length %d, n %d, " 56 "result %d)\n", 57 (char *)(event->ev_arg), task, sock, 58 dev->region.base, dev->region.length, 59 dev->n, dev->result); 60 61 if (dev->result != ISC_R_SUCCESS) { 62 isc_socket_detach(&sock); 63 isc_task_shutdown(task); 64 } 65 66 isc_mem_put(mctx, dev->region.base, dev->region.length); 67 68 isc_event_free(&event); 69} 70 71static void 72my_recv(isc_task_t *task, isc_event_t *event) { 73 isc_socket_t *sock; 74 isc_socketevent_t *dev; 75 isc_region_t region; 76 char buf[1024]; 77 char host[256]; 78 79 sock = event->ev_sender; 80 dev = (isc_socketevent_t *)event; 81 82 printf("Socket %s (sock %p, base %p, length %d, n %d, result %d)\n", 83 (char *)(event->ev_arg), sock, 84 dev->region.base, dev->region.length, 85 dev->n, dev->result); 86 if (dev->address.type.sa.sa_family == AF_INET6) { 87 inet_ntop(AF_INET6, &dev->address.type.sin6.sin6_addr, 88 host, sizeof(host)); 89 printf("\tFrom: %s port %d\n", host, 90 ntohs(dev->address.type.sin6.sin6_port)); 91 } else { 92 inet_ntop(AF_INET, &dev->address.type.sin.sin_addr, 93 host, sizeof(host)); 94 printf("\tFrom: %s port %d\n", host, 95 ntohs(dev->address.type.sin.sin_port)); 96 } 97 98 if (dev->result != ISC_R_SUCCESS) { 99 isc_socket_detach(&sock); 100 101 isc_mem_put(mctx, dev->region.base, 102 dev->region.length); 103 isc_event_free(&event); 104 105 isc_task_shutdown(task); 106 return; 107 } 108 109 /* 110 * Echo the data back. 111 */ 112 if (strcmp(event->ev_arg, "so2") != 0) { 113 region = dev->region; 114 sprintf(buf, "\r\nReceived: %.*s\r\n\r\n", 115 (int)dev->n, (char *)region.base); 116 region.base = isc_mem_get(mctx, strlen(buf) + 1); 117 region.length = strlen(buf) + 1; 118 strcpy((char *)region.base, buf); /* strcpy is safe */ 119 isc_socket_send(sock, ®ion, task, my_send, event->ev_arg); 120 } else { 121 region = dev->region; 122 printf("\r\nReceived: %.*s\r\n\r\n", 123 (int)dev->n, (char *)region.base); 124 } 125 126 isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg); 127 128 isc_event_free(&event); 129} 130 131static void 132my_http_get(isc_task_t *task, isc_event_t *event) { 133 isc_socket_t *sock; 134 isc_socketevent_t *dev; 135 136 sock = event->ev_sender; 137 dev = (isc_socketevent_t *)event; 138 139 printf("my_http_get: %s task %p\n\t(sock %p, base %p, length %d, " 140 "n %d, result %d)\n", 141 (char *)(event->ev_arg), task, sock, 142 dev->region.base, dev->region.length, 143 dev->n, dev->result); 144 145 if (dev->result != ISC_R_SUCCESS) { 146 isc_socket_detach(&sock); 147 isc_task_shutdown(task); 148 isc_event_free(&event); 149 return; 150 } 151 152 isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg); 153 154 isc_event_free(&event); 155} 156 157static void 158my_connect(isc_task_t *task, isc_event_t *event) { 159 isc_socket_t *sock; 160 isc_socket_connev_t *dev; 161 isc_region_t region; 162 char buf[1024]; 163 164 sock = event->ev_sender; 165 dev = (isc_socket_connev_t *)event; 166 167 printf("%s: Connection result: %d\n", (char *)(event->ev_arg), 168 dev->result); 169 170 if (dev->result != ISC_R_SUCCESS) { 171 isc_socket_detach(&sock); 172 isc_event_free(&event); 173 isc_task_shutdown(task); 174 return; 175 } 176 177 /* 178 * Send a GET string, and set up to receive (and just display) 179 * the result. 180 */ 181 strcpy(buf, "GET / HTTP/1.1\r\nHost: www.flame.org\r\n" 182 "Connection: Close\r\n\r\n"); 183 region.base = isc_mem_get(mctx, strlen(buf) + 1); 184 region.length = strlen(buf) + 1; 185 strcpy((char *)region.base, buf); /* This strcpy is safe. */ 186 187 isc_socket_send(sock, ®ion, task, my_http_get, event->ev_arg); 188 189 isc_event_free(&event); 190} 191 192static void 193my_listen(isc_task_t *task, isc_event_t *event) { 194 char *name = event->ev_arg; 195 isc_socket_newconnev_t *dev; 196 isc_region_t region; 197 isc_socket_t *oldsock; 198 isc_task_t *newtask; 199 200 dev = (isc_socket_newconnev_t *)event; 201 202 printf("newcon %s (task %p, oldsock %p, newsock %p, result %d)\n", 203 name, task, event->ev_sender, dev->newsocket, dev->result); 204 fflush(stdout); 205 206 if (dev->result == ISC_R_SUCCESS) { 207 /* 208 * Queue another listen on this socket. 209 */ 210 isc_socket_accept(event->ev_sender, task, my_listen, 211 event->ev_arg); 212 213 region.base = isc_mem_get(mctx, 20); 214 region.length = 20; 215 216 /* 217 * Create a new task for this socket, and queue up a 218 * recv on it. 219 */ 220 newtask = NULL; 221 RUNTIME_CHECK(isc_task_create(manager, 0, &newtask) 222 == ISC_R_SUCCESS); 223 isc_socket_recv(dev->newsocket, ®ion, 1, 224 newtask, my_recv, event->ev_arg); 225 isc_task_detach(&newtask); 226 } else { 227 printf("detaching from socket %p\n", event->ev_sender); 228 oldsock = event->ev_sender; 229 230 isc_socket_detach(&oldsock); 231 232 isc_event_free(&event); 233 isc_task_shutdown(task); 234 return; 235 } 236 237 isc_event_free(&event); 238} 239 240static void 241timeout(isc_task_t *task, isc_event_t *event) { 242 isc_socket_t *sock = event->ev_arg; 243 244 printf("Timeout, canceling IO on socket %p (task %p)\n", sock, task); 245 246 isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_ALL); 247 isc_timer_detach((isc_timer_t **)&event->ev_sender); 248 isc_event_free(&event); 249} 250 251int 252main(int argc, char *argv[]) { 253 isc_task_t *t1, *t2; 254 isc_timermgr_t *timgr; 255 isc_time_t expires; 256 isc_interval_t interval; 257 isc_timer_t *ti1; 258 unsigned int workers; 259 isc_socketmgr_t *socketmgr; 260 isc_socket_t *so1, *so2; 261 isc_sockaddr_t sockaddr; 262 struct in_addr ina; 263 struct in6_addr in6a; 264 isc_result_t result; 265 int pf; 266 267 if (argc > 1) 268 workers = atoi(argv[1]); 269 else 270 workers = 2; 271 printf("%d workers\n", workers); 272 273 if (isc_net_probeipv6() == ISC_R_SUCCESS) 274 pf = PF_INET6; 275 else 276 pf = PF_INET; 277 278 /* 279 * EVERYTHING needs a memory context. 280 */ 281 mctx = NULL; 282 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); 283 284 /* 285 * The task manager is independent (other than memory context) 286 */ 287 manager = NULL; 288 RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &manager) == 289 ISC_R_SUCCESS); 290 291 /* 292 * Timer manager depends only on the memory context as well. 293 */ 294 timgr = NULL; 295 RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS); 296 297 t1 = NULL; 298 RUNTIME_CHECK(isc_task_create(manager, 0, &t1) == ISC_R_SUCCESS); 299 t2 = NULL; 300 RUNTIME_CHECK(isc_task_create(manager, 0, &t2) == ISC_R_SUCCESS); 301 RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, "1") == 302 ISC_R_SUCCESS); 303 RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, "2") == 304 ISC_R_SUCCESS); 305 306 printf("task 1 = %p\n", t1); 307 printf("task 2 = %p\n", t2); 308 309 socketmgr = NULL; 310 RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); 311 312 /* 313 * Open up a listener socket. 314 */ 315 so1 = NULL; 316 317 if (pf == PF_INET6) { 318 in6a = in6addr_any; 319 isc_sockaddr_fromin6(&sockaddr, &in6a, 5544); 320 } else { 321 ina.s_addr = INADDR_ANY; 322 isc_sockaddr_fromin(&sockaddr, &ina, 5544); 323 } 324 RUNTIME_CHECK(isc_socket_create(socketmgr, pf, isc_sockettype_tcp, 325 &so1) == ISC_R_SUCCESS); 326 result = isc_socket_bind(so1, &sockaddr, ISC_SOCKET_REUSEADDRESS); 327 RUNTIME_CHECK(result == ISC_R_SUCCESS); 328 RUNTIME_CHECK(isc_socket_listen(so1, 0) == ISC_R_SUCCESS); 329 330 /* 331 * Queue up the first accept event. 332 */ 333 RUNTIME_CHECK(isc_socket_accept(so1, t1, my_listen, "so1") 334 == ISC_R_SUCCESS); 335 isc_time_settoepoch(&expires); 336 isc_interval_set(&interval, 10, 0); 337 ti1 = NULL; 338 RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires, 339 &interval, t1, timeout, so1, &ti1) == 340 ISC_R_SUCCESS); 341 342 /* 343 * Open up a socket that will connect to www.flame.org, port 80. 344 * Why not. :) 345 */ 346 so2 = NULL; 347 ina.s_addr = inet_addr("204.152.184.97"); 348 if (0 && pf == PF_INET6) 349 isc_sockaddr_v6fromin(&sockaddr, &ina, 80); 350 else 351 isc_sockaddr_fromin(&sockaddr, &ina, 80); 352 RUNTIME_CHECK(isc_socket_create(socketmgr, isc_sockaddr_pf(&sockaddr), 353 isc_sockettype_tcp, 354 &so2) == ISC_R_SUCCESS); 355 356 RUNTIME_CHECK(isc_socket_connect(so2, &sockaddr, t2, 357 my_connect, "so2") == ISC_R_SUCCESS); 358 359 /* 360 * Detaching these is safe, since the socket will attach to the 361 * task for any outstanding requests. 362 */ 363 isc_task_detach(&t1); 364 isc_task_detach(&t2); 365 366 /* 367 * Wait a short while. 368 */ 369 sleep(10); 370 371 fprintf(stderr, "Destroying socket manager\n"); 372 isc_socketmgr_destroy(&socketmgr); 373 374 fprintf(stderr, "Destroying timer manager\n"); 375 isc_timermgr_destroy(&timgr); 376 377 fprintf(stderr, "Destroying task manager\n"); 378 isc_taskmgr_destroy(&manager); 379 380 isc_mem_stats(mctx, stdout); 381 isc_mem_destroy(&mctx); 382 383 return (0); 384} 385