1/* 2 * $Id: asp_getsess.c,v 1.9 2009-10-13 22:55:37 didg Exp $ 3 * 4 * Copyright (c) 1990,1996 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#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include <errno.h> 16#include <signal.h> 17 18#ifdef HAVE_UNISTD_H 19#include <unistd.h> 20#endif /* HAVE_UNISTD_H */ 21 22#include <sys/types.h> 23#include <sys/time.h> 24#include <sys/uio.h> 25#include <sys/socket.h> 26#include <sys/param.h> 27#ifdef HAVE_SYS_WAIT_H 28#include <sys/wait.h> 29#endif /* HAVE_SYS_WAIT_H */ 30 31#include <netatalk/at.h> 32#include <atalk/logger.h> 33#include <atalk/compat.h> 34#include <atalk/atp.h> 35#include <atalk/asp.h> 36#include <atalk/server_child.h> 37 38#include "asp_child.h" 39 40#ifndef WEXITSTATUS 41#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 42#endif /* ! WEXITSTATUS */ 43#ifndef WIFEXITED 44#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 45#endif /* ! WIFEXITED */ 46 47#ifndef MIN 48#define MIN(a,b) ((a)<(b)?(a):(b)) 49#endif /* ! MIN */ 50 51static ASP server_asp; 52static struct server_child *children = NULL; 53static struct asp_child **asp_ac = NULL; 54 55/* send tickles and check tickle status of connections 56 * thoughts on using a hashed list: 57 * + child_cleanup, finding slots 58 * - tickle_handler, freeing, tickles 59 * if setup for a large number of connections, 60 * + space: if actual connections < potential 61 * - space: actual connections ~ potential 62 */ 63static void tickle_handler(int sig _U_) 64{ 65 int sid; 66 67 /* check status */ 68 for (sid = 0; sid < children->nsessions; sid++) { 69 if (asp_ac[sid] == NULL || asp_ac[sid]->ac_state == ACSTATE_DEAD) 70 continue; 71 72 if (++asp_ac[sid]->ac_state >= ACSTATE_BAD) { 73 /* kill. if already dead, just continue */ 74 if (kill( asp_ac[ sid ]->ac_pid, SIGTERM) == 0) 75 LOG(log_info, logtype_default, "asp_alrm: %d timed out", 76 asp_ac[ sid ]->ac_pid ); 77 78 asp_ac[ sid ]->ac_state = ACSTATE_DEAD; 79 continue; 80 } 81 82 /* send off a tickle */ 83 asp_tickle(server_asp, sid, &asp_ac[sid]->ac_sat); 84 } 85} 86 87static void child_cleanup(const pid_t pid) 88{ 89 int i; 90 91 for (i = 0; i < children->nsessions; i++) 92 if (asp_ac[i] && (asp_ac[i]->ac_pid == pid)) { 93 asp_ac[i]->ac_state = ACSTATE_DEAD; 94 break; 95 } 96} 97 98 99/* kill children */ 100void asp_kill(int sig) 101{ 102 if (children) 103 server_child_kill(children, CHILD_ASPFORK, sig); 104} 105 106void asp_stop_tickle(void) 107{ 108 if (server_asp && server_asp->inited) { 109 static const struct itimerval timer = {{0, 0}, {0, 0}}; 110 111 setitimer(ITIMER_REAL, &timer, NULL); 112 } 113} 114 115/* 116 * This call handles open, tickle, and getstatus requests. On a 117 * successful open, it forks a child process. 118 * It returns an ASP to the child and parent and NULL if there is 119 * an error. 120 */ 121static void set_asp_ac(int sid, struct asp_child *tmp); 122 123ASP asp_getsession(ASP asp, server_child *server_children, 124 const int tickleval) 125{ 126 struct sigaction action; 127 struct itimerval timer; 128 struct sockaddr_at sat; 129 struct atp_block atpb; 130 ATP atp; 131 struct iovec iov[ 8 ]; 132 pid_t pid; 133 int i, iovcnt, sid; 134 u_int16_t asperr; 135 char *buf; 136 int buflen; 137 138 if (!asp->inited) { 139 if (!(children = server_children)) 140 return NULL; 141 142 /* only calloc once */ 143 if (!asp_ac && (asp_ac = (struct asp_child **) 144 calloc(server_children->nsessions, sizeof(struct asp_child *))) 145 == NULL) 146 return NULL; 147 148 server_asp = asp; 149 150 /* install cleanup pointer */ 151 server_child_setup(children, CHILD_ASPFORK, child_cleanup); 152 153 /* install tickle handler 154 * we are the parent process 155 */ 156 memset(&action, 0, sizeof(action)); 157 action.sa_handler = tickle_handler; 158 sigemptyset(&action.sa_mask); 159 sigaddset(&action.sa_mask, SIGHUP); 160 sigaddset(&action.sa_mask, SIGTERM); 161 sigaddset(&action.sa_mask, SIGCHLD); 162 action.sa_flags = SA_RESTART; 163 164 timer.it_interval.tv_sec = timer.it_value.tv_sec = tickleval; 165 timer.it_interval.tv_usec = timer.it_value.tv_usec = 0; 166 if ((sigaction(SIGALRM, &action, NULL) < 0) || 167 (setitimer(ITIMER_REAL, &timer, NULL) < 0)) { 168 free(asp_ac); 169 server_asp = NULL; 170 asp_ac = NULL; 171 return NULL; 172 } 173 174 asp->inited = 1; 175 } 176 177 memset( &sat, 0, sizeof( struct sockaddr_at )); 178#ifdef BSD4_4 179 sat.sat_len = sizeof( struct sockaddr_at ); 180#endif /* BSD4_4 */ 181 sat.sat_family = AF_APPLETALK; 182 sat.sat_addr.s_net = ATADDR_ANYNET; 183 sat.sat_addr.s_node = ATADDR_ANYNODE; 184 sat.sat_port = ATADDR_ANYPORT; 185 atpb.atp_saddr = &sat; 186 atpb.atp_rreqdata = asp->cmdbuf; 187 atpb.atp_rreqdlen = sizeof( asp->cmdbuf ); 188 while ( atp_rreq( asp->asp_atp, &atpb ) < 0 ) { 189 if ( errno == EINTR || errno == EAGAIN ) { 190 continue; 191 } 192 return( NULL ); 193 } 194 195 switch ( asp->cmdbuf[ 0 ] ) { 196 case ASPFUNC_TICKLE: 197 sid = asp->cmdbuf[1]; 198 if ((asp_ac[sid] != NULL) && (asp_ac[sid]->ac_state != ACSTATE_DEAD)) 199 asp_ac[sid]->ac_state = ACSTATE_OK; 200 break; 201 202 case ASPFUNC_STAT : 203#ifdef EBUG 204 printf( "asp stat\n" ); 205#endif /* EBUG */ 206 if ( asp->asp_slen > 0 ) { 207 i = 0; 208 while(atpb.atp_bitmap) { 209 i++; 210 atpb.atp_bitmap >>= 1; 211 } 212 213 /* asp->data is big enough ... */ 214 memcpy( asp->data, asp->asp_status, MIN(asp->asp_slen, i*ASP_CMDSIZ)); 215 216 buflen = MIN(asp->asp_slen, i*ASP_CMDSIZ); 217 buf = asp->data; 218 iovcnt = 0; 219 220 /* If status information is too big to fit into the available 221 * ASP packets, we simply send as much as we can. 222 * Older client versions will most likely not be able to use 223 * the additional information anyway, like directory services 224 * or UTF8 server name. A very long fqdn could be a problem, 225 * we could end up with an invalid address list. 226 */ 227 do { 228 iov[ iovcnt ].iov_base = buf; 229 memmove(buf + ASP_HDRSIZ, buf, buflen); 230 memset( iov[ iovcnt ].iov_base, 0, ASP_HDRSIZ ); 231 232 if ( buflen > ASP_CMDSIZ ) { 233 buf += ASP_CMDMAXSIZ; 234 buflen -= ASP_CMDSIZ; 235 iov[ iovcnt ].iov_len = ASP_CMDMAXSIZ; 236 } else { 237 iov[ iovcnt ].iov_len = buflen + ASP_HDRSIZ; 238 buflen = 0; 239 } 240 iovcnt++; 241 } while ( iovcnt < i && buflen > 0 ); 242 243 atpb.atp_sresiovcnt = iovcnt; 244 atpb.atp_sresiov = iov; 245 atp_sresp( asp->asp_atp, &atpb ); 246 } 247 break; 248 249 case ASPFUNC_OPEN : 250 if (children->count < children->nsessions) { 251 struct asp_child *asp_ac_tmp; 252 253 /* find a slot */ 254 for (sid = 0; sid < children->nsessions; sid++) { 255 if (asp_ac[sid] == NULL) 256 break; 257 258 if (asp_ac[sid]->ac_state == ACSTATE_DEAD) { 259 free(asp_ac[sid]); 260 asp_ac[sid] = NULL; 261 break; 262 } 263 } 264 265 if ((atp = atp_open(ATADDR_ANYPORT, 266 &(atp_sockaddr(asp->asp_atp)->sat_addr))) == NULL) 267 return NULL; 268 269 int dummy[2]; 270 switch ((pid = fork())) { 271 case 0 : /* child */ 272 server_reset_signal(); 273 /* free/close some things */ 274 for (i = 0; i < children->nsessions; i++ ) { 275 if ( asp_ac[i] != NULL ) 276 free( asp_ac[i] ); 277 } 278 free(asp_ac); 279 280 server_child_free(children); 281 children = NULL; 282 atp_close(asp->asp_atp); 283 284 asp->child = 1; 285 asp->asp_atp = atp; 286 asp->asp_sat = sat; 287 asp->asp_wss = asp->cmdbuf[1]; 288 asp->asp_seq = 0; 289 asp->asp_sid = sid; 290 asp->asp_flags = ASPFL_SSS; 291 return asp; 292 293 case -1 : /* error */ 294 asp->cmdbuf[ 0 ] = 0; 295 asp->cmdbuf[ 1 ] = 0; 296 asperr = ASPERR_SERVBUSY; 297 break; 298 299 default : /* parent process */ 300 /* we need atomic setting or pb with tickle_handler */ 301 if (server_child_add(children, CHILD_ASPFORK, pid, dummy)) { 302 if ((asp_ac_tmp = malloc(sizeof(struct asp_child))) == NULL) { 303 kill(pid, SIGQUIT); 304 break; 305 } 306 asp_ac_tmp->ac_pid = pid; 307 asp_ac_tmp->ac_state = ACSTATE_OK; 308 asp_ac_tmp->ac_sat = sat; 309 asp_ac_tmp->ac_sat.sat_port = asp->cmdbuf[1]; 310 311 asp->cmdbuf[0] = atp_sockaddr(atp)->sat_port; 312 asp->cmdbuf[1] = sid; 313 set_asp_ac(sid, asp_ac_tmp); 314 asperr = ASPERR_OK; 315 break; 316 } else { 317 kill(pid, SIGQUIT); 318 break; 319 } 320 atp_close(atp); 321 break; 322 } 323 324 } else { 325 asp->cmdbuf[0] = asp->cmdbuf[1] = 0; 326 asperr = ASPERR_SERVBUSY; 327 } 328 329 memcpy( asp->cmdbuf + 2, &asperr, sizeof(asperr)); 330 iov[ 0 ].iov_base = asp->cmdbuf; 331 iov[ 0 ].iov_len = 4; 332 atpb.atp_sresiov = iov; 333 atpb.atp_sresiovcnt = 1; 334 atp_sresp( asp->asp_atp, &atpb ); 335 break; 336 337 default: 338 LOG(log_info, logtype_default, "ASPUnknown %d", asp->cmdbuf[0]); 339 break; 340 } 341 342 return asp; 343} 344 345/* with fn defined after use, assume it's not optimized by the compiler */ 346static void set_asp_ac(int sid, struct asp_child *tmp) 347{ 348 asp_ac[sid] = tmp; 349} 350