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