]> arthur.barton.de Git - netatalk.git/blob - bin/aecho/aecho.c
Remove bdb env on exit
[netatalk.git] / bin / aecho / aecho.c
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
62 static struct sockaddr_at       target;
63 static int                      sock;
64 static unsigned int             nsent = 0, nrecv = 0;
65 static time_t                   totalms = 0, minms = -1, maxms = -1;
66 static unsigned int             pings = 0;
67
68 static void usage(char *);
69
70 static 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   
85 static 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
114 int 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
260 static void usage( char * av0 )
261 {
262     fprintf( stderr, "usage:\t%s [-A source address ] [-c count] ( addr | nbpname )\n", av0 );
263     exit( 1 );
264 }