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 34int ps(struct papfile *infile, struct papfile *outfile, struct sockaddr_at *sat); 35 36extern unsigned char connid, quantum, oquantum; 37 38static char buf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ]; 39static 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 */ 55int 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} 314