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