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