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