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