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