]> arthur.barton.de Git - netatalk.git/blob - bin/aecho/aecho.c
aecho -A fix.
[netatalk.git] / bin / aecho / aecho.c
1 /*
2  * $Id: aecho.c,v 1.5.8.1 2003-06-06 19:39:34 srittau 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
62 struct sockaddr_at      target;
63 int                     s, nsent = 0, nrecv = 0;
64 time_t                  totalms = 0, minms = -1, maxms = -1;
65 static unsigned int     pings = 0;
66
67 void usage(char *);
68
69 void done()
70 {
71     if ( nsent > 0 ) {
72         printf( "\n----%d.%d AEP Statistics----\n",
73                 ntohs( target.sat_addr.s_net ), target.sat_addr.s_node );
74         printf( "%d packets sent, %d packets received, %d%% packet loss\n",
75                 nsent, nrecv, (( nsent - nrecv ) * 100 ) / nsent );
76         if ( nrecv > 0 ) {
77             printf( "round-trip (ms)  min/avg/max = %ld/%ld/%ld\n",
78                     minms, totalms / nrecv, maxms );
79         }       
80     }
81     exit( 0 );
82 }
83   
84 void aep_send()
85 {
86     struct timeval      tv;
87     char                *p, buf[ 1024 ];
88     static unsigned int seq = 0;
89
90     p = buf;
91     *p++ = DDPTYPE_AEP;
92     *p++ = AEPOP_REQUEST;
93     memcpy( p, &seq, sizeof( unsigned int ));
94     p += sizeof( unsigned int );
95     seq++;
96
97     if ( gettimeofday( &tv, (struct timezone *)0 ) < 0 ) {
98         perror( "gettimeofday" );
99         exit( 1 );
100     }
101     memcpy( p, &tv, sizeof( struct timeval ));
102     p += sizeof( struct timeval );
103
104     if ( netddp_sendto( s, buf, p - buf, 0, (struct sockaddr *) &target,
105             sizeof( struct sockaddr_at )) < 0 ) {
106         perror( "sendto" );
107         exit( 1 );
108     }
109     nsent++;
110     if (pings && nsent > pings) done();
111 }
112
113 int main( ac, av )
114     int         ac;
115     char        **av;
116 {
117     struct servent      *se;
118     struct sigaction    sv;
119     struct itimerval    it;
120     struct sockaddr_at  sat, saddr;
121     struct timeval      tv, atv;
122     struct nbpnve       nn;
123     char                *obj = NULL, *type = "Workstation", *zone = "*";
124     int                 cc;
125     SOCKLEN_T           satlen;
126     unsigned int        seq;
127     time_t              ms;
128     char                buf[ 1024 ], *p;
129     unsigned char       port;
130
131     extern char         *optarg;
132     extern int          optind;
133   
134     memset(&saddr, 0, sizeof(saddr));
135     while (( cc = getopt( ac, av, "c:A:" )) != EOF ) {
136         switch ( cc ) {
137         case 'A':
138             if (!atalk_aton(optarg, &saddr.sat_addr)) {
139                 fprintf(stderr, "Bad address.\n");
140                 exit(1);
141             }
142             break;
143
144           case 'c' :
145             pings = atoi( optarg );
146             break;
147
148         default :
149             usage( av[ 0 ] );
150             exit( 1 );
151         }
152     }
153     if ( ac - optind != 1 ) {
154         usage( av[ 0 ] );
155         exit( 1 );
156     }
157     
158     /*
159      * Save the port, since nbp_lookup calls getservbyname() to get the
160      * nbp port.
161      */
162     if (( se = getservbyname( "echo", "ddp" )) == NULL ) 
163        port = 4;
164     else
165        port = ntohs( se->s_port );
166
167     memset( &target, 0, sizeof( struct sockaddr_at ));
168 #ifdef BSD4_4
169     target.sat_len = sizeof( struct sockaddr_at );
170 #endif /* BSD4_4 */
171     target.sat_family = AF_APPLETALK;
172     if ( !atalk_aton( av[ optind ], &target.sat_addr )) {
173         if ( nbp_name( av[ optind ], &obj, &type, &zone ) || !obj ) {
174             fprintf( stderr, "Bad name: %s\n", av[ optind ] );
175             exit( 1 );
176         }
177         if ( nbp_lookup( obj, type, zone, &nn, 1, &saddr.sat_addr) <= 0 ) {
178             fprintf( stderr, "Can't find: %s\n", av[ optind ] );
179             exit( 1 );
180         }
181         memcpy( &target, &nn.nn_sat, sizeof( struct sockaddr_at ));
182     }
183     target.sat_port = port;
184
185     if ((s = netddp_open(saddr.sat_addr.s_net || saddr.sat_addr.s_node ? 
186                          &saddr : NULL, NULL)) < 0) {
187        perror("ddp_open");
188        exit(1);
189     }        
190
191     sv.sa_handler = aep_send;
192     sigemptyset( &sv.sa_mask );
193     sigaddset( &sv.sa_mask, SIGINT );
194     sv.sa_flags = SA_RESTART;
195     if ( sigaction( SIGALRM, &sv, (struct sigaction *)0 ) < 0 ) {
196         perror( "sigaction" );
197         exit( 1 );
198     }
199
200     sv.sa_handler = done;
201     sigemptyset( &sv.sa_mask );
202     sigaddset( &sv.sa_mask, SIGALRM );
203     sv.sa_flags = SA_RESTART;
204     if ( sigaction( SIGINT, &sv, (struct sigaction *)0 ) < 0 ) {
205         perror( "sigaction" );
206         exit( 1 );
207     }
208
209     it.it_interval.tv_sec = 1L;
210     it.it_interval.tv_usec = 0L;
211     it.it_value.tv_sec = 1L;
212     it.it_value.tv_usec = 0L;
213
214     if ( setitimer( ITIMER_REAL, &it, (struct itimerval *)0 ) < 0 ) {
215         perror( "setitimer" );
216         exit( 1 );
217     }
218
219     for (;;) {
220         satlen = sizeof( struct sockaddr_at );
221         if (( cc = netddp_recvfrom( s, buf, sizeof( buf ), 0, 
222                                     (struct sockaddr *) &sat,
223                                     &satlen )) < 0 ) {
224             if ( errno == EINTR ) {
225                 errno = 0;
226                 continue;
227             } else {
228                 perror( "recvfrom" );
229                 exit( 1 );
230             }
231         }
232         p = buf;
233         if ( *p++ != DDPTYPE_AEP || *p++ != AEPOP_REPLY ) {
234             fprintf( stderr, "%s: bad packet!\n", av[ 0 ] );
235             continue;
236         }
237         if ( gettimeofday( &tv, (struct timezone *)0 ) < 0 ) {
238             perror( "gettimeofday" );
239             exit( 1 );
240         }
241         memcpy( &seq, p, sizeof( unsigned int ));
242         p += sizeof( unsigned int );
243         memcpy( &atv, p, sizeof( struct timeval ));
244         nrecv++;
245         ms = ( tv.tv_sec - atv.tv_sec ) * 1000 +
246                 ( tv.tv_usec - atv.tv_usec ) / 1000;
247         totalms += ms;
248         if ( ms > maxms ) {
249             maxms = ms;
250         }
251         if ( ms < minms || minms == -1 ) {
252             minms = ms;
253         }
254         printf( "%d bytes from %u.%u: aep_seq=%d. time=%ld. ms\n",
255                 cc, ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node,
256                 seq, ms );
257         if (pings && seq + 1 >= pings) done();
258     }
259 }
260
261 void usage( char * av0 )
262 {
263     fprintf( stderr, "usage:\t%s [-A source address ] [-c count] ( addr | nbpname )\n", av0 );
264     exit( 1 );
265 }