Home | History | Annotate | Download | only in msgs
      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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     27 /*	  All Rights Reserved  	*/
     28 
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.9	*/
     31 # include	<unistd.h>
     32 # include	<stdlib.h>
     33 # include	<string.h>
     34 # include	<poll.h>
     35 # include	<stropts.h>
     36 # include	<fcntl.h>
     37 # include	<errno.h>
     38 #include	<syslog.h>
     39 #include <user_attr.h>
     40 #include <secdb.h>
     41 #include <pwd.h>
     42 
     43 # include	"lp.h"
     44 # include	"msgs.h"
     45 
     46 #define TURN_ON(X,F)	(void)Fcntl(X, F_SETFL, (Fcntl(X, F_GETFL, 0)|(F)))
     47 
     48 static int		NumEvents = 0;
     49 static int		NumCons = 0;
     50 static int		ConsSize= 0;
     51 static int		NumNewCons = 0;
     52 static MESG **		Connections = NULL;
     53 static struct pollfd *	PollFdList = NULL;
     54 
     55 int
     56 mlisteninit(MESG * md)
     57 {
     58     if (md == NULL)
     59     {
     60 	errno = EINVAL;
     61 	return(-1);
     62     }
     63 
     64     if (ConsSize > 0)
     65     {
     66 	errno = EBUSY;
     67 	return(-1);
     68     }
     69 
     70     ConsSize = 20;
     71     Connections = (MESG **) Malloc(ConsSize * MDSIZE);
     72     PollFdList = (struct pollfd*) Malloc(ConsSize * sizeof(struct pollfd));
     73     if (Connections == NULL || PollFdList == NULL)
     74     {
     75 	errno = ENOMEM;
     76 	return(-1);
     77     }
     78     Connections[0] = md;
     79     PollFdList[0].fd = md->readfd;
     80     PollFdList[0].events = POLLIN;
     81     PollFdList[0].revents = 0;
     82     NumCons = 1;
     83     return(0);
     84 }
     85 
     86 int
     87 mlistenadd(MESG * md, short events)
     88 {
     89     int			slack;
     90     struct pollfd *	fdp;
     91 
     92     /*
     93     **	See if we have room in the connection table.
     94     **	Realloc(3) the table if the number of connections
     95     **	changes by more than 20.
     96     */
     97 
     98     slack = ConsSize - (NumCons + NumNewCons + 1);
     99 
    100     if (slack < 0)
    101     {
    102 	ConsSize += 20;
    103 	Connections = (MESG **) Realloc(Connections, ConsSize * MDSIZE);
    104 	PollFdList = (struct pollfd*) Realloc(PollFdList, ConsSize * sizeof(struct pollfd));
    105 	if (Connections == NULL || PollFdList == NULL)
    106 	{
    107 	    errno = ENOMEM;
    108 	    return(-1);
    109 	}
    110     }
    111 
    112     if (slack > 20)
    113     {
    114 	ConsSize -= 20;
    115 	Connections = (MESG **) Realloc(Connections, ConsSize * MDSIZE);
    116 	PollFdList = (struct pollfd*) Realloc(PollFdList, ConsSize * sizeof(struct pollfd));
    117 	if (Connections == NULL || PollFdList == NULL)
    118 	{
    119 	    errno = ENOMEM;
    120 	    return(-1);
    121 	}
    122     }
    123 
    124     fdp = PollFdList + (NumCons + NumNewCons);
    125     fdp->fd = md->readfd;
    126     fdp->events = events;
    127     fdp->revents = 0;
    128 
    129     /*
    130     **	Now add the entry to the connection table
    131     **	NumCons will be updated above.
    132     */
    133     Connections[NumCons + NumNewCons++] = md;
    134     return(0);
    135 }
    136 
    137 MESG *
    138 mlistenreset ( void )	/* funcdef */
    139 {
    140     int		x;
    141     MESG *	md;
    142 
    143     if (ConsSize == 0)
    144 	return(NULL);
    145 
    146     ConsSize = 0;
    147 
    148     for (x = 1; x < NumCons; x++)
    149 	(void) mdisconnect(Connections[x]);
    150 
    151     md = Connections[0];
    152 
    153     Free(Connections);
    154     Free(PollFdList);
    155 
    156     Connections = NULL;
    157     PollFdList = NULL;
    158     NumCons = 0;
    159     NumNewCons = 0;
    160     NumEvents = 0;
    161     return(md);
    162 }
    163 
    164 MESG *
    165 mlisten()
    166 {
    167     extern uid_t	Lp_Uid;
    168 
    169     MESG *		mdp;
    170     MESG *		md;
    171     MQUE *		p;
    172     int			flag = 0;
    173     int			disconacts;
    174     int			x;
    175     int			y;
    176     struct pollfd *	fdp;
    177     struct strrecvfd	recbuf;
    178 #if defined(NOCONNLD)
    179     struct strbuf	ctl;
    180     char		cbuff[MSGMAX];
    181 #endif
    182 
    183 #if defined(NOCONNLD)
    184     /*
    185     **	Set up buffer for receiving messages.
    186     */
    187     ctl.buf = cbuff;
    188     ctl.maxlen = sizeof (cbuff);
    189 #endif
    190 
    191     /*
    192     **	This loop exists to return control to poll after the
    193     **	result of poll yeilds no new connections or serviceable
    194     **	messages.
    195     */
    196     for (;;)
    197     {
    198 	/*
    199 	**	If there are no unserviced events pending, call poll(2)
    200 	**	and wait for a message or connection.
    201 	**	NumEvents may be -1 in the event of an interrupt, hence
    202 	**	<= 0
    203 	*/
    204 	if (NumEvents <= 0)
    205 	{
    206 	    /*
    207 	    **	Add new connections, if any, reset connection counter
    208 	    */
    209 	    NumCons += NumNewCons;
    210 	    NumNewCons = 0;
    211 
    212 	    if (NumCons <= 0)
    213 	    {
    214 		errno = EINTR;
    215 		return(NULL);
    216 	    }
    217 
    218 	    /*
    219 	    **	Scan the connection table and remove any holes
    220 	    */
    221 	    for (x = 0; x < NumCons; x++)
    222 	    {
    223 		mdp = Connections[x];
    224 
    225 		/*
    226 		**	Disconnected, clear the node and compress the
    227 		**	tables.  If the disconnect called any
    228 		**	on_discon functions (disconacts > 0), return
    229 		**	because there may be something to clean up.
    230 		**	Finally, decrement <x> so that the next node
    231 		**	doesn't get missed.
    232 		*/
    233 		if (mdp->readfd == -1)
    234 		{
    235 		    disconacts = mdisconnect(mdp);
    236 		    NumCons--;
    237 		    for (y = x; y < (NumCons + NumNewCons); y++)
    238 		    {
    239 			Connections[y] = Connections[y + 1];
    240 			PollFdList[y] = PollFdList[y + 1];
    241 		    }
    242 		    if (disconacts > 0)
    243 		    {
    244 			errno = EINTR;
    245 			return(NULL);
    246 		    }
    247 		    else
    248 			x--;
    249 		} else {
    250 		    /*
    251 		     * We are in "mlisten", POLLIN is always set.  We'll look
    252 		     * at POLLOUT possibility when mque is non-NULL.
    253 		     */
    254 		    PollFdList[x].events = POLLIN;
    255 		    if (mdp->mque)
    256 			PollFdList[x].events |= POLLOUT;
    257 		}
    258 	    }
    259 
    260 	    /*
    261 	    **	Wait for a message or a connection.
    262 	    **	This call may be interrupted by alarms used
    263 	    **	elsewhere, so if poll fails, return NULL and
    264 	    **	set errno to EAGAIN.
    265 	    */
    266 	    if ((NumEvents = poll(PollFdList, NumCons, -1)) < 0)
    267 	    {
    268 		errno = EAGAIN;
    269 		return(NULL);
    270 	    }
    271 	}
    272 
    273 	for (x = 0; x < NumCons; x++)
    274 	{
    275 	    mdp = Connections[x];
    276 	    fdp = PollFdList + x;
    277 
    278 	    if (fdp->revents == 0)
    279 		continue;
    280 
    281 	    switch (mdp->type) {
    282 	    case MD_MASTER:
    283 		/*
    284 		**	Only valid revent is: POLLIN
    285 		*/
    286 		if (fdp->revents != POLLIN)
    287 		{
    288 		    errno = EINVAL;
    289 		    return(NULL);
    290 		}
    291 
    292 		/*
    293 		**	Retrieve the file descriptor
    294 		*/
    295 		if (ioctl(mdp->readfd, I_RECVFD, &recbuf) != 0)
    296 		{
    297 		    if (errno == EINTR)
    298 		    {
    299 			errno = EAGAIN;
    300 			return(NULL);
    301 		    }
    302 		    if (errno == ENXIO)
    303 		    {
    304 			fdp->revents = 0;
    305 			NumEvents--;
    306 			continue;
    307 		    }
    308 #if defined(NOCONNLD)
    309 		    if (errno == EBADMSG)
    310 			while (Getmsg(mdp, &ctl, &ctl, &flag) >= 0);
    311 #endif
    312 		    return(NULL);
    313 		}
    314 
    315 		TURN_ON(recbuf.fd, O_NDELAY);
    316 		/*
    317 		**	Now, create the message descriptor
    318 		**	and populate it with what we know.
    319 		*/
    320 		if ((md = (MESG *)Malloc(MDSIZE)) == NULL)
    321 		{
    322 		    errno = ENOMEM;
    323 		    return(NULL);
    324 		}
    325 
    326 		memset(md, 0, sizeof (MESG));
    327 		md->gid = recbuf.gid;
    328 		md->readfd = md->writefd = recbuf.fd;
    329 		md->state = MDS_IDLE;
    330 		md->type = MD_UNKNOWN;
    331 		md->uid = recbuf.uid;
    332 
    333 		/*
    334 		 * Determine if a print administrator is contacting lpsched.
    335 		 * currently, root, lp and users with the "solaris.print.admin"
    336 		 * privilege are print administrators
    337 		 */
    338 		md->admin = (md->uid == 0 || md->uid == Lp_Uid);
    339 		if (md->admin == 0) {
    340 			struct passwd *pw = NULL;
    341 
    342 			if ((pw = getpwuid(md->uid)) != NULL)
    343 				md->admin = chkauthattr("solaris.print.admin",
    344 							pw->pw_name);
    345 		}
    346 
    347 		get_peer_label(md->readfd, &md->slabel);
    348 
    349 		if (mlistenadd(md, POLLIN) != 0)
    350 		    return(NULL);
    351 
    352 		ResetFifoBuffer (md->readfd);
    353 		/*
    354 		**	Reset fdp because mlistenadd may have
    355 		**	realloc()ed PollFdList and changed its
    356 		**	physical location.
    357 		*/
    358 		fdp = PollFdList + x;
    359 
    360 		/*
    361 		**	Clear the event that brought us here,
    362 		**	decrement the event counter, and get the
    363 		**	next event.
    364 		*/
    365 		fdp->revents = 0;
    366 		NumEvents--;
    367 		break;
    368 
    369 	    case MD_CHILD:
    370 		/*
    371 		**	If this connection is a child process, just
    372 		**	save the event and return the message descriptor
    373 		*/
    374 
    375 		if (fdp->revents & POLLOUT) {
    376 			if (mdp->mque) {
    377 				if (mflush(mdp) < 0) {
    378 					syslog(LOG_DEBUG,
    379 						"MD_CHILD mflush failed");
    380 				}
    381 			}
    382 		}
    383 
    384 		if (fdp->revents & POLLIN) {
    385 			mdp->event = fdp->revents;
    386 			NumEvents--;
    387 			fdp->revents = 0;
    388 			return (mdp);		/* we are in listening mode */
    389 		}
    390 
    391 		NumEvents--;
    392 		fdp->revents = 0;
    393 		break;
    394 
    395 	    default:
    396 		    /*
    397 		    **	POLLNVAL means this client disconnected and
    398 		    **	all messages have been processed.
    399 		    */
    400 		    if (fdp->revents & POLLNVAL) /* disconnected & no msg */
    401 		    {
    402 			if (mdp->readfd >= 0) {
    403 				Close (mdp->readfd);
    404 				if (mdp->writefd == mdp->readfd)
    405 					mdp->writefd = -1;
    406 				mdp->readfd = -1;
    407 			}
    408 			fdp->revents = 0;
    409 			NumEvents--;
    410 			continue;
    411 		    }
    412 
    413 		    /*
    414 		    **	POLLERR means an error message is on the
    415 		    **	stream.  Since this is totally unexpected,
    416 		    **	the assumption is made that this stream will
    417 		    **	be flagged POLLNVAL next time through poll
    418 		    **	and will be removed at that time.
    419 		    */
    420 		    if (fdp->revents & POLLERR)	/* uh, oh! */
    421 		    {
    422 			if (mdp->readfd >= 0) {
    423 				Close (mdp->readfd);
    424 				if (mdp->writefd == mdp->readfd)
    425 					mdp->writefd = -1;
    426 				mdp->readfd = -1;
    427 			}
    428 			NumEvents--;
    429 			fdp->revents = 0;
    430 			continue;
    431 		    }
    432 
    433 
    434 		    /*
    435 		    **	POLLHUP means the client aborted the call.
    436 		    **	The client is not removed, because there may
    437 		    **	still be messages on the stream.
    438 		    */
    439 		    if (fdp->revents & POLLHUP)	/* disconnected */
    440 		    {
    441 			NumEvents--;
    442 			fdp->revents = 0;
    443 			/*
    444 			 * MORE: This is odd. Why are we closing the
    445 			 * stream if there ``may still be messages''???
    446 			 */
    447 			if (mdp->readfd >= 0) {
    448 				Close (mdp->readfd);
    449 				if (mdp->writefd == mdp->readfd)
    450 					mdp->writefd = -1;
    451 				mdp->readfd = -1;
    452 			}
    453 			continue;
    454 
    455 			/*
    456 			 * MORE: Why is this here??
    457 			 *
    458 			if (mdp->type == MD_SYS_FIFO)
    459 			    (void) Close(mdp->writefd);
    460 
    461 			mdp->writefd = -1;
    462 
    463 			if (fdp->revents == POLLHUP)
    464 			{
    465 			    NumEvents--;
    466 			    fdp->revents = 0;
    467 			    (void) Close(mdp->readfd);
    468 			    mdp->readfd = -1;
    469 			    continue;
    470 			}
    471 			 *
    472 			 */
    473 		    }
    474 		    /*
    475 		    **	POLLOUT means that the client had a full
    476 		    **	stream and messages became backlogged and
    477 		    **	now the stream is empty.  So the queued msgs
    478 		    **	are sent with putmsg(2)
    479 		    */
    480 		    if (fdp->revents & POLLOUT)
    481 		    {
    482 			if (mdp->mque == NULL)
    483 			{
    484 			    NumEvents--;
    485 			    fdp->revents = 0;
    486 			    continue;
    487 			}
    488 			while (mdp->mque) {
    489 			    if (Putmsg(mdp, NULL, mdp->mque->dat, 0))
    490 				break;	/* failed for some reason */
    491 			    p = mdp->mque;
    492 			    mdp->mque = p->next;
    493 			    Free(p->dat->buf);
    494 			    Free(p->dat);
    495 			    Free(p);
    496 			}
    497 			NumEvents--;
    498 			fdp->revents = 0;
    499 			continue;
    500 		    }
    501 
    502 		    /*
    503 		    **	POLLIN means that there is a message on the
    504 		    **	stream.
    505 		    **	Return the message descriptor to the caller
    506 		    **	so that the message may be received and
    507 		    **	processed.
    508 		    */
    509 		    if (fdp->revents & POLLIN)	/* got a message */
    510 		    {
    511 			NumEvents--;
    512 			mdp->event = fdp->revents;
    513 			fdp->revents = 0;
    514 			if (mdp->type == MD_UNKNOWN)
    515 			    mdp->type = MD_STREAM;
    516 			return(mdp);
    517 		    }
    518 		    break;
    519 	    }
    520 	}
    521     }
    522 }
    523 
    524 # define	VOID_FUNC_PTR		void (*)()
    525 # define	PTR_TO_VOID_FUNC_PTR	void (**)()
    526 
    527 int
    528 mon_discon(MESG * md, void (*fn)())
    529 {
    530     int		size = 2;
    531     void	(**fnp) ();
    532 
    533     if (md->on_discon)
    534     {
    535 	for (fnp = md->on_discon; *fnp; fnp++)
    536 	    size++;
    537 	if ((md->on_discon = (PTR_TO_VOID_FUNC_PTR) Realloc (md->on_discon, size * sizeof(VOID_FUNC_PTR))) == NULL)
    538 	{
    539 	    errno = ENOMEM;
    540 	    return(-1);
    541 	}
    542     }
    543     else
    544 	if ((md->on_discon = (PTR_TO_VOID_FUNC_PTR) Malloc (size * sizeof(VOID_FUNC_PTR))) == NULL)
    545 	{
    546 	    errno = ENOMEM;
    547 	    return(-1);
    548 	}
    549 
    550     size--;
    551     md->on_discon[size] = NULL;
    552     size--;
    553     md->on_discon[size] = fn;
    554     return(0);
    555 }
    556