]> arthur.barton.de Git - netatalk.git/blob - libatalk/atp/atp_rsel.c
Remove bdb env on exit
[netatalk.git] / libatalk / atp / atp_rsel.c
1 /*
2  * $Id: atp_rsel.c,v 1.6 2009-10-14 01:38:28 didg Exp $
3  *
4  * Copyright (c) 1990,1997 Regents of The University of Michigan.
5  * All Rights Reserved. See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <sys/uio.h>
16 #include <signal.h>
17 #include <errno.h>
18
19 #include <netatalk/endian.h>
20 #include <netatalk/at.h>
21
22 #include <atalk/netddp.h>
23 #include <atalk/compat.h>
24 #include <atalk/atp.h>
25 #include <atalk/util.h>
26
27 #include "atp_internals.h"
28
29 #ifdef DROP_ATPTREL
30 static int      release_count = 0;
31 #endif /* DROP_ATPTREL */
32
33
34 static int
35 resend_request(ATP ah)
36 {
37     /*
38      * update bitmap and send request packet
39      */
40     struct atphdr       req_hdr;
41
42 #ifdef EBUG
43     printf( "\n<%d> resend_request: resending %ld byte request packet",
44             getpid(), ah->atph_reqpkt->atpbuf_dlen );
45     atp_print_addr( " to", &ah->atph_reqpkt->atpbuf_addr );
46     putchar( '\n' );
47     bprint( ah->atph_reqpkt->atpbuf_info.atpbuf_data,
48             ah->atph_reqpkt->atpbuf_dlen );
49 #endif /* EBUG */
50
51     memcpy( &req_hdr, ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, 
52         sizeof( struct atphdr ));
53     req_hdr.atphd_bitmap = ah->atph_rbitmap;
54     memcpy( ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, &req_hdr, 
55             sizeof( struct atphdr ));
56
57     gettimeofday( &ah->atph_reqtv, (struct timezone *)0 );
58     if ( netddp_sendto( ah->atph_socket,
59             ah->atph_reqpkt->atpbuf_info.atpbuf_data,
60             ah->atph_reqpkt->atpbuf_dlen, 0,
61             (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr,
62             sizeof( struct sockaddr_at )) != ah->atph_reqpkt->atpbuf_dlen ) {
63         return( -1 );
64     }
65
66     if ( ah->atph_reqtries > 0 ) {
67         --(ah->atph_reqtries);
68     }
69
70     return( 0 );
71 }
72
73 int
74 atp_rsel( 
75     ATP                 ah,             /* open atp handle */
76     struct sockaddr_at  *faddr,         /* address to receive from */
77     int                 func)           /* which function(s) to wait for;
78                                            0 means request or response */
79 {
80     struct atpbuf       *abuf, *pb, *cb;
81     struct atphdr       req_hdr, resp_hdr;
82     fd_set              fds;
83     int                 i, recvlen, requesting, mask, c;
84     u_int8_t            rfunc;
85     u_int16_t           tid;
86     struct timeval      tv;
87     struct sockaddr_at  saddr;
88
89 #ifdef EBUG
90     atp_print_bufuse( ah, "atp_rsel at top" );
91 #endif /* EBUG */
92     if ( func == 0 ) {
93         func = ATP_FUNCANY;
94     }
95
96     requesting = ( func & ATP_TRESP ) && ah->atph_rrespcount > 0 &&
97         ( ah->atph_reqtries > 0 || ah->atph_reqtries == ATP_TRIES_INFINITE );
98
99     if ( requesting && ah->atph_rbitmap == 0 ) {
100         /*
101          * we already have a complete atp response; just return
102          */
103         return( ATP_TRESP );
104     }
105
106     if (( abuf = atp_alloc_buf()) == NULL ) {
107         return( -1 );
108     }
109
110     if ( requesting ) {
111 #ifdef EBUG
112         printf( "<%d> atp_rsel: request pending\n", getpid());
113 #endif /* EBUG */
114         gettimeofday( &tv, (struct timezone *)0 );
115         if ( tv.tv_sec - ah->atph_reqtv.tv_sec > ah->atph_reqto ) {
116             if ( resend_request( ah ) < 0 ) {
117                 atp_free_buf( abuf );
118                 return( -1 );
119             }
120         }
121     }
122
123     for ( ;; ) {
124         rfunc = func;
125         if ( requesting ) {
126             FD_ZERO( &fds );
127             FD_SET( ah->atph_socket, &fds );
128             tv.tv_sec = ah->atph_reqto;
129             tv.tv_usec = 0;
130             if (( c = select( ah->atph_socket + 1, &fds, NULL, NULL,
131                     &tv )) < 0 ) {
132                 atp_free_buf( abuf );
133                 return( -1 );
134             }
135             if ( c == 0 || FD_ISSET( ah->atph_socket, &fds ) == 0 ) {
136                 recvlen = -1;
137                 errno = EINTR;
138                 goto timeout;
139             }
140         }
141         memcpy( &saddr, faddr, sizeof( struct sockaddr_at ));
142 #ifdef EBUG
143         printf( "<%d> atp_rsel calling recv_atp,", getpid());
144         atp_print_addr( " accepting from: ", &saddr );
145         putchar( '\n' );
146 #endif /* EBUG */
147         if (( recvlen = atp_recv_atp( ah, &saddr, &rfunc, ATP_TIDANY,
148                 abuf->atpbuf_info.atpbuf_data, 0 )) >= 0 ) {
149             break;      /* we received something */
150         }
151
152 timeout :
153         if ( !requesting || errno != EINTR ) {
154             break;      /* error */
155         }
156             
157         if ( ah->atph_reqtries <= 0 &&
158                 ah->atph_reqtries != ATP_TRIES_INFINITE ) {
159             errno = ETIMEDOUT;
160             break;
161         }
162         
163         if ( resend_request( ah ) < 0 ) {
164             break;      /* error */
165         }
166     }
167
168     if ( recvlen <= 0 ) {       /* error */
169         atp_free_buf( abuf );
170         return( recvlen );
171     }
172
173 #ifdef EBUG
174     printf( "<%d> atp_rsel: rcvd %d bytes", getpid(), recvlen );
175     atp_print_addr( " from: ", &saddr );
176     putchar( '\n' );
177     bprint( abuf->atpbuf_info.atpbuf_data, recvlen );
178 #endif /* EBUG */
179
180     abuf->atpbuf_dlen = (size_t) recvlen;
181     memcpy( &resp_hdr, abuf->atpbuf_info.atpbuf_data + 1,
182             sizeof( struct atphdr ));
183
184     if ( rfunc == ATP_TREQ ) {
185         /*
186          * we got a request: check to see if it is a duplicate (XO)
187          * while we are at it, we expire old XO responses from sent list
188          */
189         memcpy( &req_hdr, abuf->atpbuf_info.atpbuf_data + 1, 
190                 sizeof( struct atphdr ));
191         tid = ntohs( req_hdr.atphd_tid );
192         gettimeofday( &tv, (struct timezone *)0 );
193         for ( pb = NULL, cb = ah->atph_sent; cb != NULL;
194                 pb = cb, cb = cb->atpbuf_next ) {
195 #ifdef EBUG
196             printf( "<%d>", getpid());
197             atp_print_addr( " examining", &cb->atpbuf_addr );
198             printf( " %hu", cb->atpbuf_info.atpbuf_xo.atpxo_tid );
199             atp_print_addr( " (looking for", &saddr );
200             printf( " %hu)\n", tid );
201 #endif /* EBUG */
202             if ( tv.tv_sec - cb->atpbuf_info.atpbuf_xo.atpxo_tv.tv_sec
203                     > cb->atpbuf_info.atpbuf_xo.atpxo_reltime ) {
204                 /* discard expired response */
205 #ifdef EBUG
206                 printf( "<%d> expiring tid %hu\n", getpid(),
207                         cb->atpbuf_info.atpbuf_xo.atpxo_tid );
208 #endif /* EBUG */
209                 if ( pb == NULL ) {
210                     ah->atph_sent = cb->atpbuf_next;
211                 } else {
212                     pb->atpbuf_next = cb->atpbuf_next;
213                 }
214
215                 for ( i = 0; i < 8; ++i ) {
216                     if ( cb->atpbuf_info.atpbuf_xo.atpxo_packet[ i ]
217                             != NULL ) {
218                         atp_free_buf( cb->atpbuf_info.atpbuf_xo.atpxo_packet[ i ] );
219                     }
220                 }
221                 atp_free_buf( cb );
222
223                 if (( cb = pb ) == NULL )
224                     break;
225
226             } else if ( at_addr_eq( &saddr, &cb->atpbuf_addr )) {
227                 if ( cb->atpbuf_info.atpbuf_xo.atpxo_tid == tid ) {
228                     break;
229                 }
230             }
231         }
232
233         if ( cb != NULL ) {
234 #ifdef EBUG
235             printf( "<%d> duplicate request -- re-sending XO resp\n",
236                     getpid());
237 #endif /* EBUG */
238             /* matches an old response -- just re-send and reset expire */
239             cb->atpbuf_info.atpbuf_xo.atpxo_tv = tv;
240             for ( i = 0; i < 8; ++i ) {
241                 if ( cb->atpbuf_info.atpbuf_xo.atpxo_packet[i] != NULL &&
242                         req_hdr.atphd_bitmap & ( 1 << i )) {
243                     netddp_sendto( ah->atph_socket,
244                             cb->atpbuf_info.atpbuf_xo.atpxo_packet[i]->atpbuf_info.atpbuf_data,
245                             cb->atpbuf_info.atpbuf_xo.atpxo_packet[i]->atpbuf_dlen,
246                             0, (struct sockaddr *) &saddr, sizeof( struct sockaddr_at));
247                 }
248             }
249         }
250
251         if ( cb == NULL ) {
252             /* new request -- queue it and return */
253             memcpy( &abuf->atpbuf_addr, &saddr, sizeof( struct sockaddr_at ));
254             memcpy( faddr, &saddr, sizeof( struct sockaddr_at ));
255             abuf->atpbuf_next = ah->atph_queue;
256             ah->atph_queue = abuf;
257             return( ATP_TREQ );
258         } else {
259             atp_free_buf( abuf );
260             return( 0 );
261         }
262     }
263
264     /*
265      * we got a response: update bitmap
266      */
267     memcpy( &req_hdr, ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, 
268             sizeof( struct atphdr ));
269     if ( requesting && ah->atph_rbitmap & ( 1<<resp_hdr.atphd_bitmap )
270                 && req_hdr.atphd_tid == resp_hdr.atphd_tid ) {
271         ah->atph_rbitmap &= ~( 1<<resp_hdr.atphd_bitmap );
272
273         if ( ah->atph_resppkt[ resp_hdr.atphd_bitmap ] != NULL ) {
274             atp_free_buf( ah->atph_resppkt[ resp_hdr.atphd_bitmap ] );
275         }
276         ah->atph_resppkt[ resp_hdr.atphd_bitmap ] = abuf;
277
278         /* if End Of Message, clear all higher bitmap bits
279         */
280         if ( resp_hdr.atphd_ctrlinfo & ATP_EOM ) {
281 #ifdef EBUG
282             printf( "<%d> EOM -- seq num %d  current bitmap %d\n",
283                 getpid(), resp_hdr.atphd_bitmap, ah->atph_rbitmap );
284 #endif /* EBUG */
285             mask = 1 << resp_hdr.atphd_bitmap;
286             ah->atph_rbitmap &= ( mask | (mask-1) );
287         }
288
289         /* if Send Trans. Status, send updated request
290         */
291         if ( resp_hdr.atphd_ctrlinfo & ATP_STS ) {
292 #ifdef EBUG
293             puts( "STS" );
294 #endif /* EBUG */
295             req_hdr.atphd_bitmap = ah->atph_rbitmap;
296             memcpy(ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1,
297                    &req_hdr, sizeof( struct atphdr ));
298             if ( netddp_sendto( ah->atph_socket,
299                     ah->atph_reqpkt->atpbuf_info.atpbuf_data,
300                     ah->atph_reqpkt->atpbuf_dlen, 0,
301                     (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr,
302                     sizeof( struct sockaddr_at )) !=
303                     ah->atph_reqpkt->atpbuf_dlen ) {
304                 atp_free_buf( abuf );
305                 return( -1 );
306             }
307         }
308     } else {
309         /*
310          * we are not expecting this response -- toss it
311          */
312         atp_free_buf( abuf );
313 #ifdef EBUG
314         printf( "atp_rsel: ignoring resp bm=%x tid=%d (expected %x/%d)\n",
315                 resp_hdr.atphd_bitmap, ntohs( resp_hdr.atphd_tid ),
316                 ah->atph_rbitmap, ah->atph_tid );
317 #endif /* EBUG */
318     }
319
320     if ( !ah->atph_rbitmap && ( req_hdr.atphd_ctrlinfo & ATP_XO )) {
321         /*
322          * successful completion - send release
323          * the release consists of DDP type byte + ATP header + 4 user bytes
324          */
325         req_hdr.atphd_ctrlinfo = ATP_TREL;
326         memcpy( ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, &req_hdr, 
327             sizeof( struct atphdr ));
328         memset( ah->atph_reqpkt->atpbuf_info.atpbuf_data + ATP_HDRSIZE, 0, 4 );
329         ah->atph_reqpkt->atpbuf_dlen = sizeof( struct atphdr ) + ATP_HDRSIZE;
330 #ifdef EBUG
331         printf( "<%d> sending TREL", getpid() );
332         bprint( ah->atph_reqpkt->atpbuf_info.atpbuf_data,
333                 ah->atph_reqpkt->atpbuf_dlen );
334 #endif /* EBUG */
335 #ifdef DROP_ATPTREL
336         if (( ++release_count % 10 ) != 0 ) {
337 #endif /* DROP_ATPTREL */
338         netddp_sendto( ah->atph_socket, 
339                        ah->atph_reqpkt->atpbuf_info.atpbuf_data,
340                        ah->atph_reqpkt->atpbuf_dlen, 0,
341                        (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr,
342                        sizeof( struct sockaddr_at));
343 #ifdef DROP_ATPTREL
344         }
345 #endif /* DROP_ATPTREL */
346     }
347
348     if ( ah->atph_rbitmap != 0 ) {
349         if ( ah->atph_reqtries > 0
350                 || ah->atph_reqtries == ATP_TRIES_INFINITE ) {
351             return( 0 );
352         } else {
353             errno = ETIMEDOUT;
354             return( -1 );
355         }
356     }
357
358     memcpy( faddr, &saddr, sizeof( struct sockaddr_at ));
359     return( ATP_TRESP );
360 }