17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <syslog.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <thread.h>
327c478bd9Sstevel@tonic-gate #include <synch.h>
337c478bd9Sstevel@tonic-gate #include <slp-internal.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /* This is used to pass needed params to consumer_thr and slp_call */
367c478bd9Sstevel@tonic-gate struct thr_call_args {
377c478bd9Sstevel@tonic-gate 	slp_handle_impl_t *hp;
387c478bd9Sstevel@tonic-gate 	SLPGenericAppCB *cb;
397c478bd9Sstevel@tonic-gate 	void *cookie;
407c478bd9Sstevel@tonic-gate 	SLPMsgReplyCB *msg_cb;
417c478bd9Sstevel@tonic-gate 	slp_target_list_t *targets;
427c478bd9Sstevel@tonic-gate };
437c478bd9Sstevel@tonic-gate 
44*48d1bcbbSToomas Soome static void *consumer(void *);
45*48d1bcbbSToomas Soome static void *slp_call(void *);
467c478bd9Sstevel@tonic-gate static SLPError check_message_fit(slp_handle_impl_t *, slp_target_list_t *);
477c478bd9Sstevel@tonic-gate 
slp_ua_common(SLPHandle hSLP,const char * scopes,SLPGenericAppCB cb,void * cookie,SLPMsgReplyCB msg_cb)487c478bd9Sstevel@tonic-gate SLPError slp_ua_common(SLPHandle hSLP, const char *scopes,
49*48d1bcbbSToomas Soome     SLPGenericAppCB cb, void *cookie, SLPMsgReplyCB msg_cb)
50*48d1bcbbSToomas Soome {
517c478bd9Sstevel@tonic-gate 	slp_handle_impl_t *hp;
527c478bd9Sstevel@tonic-gate 	slp_target_list_t *targets;
537c478bd9Sstevel@tonic-gate 	struct thr_call_args *args;
547c478bd9Sstevel@tonic-gate 	slp_queue_t *q;
557c478bd9Sstevel@tonic-gate 	SLPError err;
567c478bd9Sstevel@tonic-gate 	thread_t tid;
577c478bd9Sstevel@tonic-gate 	int terr;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	hp = (slp_handle_impl_t *)hSLP;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	/* select targets */
627c478bd9Sstevel@tonic-gate 	if ((err = slp_new_target_list(hp, scopes, &targets)) != SLP_OK)
637c478bd9Sstevel@tonic-gate 		return (err);
647c478bd9Sstevel@tonic-gate 	if ((err = check_message_fit(hp, targets)) != SLP_OK) {
657c478bd9Sstevel@tonic-gate 		slp_destroy_target_list(targets);
667c478bd9Sstevel@tonic-gate 		return (err);
677c478bd9Sstevel@tonic-gate 	}
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	/* populate the args structure */
707c478bd9Sstevel@tonic-gate 	args = malloc(sizeof (*args));
717c478bd9Sstevel@tonic-gate 	if (args == NULL) {
727c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "ua_common", "out of memory");
737c478bd9Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	args->hp = hp;
777c478bd9Sstevel@tonic-gate 	args->cb = cb;
787c478bd9Sstevel@tonic-gate 	args->cookie = cookie;
797c478bd9Sstevel@tonic-gate 	args->msg_cb = msg_cb;
807c478bd9Sstevel@tonic-gate 	args->targets = targets;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	/* create the queue that this call will use */
837c478bd9Sstevel@tonic-gate 	q = slp_new_queue(&err);	/* freed in consumer_thr */
847c478bd9Sstevel@tonic-gate 	if (err != SLP_OK)
857c478bd9Sstevel@tonic-gate 		goto error;
867c478bd9Sstevel@tonic-gate 	hp->q = q;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	/* kick off the producer thread */
89*48d1bcbbSToomas Soome 	if ((terr = thr_create(NULL, 0, slp_call, args, 0, &tid)) != 0) {
907c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "ua_common", "could not start thread: %s",
91*48d1bcbbSToomas Soome 		    strerror(terr));
927c478bd9Sstevel@tonic-gate 		err = SLP_INTERNAL_SYSTEM_ERROR;
937c478bd9Sstevel@tonic-gate 		goto error;
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 	hp->producer_tid = tid;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if (hp->async) {
987c478bd9Sstevel@tonic-gate 		/* kick off the consumer thread */
99*48d1bcbbSToomas Soome 		if ((terr = thr_create(NULL, 0, consumer,
100*48d1bcbbSToomas Soome 		    args, 0, NULL)) != 0) {
1017c478bd9Sstevel@tonic-gate 			slp_err(LOG_CRIT, 0, "ua_common",
102*48d1bcbbSToomas Soome 			    "could not start thread: %s",
103*48d1bcbbSToomas Soome 			    strerror(terr));
1047c478bd9Sstevel@tonic-gate 			err = SLP_INTERNAL_SYSTEM_ERROR;
1057c478bd9Sstevel@tonic-gate 			/* cleanup producer thread, if necessary */
1067c478bd9Sstevel@tonic-gate 			hp->cancel = 1;
1077c478bd9Sstevel@tonic-gate 			(void) thr_join(tid, NULL, NULL);
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 			goto error;
1107c478bd9Sstevel@tonic-gate 		}
1117c478bd9Sstevel@tonic-gate 		return (SLP_OK);
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 	/* else	sync */
114*48d1bcbbSToomas Soome 	return ((SLPError)consumer(args));
1157c478bd9Sstevel@tonic-gate error:
1167c478bd9Sstevel@tonic-gate 	free(args);
1177c478bd9Sstevel@tonic-gate 	return (err);
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
120*48d1bcbbSToomas Soome static void *
consumer(void * ap)121*48d1bcbbSToomas Soome consumer(void *ap)
122*48d1bcbbSToomas Soome {
1237c478bd9Sstevel@tonic-gate 	slp_handle_impl_t *hp;
1247c478bd9Sstevel@tonic-gate 	char *reply;
1257c478bd9Sstevel@tonic-gate 	void *collator;
1267c478bd9Sstevel@tonic-gate 	int numResults = 0;
1277c478bd9Sstevel@tonic-gate 	struct thr_call_args *args = (struct thr_call_args *)ap;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	hp = args->hp;
1307c478bd9Sstevel@tonic-gate 	collator = NULL;
1317c478bd9Sstevel@tonic-gate 	hp->consumer_tid = thr_self();
1327c478bd9Sstevel@tonic-gate 	/* while cb wants more and there is more to get ... */
1337c478bd9Sstevel@tonic-gate 	for (;;) {
1347c478bd9Sstevel@tonic-gate 		SLPBoolean cont;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 		reply = slp_dequeue(hp->q);
1377c478bd9Sstevel@tonic-gate 		/* reply == NULL if no more available or SLPClosed */
1387c478bd9Sstevel@tonic-gate 		cont = args->msg_cb(hp, reply, args->cb, args->cookie,
139*48d1bcbbSToomas Soome 		    &collator, &numResults);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		if (reply) {
142*48d1bcbbSToomas Soome 			free(reply);
1437c478bd9Sstevel@tonic-gate 		} else {
144*48d1bcbbSToomas Soome 			break;
1457c478bd9Sstevel@tonic-gate 		}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 		if (!cont) {
148*48d1bcbbSToomas Soome 			/* cb doesn't want any more; invoke last call */
149*48d1bcbbSToomas Soome 			args->msg_cb(hp, NULL, args->cb, args->cookie,
150*48d1bcbbSToomas Soome 			    &collator, &numResults);
151*48d1bcbbSToomas Soome 			break;
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 	/* cleanup */
1557c478bd9Sstevel@tonic-gate 	/* clean stop producer [thread] */
1567c478bd9Sstevel@tonic-gate 	hp->cancel = 1;
1577c478bd9Sstevel@tonic-gate 	(void) thr_join(hp->producer_tid, NULL, NULL);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* empty and free queue */
1607c478bd9Sstevel@tonic-gate 	slp_flush_queue(hp->q, free);
1617c478bd9Sstevel@tonic-gate 	slp_destroy_queue(hp->q);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	free(args);
1647c478bd9Sstevel@tonic-gate 	slp_end_call(hp);
165*48d1bcbbSToomas Soome 	return ((void *)SLP_OK);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * This is the producer thread
1707c478bd9Sstevel@tonic-gate  */
171*48d1bcbbSToomas Soome static void *
slp_call(void * ap)172*48d1bcbbSToomas Soome slp_call(void *ap)
173*48d1bcbbSToomas Soome {
1747c478bd9Sstevel@tonic-gate 	struct thr_call_args *args = (struct thr_call_args *)ap;
1757c478bd9Sstevel@tonic-gate 	slp_target_t *t;
1767c478bd9Sstevel@tonic-gate 	const char *uc_scopes, *mc_scopes;
1777c478bd9Sstevel@tonic-gate 	SLPBoolean use_tcp = SLP_FALSE;
1787c478bd9Sstevel@tonic-gate 	size_t len;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* Unicast */
1817c478bd9Sstevel@tonic-gate 	if (uc_scopes = slp_get_uc_scopes(args->targets)) {
1827c478bd9Sstevel@tonic-gate 		size_t mtu;
1837c478bd9Sstevel@tonic-gate 		int i;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 		/* calculate msg length */
1867c478bd9Sstevel@tonic-gate 		len = slp_hdrlang_length(args->hp);
1877c478bd9Sstevel@tonic-gate 		for (i = 0; i < args->hp->msg.iovlen; i++) {
1887c478bd9Sstevel@tonic-gate 			len += args->hp->msg.iov[i].iov_len;
1897c478bd9Sstevel@tonic-gate 		}
1907c478bd9Sstevel@tonic-gate 		len += strlen(uc_scopes);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 		mtu = slp_get_mtu();
1937c478bd9Sstevel@tonic-gate 		if (len > mtu)
1947c478bd9Sstevel@tonic-gate 			use_tcp = SLP_TRUE;
1957c478bd9Sstevel@tonic-gate 
196*48d1bcbbSToomas Soome 		for (t = slp_next_uc_target(args->targets); t != NULL;
197*48d1bcbbSToomas Soome 		    t = slp_next_uc_target(args->targets)) {
1987c478bd9Sstevel@tonic-gate 			if (args->hp->cancel)
1997c478bd9Sstevel@tonic-gate 				break;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 			if (use_tcp)
2027c478bd9Sstevel@tonic-gate 				slp_uc_tcp_send(args->hp, t, uc_scopes,
203*48d1bcbbSToomas Soome 				    SLP_FALSE, 0);
2047c478bd9Sstevel@tonic-gate 			else
2057c478bd9Sstevel@tonic-gate 				slp_uc_udp_send(args->hp, t, uc_scopes);
2067c478bd9Sstevel@tonic-gate 		}
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/* Multicast */
2107c478bd9Sstevel@tonic-gate 	if ((!args->hp->cancel) &&
2117c478bd9Sstevel@tonic-gate 	    (mc_scopes = slp_get_mc_scopes(args->targets)))
2127c478bd9Sstevel@tonic-gate 		slp_mc_send(args->hp, mc_scopes);
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	/* Wait for TCP to complete, if necessary */
2157c478bd9Sstevel@tonic-gate 	if (args->hp->tcp_lock)
2167c478bd9Sstevel@tonic-gate 		slp_tcp_wait(args->hp);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	slp_destroy_target_list(args->targets);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	/* free the message */
2217c478bd9Sstevel@tonic-gate 	free(args->hp->msg.iov);
2227c478bd9Sstevel@tonic-gate 	free(args->hp->msg.msg);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	/* null terminate message queue */
2257c478bd9Sstevel@tonic-gate 	(void) slp_enqueue(args->hp->q, NULL);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	thr_exit(NULL);	/* we're outa here */
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * If the message to be sent needs to be multicast, check that it
2327c478bd9Sstevel@tonic-gate  * can fit into a datagram. If not, return BUFFER_OVERFLOW, otherwise
2337c478bd9Sstevel@tonic-gate  * return SLP_OK.
2347c478bd9Sstevel@tonic-gate  */
check_message_fit(slp_handle_impl_t * hp,slp_target_list_t * targets)2357c478bd9Sstevel@tonic-gate static SLPError check_message_fit(slp_handle_impl_t *hp,
2367c478bd9Sstevel@tonic-gate 					slp_target_list_t *targets) {
2377c478bd9Sstevel@tonic-gate 	size_t msgSize;
2387c478bd9Sstevel@tonic-gate 	int i;
2397c478bd9Sstevel@tonic-gate 	const char *mc_scopes;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	if (!(mc_scopes = slp_get_mc_scopes(targets)))
2427c478bd9Sstevel@tonic-gate 		return (SLP_OK);	/* no mc targets to worry about */
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	msgSize = slp_hdrlang_length(hp);
2457c478bd9Sstevel@tonic-gate 	for (i = 0; i < hp->msg.iovlen; i++) {
2467c478bd9Sstevel@tonic-gate 		msgSize += hp->msg.iov[i].iov_len;
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 	msgSize += strlen(mc_scopes);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if (msgSize > slp_get_mtu())
2517c478bd9Sstevel@tonic-gate 		return (SLP_BUFFER_OVERFLOW);
2527c478bd9Sstevel@tonic-gate 	return (SLP_OK);
2537c478bd9Sstevel@tonic-gate }
254