// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // vim:set sts=4 ts=8: // Copyright (c) 2001-2007 International Computer Science Institute // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. #ident "$XORP: xorp/libcomm/test_connect.cc,v 1.5 2007/02/16 22:45:59 pavlin Exp $" #include "comm_module.h" #include "libxorp/xorp.h" #include "libxorp/debug.h" #include "libxorp/xorpfd.hh" #include "libxorp/eventloop.hh" #include "libxorp/xlog.h" #include "libxorp/ipv4.hh" #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_GETOPT_H #include #endif #include "libcomm/comm_api.h" static bool fd_connect_callback_called = false; static bool fd_success_connection = false; static IPv4 dst_addr; static uint16_t dst_port = 0; #define LIMIT_SECS 6 class ConnectCB { public: void connect_callback(XorpFd fd, IoEventType type); }; void ConnectCB::connect_callback(XorpFd fd, IoEventType type) { /* XXX: May trigger multiple times as data may be readable, * when using Selector as underlying dispatcher */ //fputc('.',stderr); if (fd_connect_callback_called == false) { printf("connect callback fired for first time\n"); fd_connect_callback_called = true; int is_conn = comm_sock_is_connected(fd); fd_success_connection = true; printf("comm_sock_is_connected() returned %d\n", is_conn); } UNUSED(fd); UNUSED(type); } static void run_test() { EventLoop e; ConnectCB cb; XorpFd s; int in_progress; int err; bool times_up = false; XorpTimer after; // XXX: Need to open socket, add to event loop, initiate connect s = comm_sock_open(AF_INET, SOCK_STREAM, IPPROTO_TCP, COMM_SOCK_NONBLOCKING); if (!s.is_valid()) { puts(comm_get_last_error_str()); exit(-1); } e.add_ioevent_cb(s, IOT_CONNECT, callback(&cb, &ConnectCB::connect_callback)); after = e.set_flag_after_ms(LIMIT_SECS * 1000, ×_up); struct in_addr dst_in_addr; dst_addr.copy_out(dst_in_addr); err = comm_sock_connect4(s, &dst_in_addr, htons(dst_port), COMM_SOCK_NONBLOCKING, &in_progress); if (err == XORP_ERROR) { if (in_progress != 1) { printf("Connection failed immediately"); exit(1); } } printf("connection in progress\n"); printf("comm_sock_is_connected() returned %d before eventloop\n", comm_sock_is_connected(s)); while (!times_up || fd_connect_callback_called || fd_success_connection) e.run(); if (fd_success_connection == true) { printf("successful completion\n"); } else if (times_up) { printf("%d seconds elapsed without a connect() completion\n", LIMIT_SECS); } else { printf("connection failed for some other reason.\n"); } e.remove_ioevent_cb(s, IOT_CONNECT); comm_sock_close(s); } /* ------------------------------------------------------------------------- */ /* Utility resolver function */ IPv4 lookup4(const char* addr) { const struct hostent* he = gethostbyname(addr); if (he == 0 || he->h_length < 4) { fprintf(stderr, "gethostbyname failed: %s %d\n", #ifdef HAVE_HSTRERROR hstrerror(h_errno), #else "", #endif #ifdef HOST_OS_WINDOWS WSAGetLastError() #else h_errno #endif ); exit(EXIT_FAILURE); } struct in_addr ia; memcpy(&ia, he->h_addr_list[0], sizeof(ia)); return IPv4(ia.s_addr); } static void usage() { fprintf(stderr, "usage: test_connect [-v] dst port\n"); fprintf(stderr, "tests non-blocking connect to dst and port.\n"); exit(1); } int main(int argc, char *argv[]) { comm_init(); // // Initialize and start xlog // xlog_init(argv[0], NULL); xlog_set_verbose(XLOG_VERBOSE_LOW); // Least verbose messages // XXX: verbosity of the error messages temporary increased xlog_level_set_verbose(XLOG_LEVEL_ERROR, XLOG_VERBOSE_HIGH); xlog_add_default_output(); xlog_start(); int ch; while ((ch = getopt(argc, argv, "hv")) != -1) { switch (ch) { case 'v': // doesn't do anything, it's a paste-o! break; default: usage(); break; } } argc -= optind; argv += optind; if (argc != 2) { usage(); } dst_addr = lookup4(argv[0]); dst_port = atoi(argv[1]); printf("Running \"connect\" to %s:%d\n", dst_addr.str().c_str(), dst_port); // Some of test generates warnings - under normal circumstances the // end user wants to know, but here not. xlog_disable(XLOG_LEVEL_WARNING); run_test(); // // Gracefully stop and exit xlog // xlog_stop(); xlog_exit(); comm_exit(); return (0); }