1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 # include <stdarg.h> 34 # include <limits.h> 35 # include <sys/types.h> 36 # include <poll.h> 37 # include <stropts.h> 38 # include <unistd.h> 39 #include <syslog.h> 40 41 # include "lpsched.h" 42 43 #define TURN_OFF(X,F) (void)Fcntl(X, F_SETFL, (Fcntl(X, F_GETFL, 0) & ~(F))) 44 45 46 static void conn_shutdown(); 47 48 extern int Filter_Status; 49 extern void dispatch(); 50 extern int Waitrequest; 51 void shutdown_messages(); 52 static char *Message; 53 static int MaxClients = 0, 54 do_msg(); 55 extern int Reserve_Fds; 56 extern int Shutdown; 57 58 MESG *Net_md; 59 60 /* 61 ** take_message() - WAIT FOR INTERRUPT OR ONE MESSAGE FROM USER PROCESS 62 */ 63 64 void take_message(void) 65 { 66 int bytes; 67 int i; 68 MESG * md; 69 70 for (EVER) { /* not really forever...returns are in the loop */ 71 if ((md = mlisten()) == NULL) 72 switch(errno) { 73 case EAGAIN: 74 case EINTR: 75 return; 76 77 case ENOMEM: 78 mallocfail(); 79 /* NOTREACHED */ 80 81 default: 82 fail ("Unexpected streams error in mlisten (%s).\n" , PERROR); 83 } 84 85 /* 86 * Check for a dropped connection to a child. 87 * Normally a child should tell us that it is dying 88 * (with S_SHUTDOWN or S_SEND_CHILD), but it may have 89 * died a fast death. We'll simulate the message we 90 * wanted to get so we can use the same code to clean up. 91 */ 92 if ((md->event & POLLHUP) && !(md->event & POLLIN) || 93 (md->event & (POLLERR|POLLNVAL))) { 94 switch (md->type) { 95 96 case MD_CHILD: 97 /* 98 * If the message descriptor is found in the 99 * exec table, it must be an interface pgm, 100 * notification, etc. Otherwise, it must be 101 * a network child. 102 */ 103 for (i = 0; Exec_Table[i] != NULL; i++) 104 if (Exec_Table[i]->md == md) 105 break; 106 107 if (Exec_Table[i] != NULL) { 108 (void) putmessage(Message, S_CHILD_DONE, 109 Exec_Table[i]->key, 0, 0); 110 } else { 111 (void) putmessage(Message, S_SHUTDOWN, 1); 112 } 113 bytes = 1; 114 break; 115 116 default: 117 bytes = -1; 118 break; 119 120 } 121 122 } else { 123 if (md->readfd == -1) { /* something happened to the readfd */ 124 syslog(LOG_DEBUG, "take_message: readfd is -1"); 125 return; 126 } 127 bytes = mread(md, Message, MSGMAX); 128 } 129 130 switch (bytes) { 131 case -1: 132 if (errno == EINTR) 133 return; 134 else 135 fail ("Unexpected streams error (%s).\n" , PERROR); 136 break; 137 138 case 0: 139 break; 140 141 default: 142 if (do_msg(md)) 143 return; 144 break; 145 } 146 } 147 } 148 149 /* 150 ** do_msg() - HANDLE AN INCOMING MESSAGE 151 */ 152 153 static int 154 do_msg(MESG *md) 155 { 156 int type = mtype(Message); 157 158 if (type != S_GOODBYE) { 159 md->wait = 0; 160 dispatch (type, Message, md); 161 /* 162 * The message may have caused the need to 163 * schedule something, so go back and check. 164 */ 165 return(1); 166 } 167 return(0); 168 } 169 170 /* 171 ** calculate_nopen() - DETERMINE # FILE DESCRIPTORS AVAILABLE FOR QUEUES 172 */ 173 174 static void 175 calculate_nopen(void) 176 { 177 int fd, nopen; 178 179 /* 180 * How many file descriptorss are currently being used? 181 */ 182 for (fd = nopen = 0; fd < OpenMax; fd++) 183 if (fcntl(fd, F_GETFL, 0) != -1) 184 nopen++; 185 186 /* 187 * How many file descriptors are available for use 188 * as open FIFOs? Leave one spare as a way to tell 189 * clients we don't have any to spare (hmmm....) and 190 * one for the incoming fifo. 191 */ 192 193 MaxClients = OpenMax; 194 MaxClients -= nopen; /* current overhead */ 195 MaxClients -= Reserve_Fds; 196 MaxClients -= 2; /* incoming FIFO and spare outgoing */ 197 MaxClients--; /* the requests log */ 198 MaxClients--; /* HPI routines and lpsched log */ 199 200 return; 201 } 202 203 static void conn_shutdown ( ) 204 { 205 if (!Shutdown) { 206 note ("The public connection \"%s\", has failed.\n", Lp_FIFO); 207 lpshut(1); 208 } 209 } 210 211 /* 212 ** init_messages() - INITIALIZE MAIN MESSAGE QUEUE 213 */ 214 215 void 216 init_messages(void) 217 { 218 char *cmd; 219 MESG * md; 220 221 (void) signal(SIGPIPE, SIG_IGN); 222 223 calculate_nopen (); 224 225 Message = (char *)Malloc(MSGMAX); 226 227 (void) Chmod(Lp_Tmp, 0711); 228 229 if ((md = mcreate(Lp_FIFO)) == NULL) 230 fail ("Can't create public message device (%s).\n", PERROR); 231 mon_discon(md, conn_shutdown); 232 233 if (mlisteninit(md) != 0) 234 if (errno == ENOMEM) 235 mallocfail(); 236 else 237 fail ("Unexpected streams error (%s).\n" , PERROR); 238 239 (void) Chmod(Lp_FIFO, 0666); 240 return; 241 } 242 243 244 void 245 shutdown_messages(void) 246 { 247 MESG *md; 248 249 (void) Chmod(Lp_Tmp, 0700); 250 (void) Chmod(Lp_FIFO, 0600); 251 md = mlistenreset(); 252 mdestroy(md); 253 } 254