1f08c3bdfSopenharmony_ci/******************************************************************************/ 2f08c3bdfSopenharmony_ci/* */ 3f08c3bdfSopenharmony_ci/* Copyright (c) International Business Machines Corp., 2005 */ 4f08c3bdfSopenharmony_ci/* */ 5f08c3bdfSopenharmony_ci/* This program is free software; you can redistribute it and/or modify */ 6f08c3bdfSopenharmony_ci/* it under the terms of the GNU General Public License as published by */ 7f08c3bdfSopenharmony_ci/* the Free Software Foundation; either version 2 of the License, or */ 8f08c3bdfSopenharmony_ci/* (at your option) any later version. */ 9f08c3bdfSopenharmony_ci/* */ 10f08c3bdfSopenharmony_ci/* This program is distributed in the hope that it will be useful, */ 11f08c3bdfSopenharmony_ci/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12f08c3bdfSopenharmony_ci/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 13f08c3bdfSopenharmony_ci/* the GNU General Public License for more details. */ 14f08c3bdfSopenharmony_ci/* */ 15f08c3bdfSopenharmony_ci/* You should have received a copy of the GNU General Public License */ 16f08c3bdfSopenharmony_ci/* along with this program; if not, write to the Free Software */ 17f08c3bdfSopenharmony_ci/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18f08c3bdfSopenharmony_ci/* */ 19f08c3bdfSopenharmony_ci/******************************************************************************/ 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_ci/* 22f08c3bdfSopenharmony_ci * File: 23f08c3bdfSopenharmony_ci * ns-udpclient.c 24f08c3bdfSopenharmony_ci * 25f08c3bdfSopenharmony_ci * Description: 26f08c3bdfSopenharmony_ci * This is UDP traffic client. 27f08c3bdfSopenharmony_ci * Send UDP datagram to a server, then receive datagram from it 28f08c3bdfSopenharmony_ci * 29f08c3bdfSopenharmony_ci * Author: 30f08c3bdfSopenharmony_ci * Mitsuru Chinen <mitch@jp.ibm.com> 31f08c3bdfSopenharmony_ci * 32f08c3bdfSopenharmony_ci * History: 33f08c3bdfSopenharmony_ci * Oct 19 2005 - Created (Mitsuru Chinen) 34f08c3bdfSopenharmony_ci *---------------------------------------------------------------------------*/ 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_ci#include "ns-traffic.h" 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci/* 39f08c3bdfSopenharmony_ci * Fixed value 40f08c3bdfSopenharmony_ci */ 41f08c3bdfSopenharmony_ci#define MESSAGE_LEN 1000 /* The length of message */ 42f08c3bdfSopenharmony_ci#define RECVFROM_TIMEOUT 1 /* Timeout length of recvfrom() */ 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_ci/* 45f08c3bdfSopenharmony_ci * Gloval variables 46f08c3bdfSopenharmony_ci */ 47f08c3bdfSopenharmony_cistruct sigaction handler; /* Behavior for a signal */ 48f08c3bdfSopenharmony_ciint catch_sigalrm; /* When catch the SIGALRM, set to non-zero */ 49f08c3bdfSopenharmony_ciint catch_sighup; /* When catch the SIGHUP, set to non-zero */ 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci/* 52f08c3bdfSopenharmony_ci * Standard Header Files 53f08c3bdfSopenharmony_ci */ 54f08c3bdfSopenharmony_ci#include <stdio.h> 55f08c3bdfSopenharmony_ci#include <stdlib.h> 56f08c3bdfSopenharmony_ci#include <string.h> 57f08c3bdfSopenharmony_ci#include <errno.h> 58f08c3bdfSopenharmony_ci#include <fcntl.h> 59f08c3bdfSopenharmony_ci#include <netdb.h> 60f08c3bdfSopenharmony_ci#include <time.h> 61f08c3bdfSopenharmony_ci#include <unistd.h> 62f08c3bdfSopenharmony_ci#include <sys/socket.h> 63f08c3bdfSopenharmony_ci#include <sys/stat.h> 64f08c3bdfSopenharmony_ci#include <sys/types.h> 65f08c3bdfSopenharmony_ci#include <sys/wait.h> 66f08c3bdfSopenharmony_ci#include <netinet/in.h> 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci/* 69f08c3bdfSopenharmony_ci * Function: usage() 70f08c3bdfSopenharmony_ci * 71f08c3bdfSopenharmony_ci * Descripton: 72f08c3bdfSopenharmony_ci * Print the usage of this program. Then, terminate this program with 73f08c3bdfSopenharmony_ci * the specified exit value. 74f08c3bdfSopenharmony_ci * 75f08c3bdfSopenharmony_ci * Argument: 76f08c3bdfSopenharmony_ci * exit_value: exit value 77f08c3bdfSopenharmony_ci * 78f08c3bdfSopenharmony_ci * Return value: 79f08c3bdfSopenharmony_ci * This function does not return. 80f08c3bdfSopenharmony_ci */ 81f08c3bdfSopenharmony_civoid usage(char *program_name, int exit_value) 82f08c3bdfSopenharmony_ci{ 83f08c3bdfSopenharmony_ci FILE *stream = stdout; /* stream where the usage is output */ 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_ci if (exit_value == EXIT_FAILURE) 86f08c3bdfSopenharmony_ci stream = stderr; 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci fprintf(stream, "%s [OPTION]\n" 89f08c3bdfSopenharmony_ci "\t-S\tname or IP address of the server\n" 90f08c3bdfSopenharmony_ci "\t-f\tprotocol family\n" 91f08c3bdfSopenharmony_ci "\t\t 4 : IPv4\n" 92f08c3bdfSopenharmony_ci "\t\t 6 : IPv6\n" 93f08c3bdfSopenharmony_ci "\t-p\tport number\n" 94f08c3bdfSopenharmony_ci "\t-b\twork in the background\n" 95f08c3bdfSopenharmony_ci "\t-d\tdisplay debug informations\n" 96f08c3bdfSopenharmony_ci "\t-h\tdisplay this usage\n", program_name); 97f08c3bdfSopenharmony_ci exit(exit_value); 98f08c3bdfSopenharmony_ci} 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci/* 101f08c3bdfSopenharmony_ci * Function: set_signal_flag() 102f08c3bdfSopenharmony_ci * 103f08c3bdfSopenharmony_ci * Description: 104f08c3bdfSopenharmony_ci * This function sets global variables accordig to signal 105f08c3bdfSopenharmony_ci * 106f08c3bdfSopenharmony_ci * Argument: 107f08c3bdfSopenharmony_ci * type: type of signal 108f08c3bdfSopenharmony_ci * 109f08c3bdfSopenharmony_ci * Return value: 110f08c3bdfSopenharmony_ci * None 111f08c3bdfSopenharmony_ci */ 112f08c3bdfSopenharmony_civoid set_signal_flag(int type) 113f08c3bdfSopenharmony_ci{ 114f08c3bdfSopenharmony_ci if (debug) 115f08c3bdfSopenharmony_ci fprintf(stderr, "Catch signal. type is %d\n", type); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci switch (type) { 118f08c3bdfSopenharmony_ci case SIGHUP: 119f08c3bdfSopenharmony_ci catch_sighup = 1; 120f08c3bdfSopenharmony_ci handler.sa_handler = SIG_IGN; 121f08c3bdfSopenharmony_ci if (sigaction(type, &handler, NULL) < 0) 122f08c3bdfSopenharmony_ci fatal_error("sigaction()"); 123f08c3bdfSopenharmony_ci break; 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci case SIGALRM: 126f08c3bdfSopenharmony_ci catch_sigalrm = 1; 127f08c3bdfSopenharmony_ci break; 128f08c3bdfSopenharmony_ci default: 129f08c3bdfSopenharmony_ci fprintf(stderr, "Unexpected signal (%d) is caught\n", type); 130f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 131f08c3bdfSopenharmony_ci } 132f08c3bdfSopenharmony_ci} 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci/* 135f08c3bdfSopenharmony_ci * 136f08c3bdfSopenharmony_ci * Function: main() 137f08c3bdfSopenharmony_ci * 138f08c3bdfSopenharmony_ci */ 139f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 140f08c3bdfSopenharmony_ci{ 141f08c3bdfSopenharmony_ci char *program_name = argv[0]; 142f08c3bdfSopenharmony_ci int optc; /* option */ 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci sa_family_t family; /* protocol family */ 145f08c3bdfSopenharmony_ci char *server_name; /* Name (or IP address) of the server */ 146f08c3bdfSopenharmony_ci char *portnum; /* port number in string representation */ 147f08c3bdfSopenharmony_ci 148f08c3bdfSopenharmony_ci int sock_fd; /* socket descriptor to access */ 149f08c3bdfSopenharmony_ci int on; /* on/off at an socket option */ 150f08c3bdfSopenharmony_ci 151f08c3bdfSopenharmony_ci struct addrinfo hints; /* hints for getaddrinfo() */ 152f08c3bdfSopenharmony_ci struct addrinfo *res; /* pointer to addrinfo structure */ 153f08c3bdfSopenharmony_ci int err; /* return value of getaddrinfo */ 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_ci char *message; /* Pointer to the message */ 156f08c3bdfSopenharmony_ci char *recvbuf = NULL; /* Pointer to the message */ 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_ci int background = 0; /* work in the background if non-zero */ 159f08c3bdfSopenharmony_ci 160f08c3bdfSopenharmony_ci debug = 0; 161f08c3bdfSopenharmony_ci 162f08c3bdfSopenharmony_ci /* Initilalize the client information */ 163f08c3bdfSopenharmony_ci family = PF_UNSPEC; 164f08c3bdfSopenharmony_ci server_name = NULL; 165f08c3bdfSopenharmony_ci portnum = NULL; 166f08c3bdfSopenharmony_ci 167f08c3bdfSopenharmony_ci /* Retrieve the options */ 168f08c3bdfSopenharmony_ci while ((optc = getopt(argc, argv, "S:f:p:bdh")) != EOF) { 169f08c3bdfSopenharmony_ci switch (optc) { 170f08c3bdfSopenharmony_ci case 'S': 171f08c3bdfSopenharmony_ci server_name = strdup(optarg); 172f08c3bdfSopenharmony_ci if (server_name == NULL) { 173f08c3bdfSopenharmony_ci fprintf(stderr, "strdup() failed."); 174f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 175f08c3bdfSopenharmony_ci } 176f08c3bdfSopenharmony_ci break; 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_ci case 'f': 179f08c3bdfSopenharmony_ci if (strncmp(optarg, "4", 1) == 0) 180f08c3bdfSopenharmony_ci family = PF_INET; /* IPv4 */ 181f08c3bdfSopenharmony_ci else if (strncmp(optarg, "6", 1) == 0) 182f08c3bdfSopenharmony_ci family = PF_INET6; /* IPv6 */ 183f08c3bdfSopenharmony_ci else { 184f08c3bdfSopenharmony_ci fprintf(stderr, 185f08c3bdfSopenharmony_ci "protocol family should be 4 or 6.\n"); 186f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 187f08c3bdfSopenharmony_ci } 188f08c3bdfSopenharmony_ci break; 189f08c3bdfSopenharmony_ci 190f08c3bdfSopenharmony_ci case 'p': 191f08c3bdfSopenharmony_ci { 192f08c3bdfSopenharmony_ci unsigned long int tmp; 193f08c3bdfSopenharmony_ci tmp = strtoul(optarg, NULL, 0); 194f08c3bdfSopenharmony_ci if (tmp < PORTNUMMIN || PORTNUMMAX < tmp) { 195f08c3bdfSopenharmony_ci fprintf(stderr, 196f08c3bdfSopenharmony_ci "The range of port is from %u to %u\n", 197f08c3bdfSopenharmony_ci PORTNUMMIN, PORTNUMMAX); 198f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 199f08c3bdfSopenharmony_ci } 200f08c3bdfSopenharmony_ci portnum = strdup(optarg); 201f08c3bdfSopenharmony_ci } 202f08c3bdfSopenharmony_ci break; 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci case 'b': 205f08c3bdfSopenharmony_ci background = 1; 206f08c3bdfSopenharmony_ci break; 207f08c3bdfSopenharmony_ci 208f08c3bdfSopenharmony_ci case 'd': 209f08c3bdfSopenharmony_ci debug = 1; 210f08c3bdfSopenharmony_ci break; 211f08c3bdfSopenharmony_ci 212f08c3bdfSopenharmony_ci case 'h': 213f08c3bdfSopenharmony_ci usage(program_name, EXIT_SUCCESS); 214f08c3bdfSopenharmony_ci break; 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_ci default: 217f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 218f08c3bdfSopenharmony_ci } 219f08c3bdfSopenharmony_ci } 220f08c3bdfSopenharmony_ci 221f08c3bdfSopenharmony_ci /* Check the family is specified. */ 222f08c3bdfSopenharmony_ci if (family == PF_UNSPEC) { 223f08c3bdfSopenharmony_ci fprintf(stderr, "protocol family isn't specified.\n"); 224f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 225f08c3bdfSopenharmony_ci } 226f08c3bdfSopenharmony_ci 227f08c3bdfSopenharmony_ci /* Check the server name is specified. */ 228f08c3bdfSopenharmony_ci if (server_name == NULL) { 229f08c3bdfSopenharmony_ci fprintf(stderr, "server name isn't specified.\n"); 230f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 231f08c3bdfSopenharmony_ci } 232f08c3bdfSopenharmony_ci 233f08c3bdfSopenharmony_ci /* Check the port number is specified. */ 234f08c3bdfSopenharmony_ci if (portnum == NULL) { 235f08c3bdfSopenharmony_ci fprintf(stderr, "port number isn't specified.\n"); 236f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 237f08c3bdfSopenharmony_ci } 238f08c3bdfSopenharmony_ci 239f08c3bdfSopenharmony_ci /* If -b option is specified, work as a daemon */ 240f08c3bdfSopenharmony_ci if (background) 241f08c3bdfSopenharmony_ci if (daemon(0, 0) < 0) 242f08c3bdfSopenharmony_ci fatal_error("daemon()"); 243f08c3bdfSopenharmony_ci 244f08c3bdfSopenharmony_ci /* Set a signal handler against SIGALRM */ 245f08c3bdfSopenharmony_ci handler.sa_handler = set_signal_flag; 246f08c3bdfSopenharmony_ci handler.sa_flags = 0; 247f08c3bdfSopenharmony_ci if (sigfillset(&handler.sa_mask) < 0) 248f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 249f08c3bdfSopenharmony_ci if (sigaction(SIGALRM, &handler, NULL) < 0) 250f08c3bdfSopenharmony_ci fatal_error("sigaction()"); 251f08c3bdfSopenharmony_ci 252f08c3bdfSopenharmony_ci /* At first, SIGHUP are Ignored. */ 253f08c3bdfSopenharmony_ci handler.sa_handler = SIG_IGN; 254f08c3bdfSopenharmony_ci if (sigaction(SIGHUP, &handler, NULL) < 0) 255f08c3bdfSopenharmony_ci fatal_error("sigaction()"); 256f08c3bdfSopenharmony_ci 257f08c3bdfSopenharmony_ci /* Set the hints to addrinfo() */ 258f08c3bdfSopenharmony_ci memset(&hints, '\0', sizeof(struct addrinfo)); 259f08c3bdfSopenharmony_ci hints.ai_family = family; 260f08c3bdfSopenharmony_ci hints.ai_socktype = SOCK_DGRAM; 261f08c3bdfSopenharmony_ci hints.ai_protocol = IPPROTO_UDP; 262f08c3bdfSopenharmony_ci 263f08c3bdfSopenharmony_ci err = getaddrinfo(server_name, portnum, &hints, &res); 264f08c3bdfSopenharmony_ci if (err) { 265f08c3bdfSopenharmony_ci fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(err)); 266f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 267f08c3bdfSopenharmony_ci } 268f08c3bdfSopenharmony_ci if (res->ai_next) { 269f08c3bdfSopenharmony_ci fprintf(stderr, "getaddrinfo(): multiple address is found."); 270f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 271f08c3bdfSopenharmony_ci } 272f08c3bdfSopenharmony_ci 273f08c3bdfSopenharmony_ci /* Create a socket */ 274f08c3bdfSopenharmony_ci sock_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 275f08c3bdfSopenharmony_ci if (sock_fd < 0) 276f08c3bdfSopenharmony_ci fatal_error("socket()"); 277f08c3bdfSopenharmony_ci 278f08c3bdfSopenharmony_ci /* Enable to reuse the socket */ 279f08c3bdfSopenharmony_ci on = 1; 280f08c3bdfSopenharmony_ci if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int))) 281f08c3bdfSopenharmony_ci fatal_error("setsockopt()"); 282f08c3bdfSopenharmony_ci 283f08c3bdfSopenharmony_ci /* Create a message */ 284f08c3bdfSopenharmony_ci message = malloc(MESSAGE_LEN); 285f08c3bdfSopenharmony_ci if (debug) { 286f08c3bdfSopenharmony_ci strncpy(message, "Hello!", MESSAGE_LEN); 287f08c3bdfSopenharmony_ci message[MESSAGE_LEN - 1] = '\0'; 288f08c3bdfSopenharmony_ci } 289f08c3bdfSopenharmony_ci 290f08c3bdfSopenharmony_ci /* Prepare the buffer to store the received message */ 291f08c3bdfSopenharmony_ci recvbuf = malloc(MESSAGE_LEN + 1); 292f08c3bdfSopenharmony_ci if (recvbuf == NULL) { 293f08c3bdfSopenharmony_ci fprintf(stderr, "malloc() is failed.\n"); 294f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 295f08c3bdfSopenharmony_ci } 296f08c3bdfSopenharmony_ci 297f08c3bdfSopenharmony_ci /* 298f08c3bdfSopenharmony_ci * Loop for access to the server 299f08c3bdfSopenharmony_ci */ 300f08c3bdfSopenharmony_ci handler.sa_handler = set_signal_flag; 301f08c3bdfSopenharmony_ci if (sigaction(SIGHUP, &handler, NULL) < 0) 302f08c3bdfSopenharmony_ci fatal_error("sigaction()"); 303f08c3bdfSopenharmony_ci for (;;) { 304f08c3bdfSopenharmony_ci int recvlen; /* lenght of recevied message */ 305f08c3bdfSopenharmony_ci struct sockaddr_storage from_addr; /* address of a client */ 306f08c3bdfSopenharmony_ci socklen_t from_addr_len; /* length of `client_addr' */ 307f08c3bdfSopenharmony_ci 308f08c3bdfSopenharmony_ci /* Send the message to the server */ 309f08c3bdfSopenharmony_ci if (sendto(sock_fd, message, MESSAGE_LEN, 0, 310f08c3bdfSopenharmony_ci res->ai_addr, res->ai_addrlen) != MESSAGE_LEN) { 311f08c3bdfSopenharmony_ci if (catch_sighup) 312f08c3bdfSopenharmony_ci break; 313f08c3bdfSopenharmony_ci else 314f08c3bdfSopenharmony_ci fatal_error("sendto()"); 315f08c3bdfSopenharmony_ci } 316f08c3bdfSopenharmony_ci 317f08c3bdfSopenharmony_ci /* Receive the response from the server */ 318f08c3bdfSopenharmony_ci from_addr_len = sizeof(from_addr); 319f08c3bdfSopenharmony_ci alarm(RECVFROM_TIMEOUT); 320f08c3bdfSopenharmony_ci if ((recvlen = recvfrom(sock_fd, recvbuf, MESSAGE_LEN, 0, 321f08c3bdfSopenharmony_ci (struct sockaddr *)&from_addr, 322f08c3bdfSopenharmony_ci &from_addr_len)) < 0) { 323f08c3bdfSopenharmony_ci if (errno == EINTR) { 324f08c3bdfSopenharmony_ci if (catch_sighup) { 325f08c3bdfSopenharmony_ci break; 326f08c3bdfSopenharmony_ci } else if (catch_sigalrm) { 327f08c3bdfSopenharmony_ci if (debug) 328f08c3bdfSopenharmony_ci fprintf(stderr, 329f08c3bdfSopenharmony_ci "recvfrom() is timeout\n"); 330f08c3bdfSopenharmony_ci continue; 331f08c3bdfSopenharmony_ci } 332f08c3bdfSopenharmony_ci } 333f08c3bdfSopenharmony_ci fatal_error("recvfrom()"); 334f08c3bdfSopenharmony_ci } 335f08c3bdfSopenharmony_ci alarm(0); 336f08c3bdfSopenharmony_ci recvbuf[recvlen] = '\0'; 337f08c3bdfSopenharmony_ci if (debug) 338f08c3bdfSopenharmony_ci fprintf(stderr, "Message is %s\n", recvbuf); 339f08c3bdfSopenharmony_ci 340f08c3bdfSopenharmony_ci /* Catch sighup */ 341f08c3bdfSopenharmony_ci if (catch_sighup) 342f08c3bdfSopenharmony_ci break; 343f08c3bdfSopenharmony_ci } 344f08c3bdfSopenharmony_ci 345f08c3bdfSopenharmony_ci exit(EXIT_SUCCESS); 346f08c3bdfSopenharmony_ci} 347