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