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