]> arthur.barton.de Git - netatalk.git/blob - etc/papd/session.c
sourceforge patch
[netatalk.git] / etc / papd / session.c
1 /*
2  * $Id: session.c,v 1.9 2001-08-08 18:12:48 rufustfirefly Exp $
3  *
4  * Copyright (c) 1990,1994 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #include <sys/errno.h>
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif /* HAVE_CONFIG_H */
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <sys/syslog.h>
17 #include <sys/time.h>
18 #include <sys/uio.h>
19 #include <netatalk/endian.h>
20 #include <netatalk/at.h>
21 #include <atalk/atp.h>
22 #include <atalk/pap.h>
23
24 #include "file.h"
25 #include "lp.h"
26 #include "session.h"
27
28 int ps(struct papfile *infile, struct papfile *outfile, struct sockaddr_at *sat);
29
30 extern unsigned char    connid, quantum, oquantum;
31
32 char            buf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
33 struct iovec    niov[ PAP_MAXQUANTUM ] = {
34     { buf[ 0 ], 0 },
35     { buf[ 1 ], 0 },
36     { buf[ 2 ], 0 },
37     { buf[ 3 ], 0 },
38     { buf[ 4 ], 0 },
39     { buf[ 5 ], 0 },
40     { buf[ 6 ], 0 },
41     { buf[ 7 ], 0 },
42 };
43 struct iovec    iov[ PAP_MAXQUANTUM ] = {
44     { buf[ 0 ] + 4,     0 },
45     { buf[ 1 ] + 4,     0 },
46     { buf[ 2 ] + 4,     0 },
47     { buf[ 3 ] + 4,     0 },
48     { buf[ 4 ] + 4,     0 },
49     { buf[ 5 ] + 4,     0 },
50     { buf[ 6 ] + 4,     0 },
51     { buf[ 7 ] + 4,     0 },
52 };
53
54 /*
55  * Accept files until the client closes the connection.
56  * Read lines of a file, until the client sends eof, after
57  * which we'll send eof also.
58  */
59 int session( atp, sat )
60     ATP                 atp;
61     struct sockaddr_at  *sat;
62 {
63     struct timeval      tv;
64     struct atp_block    atpb;
65     struct sockaddr_at  ssat;
66     struct papfile      infile, outfile;
67     fd_set              fds;
68     char                cbuf[ 578 ];
69     int                 i, cc, timeout = 0, readpending = 0;
70     u_int16_t           seq = 0, rseq = 1, netseq;
71     u_char              readport;
72
73     infile.pf_state = PF_BOT;
74     infile.pf_bufsize = 0;
75     infile.pf_datalen = 0;
76     infile.pf_buf = 0;
77     infile.pf_data = 0;
78
79     outfile.pf_state = PF_BOT;
80     outfile.pf_bufsize = 0;
81     outfile.pf_datalen = 0;
82     outfile.pf_buf = 0;
83     outfile.pf_data = 0;
84
85     /*
86      * Ask for data.
87      */
88     cbuf[ 0 ] = connid;
89     cbuf[ 1 ] = PAP_READ;
90     if (++seq == 0) seq = 1;
91     netseq = htons( seq );
92     memcpy( &cbuf[ 2 ], &netseq, sizeof( netseq ));
93     atpb.atp_saddr = sat;
94     atpb.atp_sreqdata = cbuf;
95     atpb.atp_sreqdlen = 4;              /* bytes in SendData request */
96     atpb.atp_sreqto = 5;                /* retry timer */
97     atpb.atp_sreqtries = -1;            /* infinite retries */
98     if ( atp_sreq( atp, &atpb, oquantum, ATP_XO )) {
99         syslog( LOG_ERR, "atp_sreq: %m" );
100         return( -1 );
101     }
102
103     for (;;) {
104         /*
105          * Time between tickles.
106          */
107         tv.tv_sec = 60;
108         tv.tv_usec = 0;
109
110         /*
111          * If we don't get anything for a while, time out.
112          */
113         FD_ZERO( &fds );
114         FD_SET( atp_fileno( atp ), &fds );
115
116         do { /* do list until success or an unrecoverable error occurs */
117           if (( cc = select( FD_SETSIZE, &fds, 0, 0, &tv )) < 0 )
118               syslog( LOG_ERR, "select: %m" ); /* log all errors */
119 `       } while (( cc < 0 ) && (errno == 4));
120
121         if ( cc < 0 ) {
122           syslog( LOG_ERR, "select: Error is unrecoverable" );
123           return( -1 );
124         }
125         if ( cc == 0 ) {
126             if ( timeout++ > 2 ) {
127                 syslog( LOG_ERR, "connection timed out" );
128                 lp_cancel();
129                 return( -1 );
130             }
131
132             /*
133              * Send a tickle.
134              */
135             cbuf[ 0 ] = connid;
136             cbuf[ 1 ] = PAP_TICKLE;
137             cbuf[ 2 ] = cbuf[ 3 ] = 0;
138             atpb.atp_saddr = sat;
139             atpb.atp_sreqdata = cbuf;
140             atpb.atp_sreqdlen = 4;              /* bytes in Tickle request */
141             atpb.atp_sreqto = 0;                /* best effort */
142             atpb.atp_sreqtries = 1;             /* try once */
143             if ( atp_sreq( atp, &atpb, 0, 0 )) {
144                 syslog( LOG_ERR, "atp_sreq: %m" );
145                 return( -1 );
146             }
147             continue;
148         } else {
149             timeout = 0;
150         }
151
152         memset( &ssat, 0, sizeof( struct sockaddr_at ));
153         switch( atp_rsel( atp, &ssat, ATP_TRESP | ATP_TREQ )) {
154         case ATP_TREQ :
155             atpb.atp_saddr = &ssat;
156             atpb.atp_rreqdata = cbuf;
157             atpb.atp_rreqdlen = sizeof( cbuf );
158             if ( atp_rreq( atp, &atpb ) < 0 ) {
159                 syslog( LOG_ERR, "atp_rreq: %m" );
160                 return( -1 );
161             }
162             /* sanity */
163             if ( (unsigned char)cbuf[ 0 ] != connid ) {
164                 syslog( LOG_ERR, "Bad ATP request!" );
165                 continue;
166             }
167
168             switch( cbuf[ 1 ] ) {
169             case PAP_READ :
170                 /*
171                  * Other side is ready for some data.
172                  */
173                 memcpy( &netseq, &cbuf[ 2 ], sizeof( netseq ));
174                 if ( netseq != 0 ) {
175                     if ( rseq != ntohs( netseq )) {
176                         break;
177                     }
178                     if ( rseq++ == 0xffff ) rseq = 1;
179                 }
180                 readpending = 1;
181                 readport = ssat.sat_port;
182                 break;
183
184             case PAP_CLOSE :
185                 /*
186                  * Respond to the close request.
187                  * If we're in the middle of a file, clean up.
188                  */
189                 if (( infile.pf_state & PF_BOT ) ||
190                         ( infile.pf_datalen == 0 &&
191                         ( infile.pf_state & PF_EOF ))) {
192                     lp_print();
193                 } else {
194                     lp_cancel();
195                 }
196
197                 niov[ 0 ].iov_len = 4;
198                 ((char *)niov[ 0 ].iov_base)[ 0 ] = connid;
199                 ((char *)niov[ 0 ].iov_base)[ 1 ] = PAP_CLOSEREPLY;
200                 ((char *)niov[ 0 ].iov_base)[ 2 ] =
201                         ((char *)niov[ 0 ].iov_base)[ 3 ] = 0;
202                 atpb.atp_sresiov = niov;
203                 atpb.atp_sresiovcnt = 1;
204                 if ( atp_sresp( atp, &atpb ) < 0 ) {
205                     syslog( LOG_ERR, "atp_sresp: %m" );
206                     exit( 1 );
207                 }
208                 return( 0 );
209                 break;
210
211             case PAP_TICKLE :
212                 break;
213             default :
214                 syslog( LOG_ERR, "Bad PAP request!" );
215             }
216
217             break;
218
219         case ATP_TRESP :
220             atpb.atp_saddr = &ssat;
221             for ( i = 0; i < oquantum; i++ ) {
222                 niov[ i ].iov_len = PAP_MAXDATA + 4;
223             }
224             atpb.atp_rresiov = niov;
225             atpb.atp_rresiovcnt = oquantum;
226             if ( atp_rresp( atp, &atpb ) < 0 ) {
227                 syslog( LOG_ERR, "atp_rresp: %m" );
228                 return( -1 );
229             }
230
231             /* sanity */
232             if ( ((unsigned char *)niov[ 0 ].iov_base)[ 0 ] != connid ||
233                     ((char *)niov[ 0 ].iov_base)[ 1 ] != PAP_DATA ) {
234                 syslog( LOG_ERR, "Bad data response!" );
235                 continue;
236             }
237
238             for ( i = 0; i < atpb.atp_rresiovcnt; i++ ) {
239                 append( &infile,
240                         niov[ i ].iov_base + 4, niov[ i ].iov_len - 4 );
241                 if (( infile.pf_state & PF_EOF ) == 0 &&
242                         ((char *)niov[ 0 ].iov_base)[ 2 ] ) {
243                     infile.pf_state |= PF_EOF;
244                 }
245             }
246
247             /* move data */
248             if ( ps( &infile, &outfile, sat ) < 0 ) {
249                 syslog( LOG_ERR, "parse: bad return" );
250                 return( -1 );   /* really?  close? */
251             }
252
253             /*
254              * Ask for more data.
255              */
256             cbuf[ 0 ] = connid;
257             cbuf[ 1 ] = PAP_READ;
258             if ( ++seq == 0 ) seq = 1;
259             netseq = htons( seq );
260             memcpy( &cbuf[ 2 ], &netseq, sizeof( netseq ));
261             atpb.atp_saddr = sat;
262             atpb.atp_sreqdata = cbuf;
263             atpb.atp_sreqdlen = 4;              /* bytes in SendData request */
264             atpb.atp_sreqto = 5;                /* retry timer */
265             atpb.atp_sreqtries = -1;            /* infinite retries */
266             if ( atp_sreq( atp, &atpb, oquantum, ATP_XO )) {
267                 syslog( LOG_ERR, "atp_sreq: %m" );
268                 return( -1 );
269             }
270             break;
271
272         case 0:
273             break;
274
275         default :
276             syslog( LOG_ERR, "atp_rsel: %m" );
277             return( -1 );
278         }
279
280         /* send any data that we have */
281         if ( readpending &&
282                 ( outfile.pf_datalen || ( outfile.pf_state & PF_EOF ))) {
283             for ( i = 0; i < quantum; i++ ) {
284                 ((char *)niov[ i ].iov_base)[ 0 ] = connid;
285                 ((char *)niov[ i ].iov_base)[ 1 ] = PAP_DATA;
286                 ((char *)niov[ i ].iov_base)[ 2 ] =
287                         ((char *)niov[ i ].iov_base)[ 3 ] = 0;
288
289                 if ( outfile.pf_datalen > PAP_MAXDATA  ) {
290                     cc = PAP_MAXDATA;
291                 } else {
292                     cc = outfile.pf_datalen;
293                     if ( outfile.pf_state & PF_EOF ) {
294                         ((char *)niov[ 0 ].iov_base)[ 2 ] = 1;  /* eof */
295                         outfile.pf_state = PF_BOT;
296                         infile.pf_state = PF_BOT;
297                     }
298                 }
299
300                 niov[ i ].iov_len = 4 + cc;
301                 memcpy( niov[ i ].iov_base + 4, outfile.pf_data, cc );
302                 CONSUME( &outfile, cc );
303                 if ( outfile.pf_datalen == 0 ) {
304                     i++;
305                     break;
306                 }
307             }
308             ssat.sat_port = readport;
309             atpb.atp_saddr = &ssat;
310             atpb.atp_sresiov = niov;
311             atpb.atp_sresiovcnt = i;    /* reported by stevebn@pc1.eos.co.uk */
312             if ( atp_sresp( atp, &atpb ) < 0 ) {
313                 syslog( LOG_ERR, "atp_sresp: %m" );
314                 return( -1 );
315             }
316             readpending = 0;
317         }
318     }
319 }