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