1/* 2 * $Id: aecho.c,v 1.9 2009-10-14 01:38:28 didg Exp $ 3 * 4 * Copyright (c) 1990,1991 Regents of The University of Michigan. 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby granted, 9 * provided that the above copyright notice appears in all copies and 10 * that both that copyright notice and this permission notice appear 11 * in supporting documentation, and that the name of The University 12 * of Michigan not be used in advertising or publicity pertaining to 13 * distribution of the software without specific, written prior 14 * permission. This software is supplied as is without expressed or 15 * implied warranties of any kind. 16 * 17 * Research Systems Unix Group 18 * The University of Michigan 19 * c/o Mike Clark 20 * 535 W. William Street 21 * Ann Arbor, Michigan 22 * +1-313-763-0525 23 * netatalk@itd.umich.edu 24 */ 25 26/* 27 * AppleTalk Echo Protocol Client 28 */ 29 30#ifdef HAVE_CONFIG_H 31#include "config.h" 32#endif /* HAVE_CONFIG_H */ 33 34#include <sys/types.h> 35#include <sys/param.h> 36#include <sys/socket.h> 37#include <sys/time.h> 38#include <errno.h> 39 40#include <signal.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#ifdef HAVE_NETDB_H 45#include <netdb.h> 46#endif /* HAVE_NETDB_H */ 47 48#include <netatalk/endian.h> 49#include <netatalk/at.h> 50#include <atalk/compat.h> 51#include <atalk/aep.h> 52#include <atalk/nbp.h> 53#include <atalk/netddp.h> 54#include <atalk/ddp.h> 55#include <atalk/util.h> 56 57/* FIXME/SOCKLEN_T: socklen_t is a unix98 feature */ 58#ifndef SOCKLEN_T 59#define SOCKLEN_T unsigned int 60#endif /* ! SOCKLEN_T */ 61 62static struct sockaddr_at target; 63static int sock; 64static unsigned int nsent = 0, nrecv = 0; 65static time_t totalms = 0, minms = -1, maxms = -1; 66static unsigned int pings = 0; 67 68static void usage(char *); 69 70static void done(int sig _U_) 71{ 72 if ( nsent) { 73 printf( "\n----%d.%d AEP Statistics----\n", 74 ntohs( target.sat_addr.s_net ), target.sat_addr.s_node ); 75 printf( "%d packets sent, %d packets received, %d%% packet loss\n", 76 nsent, nrecv, (( nsent - nrecv ) * 100 ) / nsent ); 77 if ( nrecv ) { 78 printf( "round-trip (ms) min/avg/max = %ld/%ld/%ld\n", 79 minms, totalms / nrecv, maxms ); 80 } 81 } 82 exit( 0 ); 83} 84 85static void aep_send(int sig _U_) 86{ 87 struct timeval tv; 88 char *p, buf[ 1024 ]; 89 static unsigned int seq = 0; 90 91 p = buf; 92 *p++ = DDPTYPE_AEP; 93 *p++ = AEPOP_REQUEST; 94 memcpy( p, &seq, sizeof( unsigned int )); 95 p += sizeof( unsigned int ); 96 seq++; 97 98 if ( gettimeofday( &tv, (struct timezone *)0 ) < 0 ) { 99 perror( "gettimeofday" ); 100 exit( 1 ); 101 } 102 memcpy( p, &tv, sizeof( struct timeval )); 103 p += sizeof( struct timeval ); 104 105 if ( netddp_sendto( sock, buf, p - buf, 0, (struct sockaddr *) &target, 106 sizeof( struct sockaddr_at )) < 0 ) { 107 perror( "sendto" ); 108 exit( 1 ); 109 } 110 nsent++; 111 if (pings && nsent > pings) done(0); 112} 113 114int main(int ac, char **av) 115{ 116 struct servent *se; 117 struct sigaction sv; 118 struct itimerval it; 119 struct sockaddr_at sat, saddr; 120 struct timeval tv, atv; 121 struct nbpnve nn; 122 char *obj = NULL, *type = "Workstation", *zone = "*"; 123 int cc; 124 SOCKLEN_T satlen; 125 unsigned int seq; 126 time_t ms; 127 char buf[ 1024 ], *p; 128 unsigned char port; 129 130 extern char *optarg; 131 extern int optind; 132 133 memset(&saddr, 0, sizeof(saddr)); 134 while (( cc = getopt( ac, av, "c:A:" )) != EOF ) { 135 switch ( cc ) { 136 case 'A': 137 if (!atalk_aton(optarg, &saddr.sat_addr)) { 138 fprintf(stderr, "Bad address.\n"); 139 exit(1); 140 } 141 break; 142 143 case 'c' : 144 pings = atoi( optarg ); 145 break; 146 147 default : 148 usage( av[ 0 ] ); 149 exit( 1 ); 150 } 151 } 152 if ( ac - optind != 1 ) { 153 usage( av[ 0 ] ); 154 exit( 1 ); 155 } 156 157 /* 158 * Save the port, since nbp_lookup calls getservbyname() to get the 159 * nbp port. 160 */ 161 if (( se = getservbyname( "echo", "ddp" )) == NULL ) 162 port = 4; 163 else 164 port = ntohs( se->s_port ); 165 166 memset( &target, 0, sizeof( struct sockaddr_at )); 167#ifdef BSD4_4 168 target.sat_len = sizeof( struct sockaddr_at ); 169#endif /* BSD4_4 */ 170 target.sat_family = AF_APPLETALK; 171 if ( !atalk_aton( av[ optind ], &target.sat_addr )) { 172 if ( nbp_name( av[ optind ], &obj, &type, &zone ) || !obj ) { 173 fprintf( stderr, "Bad name: %s\n", av[ optind ] ); 174 exit( 1 ); 175 } 176 if ( nbp_lookup( obj, type, zone, &nn, 1, &saddr.sat_addr) <= 0 ) { 177 fprintf( stderr, "Can't find: %s\n", av[ optind ] ); 178 exit( 1 ); 179 } 180 memcpy( &target, &nn.nn_sat, sizeof( struct sockaddr_at )); 181 } 182 target.sat_port = port; 183 184 if ((sock = netddp_open(saddr.sat_addr.s_net || saddr.sat_addr.s_node ? 185 &saddr : NULL, NULL)) < 0) { 186 perror("ddp_open"); 187 exit(1); 188 } 189 190 sv.sa_handler = aep_send; 191 sigemptyset( &sv.sa_mask ); 192 sigaddset( &sv.sa_mask, SIGINT ); 193 sv.sa_flags = SA_RESTART; 194 if ( sigaction( SIGALRM, &sv, (struct sigaction *)0 ) < 0 ) { 195 perror( "sigaction" ); 196 exit( 1 ); 197 } 198 199 sv.sa_handler = done; 200 sigemptyset( &sv.sa_mask ); 201 sigaddset( &sv.sa_mask, SIGALRM ); 202 sv.sa_flags = SA_RESTART; 203 if ( sigaction( SIGINT, &sv, (struct sigaction *)0 ) < 0 ) { 204 perror( "sigaction" ); 205 exit( 1 ); 206 } 207 208 it.it_interval.tv_sec = 1L; 209 it.it_interval.tv_usec = 0L; 210 it.it_value.tv_sec = 1L; 211 it.it_value.tv_usec = 0L; 212 213 if ( setitimer( ITIMER_REAL, &it, (struct itimerval *)0 ) < 0 ) { 214 perror( "setitimer" ); 215 exit( 1 ); 216 } 217 218 for (;;) { 219 satlen = sizeof( struct sockaddr_at ); 220 if (( cc = netddp_recvfrom( sock, buf, sizeof( buf ), 0, 221 (struct sockaddr *) &sat, 222 &satlen )) < 0 ) { 223 if ( errno == EINTR ) { 224 errno = 0; 225 continue; 226 } else { 227 perror( "recvfrom" ); 228 exit( 1 ); 229 } 230 } 231 p = buf; 232 if ( *p++ != DDPTYPE_AEP || *p++ != AEPOP_REPLY ) { 233 fprintf( stderr, "%s: bad packet!\n", av[ 0 ] ); 234 continue; 235 } 236 if ( gettimeofday( &tv, (struct timezone *)0 ) < 0 ) { 237 perror( "gettimeofday" ); 238 exit( 1 ); 239 } 240 memcpy( &seq, p, sizeof( unsigned int )); 241 p += sizeof( unsigned int ); 242 memcpy( &atv, p, sizeof( struct timeval )); 243 nrecv++; 244 ms = ( tv.tv_sec - atv.tv_sec ) * 1000 + 245 ( tv.tv_usec - atv.tv_usec ) / 1000; 246 totalms += ms; 247 if ( ms > maxms ) { 248 maxms = ms; 249 } 250 if ( ms < minms || minms == -1 ) { 251 minms = ms; 252 } 253 printf( "%d bytes from %u.%u: aep_seq=%d. time=%ld. ms\n", 254 cc, ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node, 255 seq, ms ); 256 if (pings && seq + 1 >= pings) done(0); 257 } 258} 259 260static void usage( char * av0 ) 261{ 262 fprintf( stderr, "usage:\t%s [-A source address ] [-c count] ( addr | nbpname )\n", av0 ); 263 exit( 1 ); 264} 265