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
5*9a70fc3bSMark J. Nelson  * Common Development and Distribution License (the "License").
6*9a70fc3bSMark J. Nelson  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
237c478bd9Sstevel@tonic-gate  * All rights reserved.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate //  Listener.java:    Organize basic listening for slpd and specifically
287c478bd9Sstevel@tonic-gate //                    support datagram listening.
297c478bd9Sstevel@tonic-gate //  Author:           James Kempf
307c478bd9Sstevel@tonic-gate //  Created On:       Mon May 18 12:43:50 1998
317c478bd9Sstevel@tonic-gate //  Last Modified By: James Kempf
327c478bd9Sstevel@tonic-gate //  Last Modified On: Thu Jan  7 08:39:19 1999
337c478bd9Sstevel@tonic-gate //  Update Count:     54
347c478bd9Sstevel@tonic-gate //
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate package com.sun.slp;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate import java.util.*;
397c478bd9Sstevel@tonic-gate import java.net.*;
407c478bd9Sstevel@tonic-gate import java.io.*;
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /**
437c478bd9Sstevel@tonic-gate  * This class supplies the basic listening function for the DA
447c478bd9Sstevel@tonic-gate  * and SA. On creation, a StreamListener is created to listen for
457c478bd9Sstevel@tonic-gate  * clients that need to initiate unicast connections. The main object
467c478bd9Sstevel@tonic-gate  * listens on the SLP multicast address for SLP multicasts, and
477c478bd9Sstevel@tonic-gate  * passes the results off to the RequestHandler for direction to
487c478bd9Sstevel@tonic-gate  * the proper table. The RequestHandler object is executed in a different
497c478bd9Sstevel@tonic-gate  * thread to maximize throughput. Note that unicast datagram requests
507c478bd9Sstevel@tonic-gate  * may also enter through this class, since many systems don't distinguish
517c478bd9Sstevel@tonic-gate  * between the multicast and datagram queues for a port.
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * @author James Kempf, Erik Guttman
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate class Listener extends Thread {
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate     private DatagramSocket dss = null; 	    // SLP multicast/broadcast socket.
597c478bd9Sstevel@tonic-gate     private InetAddress interfac = null;    // Interface on which we listen.
607c478bd9Sstevel@tonic-gate     private int pktsize = 0;	    	    // MTU of network packet.
617c478bd9Sstevel@tonic-gate     private Vector groups = new Vector();   // Multicast groups monitored.
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate     static private SLPConfig config = null; // Config object for properties
647c478bd9Sstevel@tonic-gate     static private Hashtable listeners =
657c478bd9Sstevel@tonic-gate 			new Hashtable();    // Listeners keyed by interface.
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate     // Initialize the complex of listener/sender objects on the interface.
687c478bd9Sstevel@tonic-gate     //  This includes a datagram listener, a DAAdvertiser (which shares
697c478bd9Sstevel@tonic-gate     //  the same socket as the datagram listener) if a DA, and a
707c478bd9Sstevel@tonic-gate     //  stream listener.
717c478bd9Sstevel@tonic-gate 
initializeInterfaceManagers(InetAddress interfac)727c478bd9Sstevel@tonic-gate     static void initializeInterfaceManagers(InetAddress interfac)
737c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	// If we've done the intializtion, forget it.
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	if (listeners.get(interfac) != null) {
787c478bd9Sstevel@tonic-gate 	    return;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	// Get config object.
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	if (config == null) {
857c478bd9Sstevel@tonic-gate 	    config = SLPConfig.getSLPConfig();
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	// Create a listener object for this interface.
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	Listener listener = new Listener(interfac);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	// Start thread to listen for incoming datagram request.
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	listener.start();
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	// Create a stream listener object for this interface.
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	StreamListener.initializeStreamListenerOnInterface(interfac);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	// We wait until this point to advertise ourselves as DAs. At
1027c478bd9Sstevel@tonic-gate 	//  this point, we have the listeners up to handle any messages
1037c478bd9Sstevel@tonic-gate 	//  that might come in as a result.
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate     }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate     // Return the socket for the listener on the designated interface.
1087c478bd9Sstevel@tonic-gate     //  DAAdvertisers and the SLPv1 codes uses this to share the
1097c478bd9Sstevel@tonic-gate     //  same socket as the main datagram listener.
1107c478bd9Sstevel@tonic-gate 
returnListenerSocketOnInterface( InetAddress interfac)1117c478bd9Sstevel@tonic-gate     static DatagramSocket returnListenerSocketOnInterface(
1127c478bd9Sstevel@tonic-gate 						InetAddress interfac) {
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	Listener listener = (Listener)listeners.get(interfac);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	if (listener != null) {
1177c478bd9Sstevel@tonic-gate 	    return listener.dss;
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	return null;
1217c478bd9Sstevel@tonic-gate     }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate     // Add the listener on the interface to the multicast group.
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate     static void
addListenerToMulticastGroup(InetAddress interfac, InetAddress maddr)1267c478bd9Sstevel@tonic-gate 	addListenerToMulticastGroup(InetAddress interfac, InetAddress maddr)
1277c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	Listener listener = (Listener)listeners.get(interfac);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	// Ignore if we haven't got it.
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	if (listener == null) {
1347c478bd9Sstevel@tonic-gate 	    return;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	DatagramSocket dss = listener.dss;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	// Only add if we're multicast.
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if (dss instanceof MulticastSocket) {
1437c478bd9Sstevel@tonic-gate 	    MulticastSocket mss = (MulticastSocket)dss;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	    try {
1467c478bd9Sstevel@tonic-gate 		mss.joinGroup(maddr);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 		// Record the groups monitored.
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 		listener.groups.addElement(maddr);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	    } catch (IOException ex) {
1537c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1547c478bd9Sstevel@tonic-gate 				ServiceLocationException.NETWORK_INIT_FAILED,
1557c478bd9Sstevel@tonic-gate 				"socket_initializtion_failure",
1567c478bd9Sstevel@tonic-gate 				new Object[] {maddr, ex.getMessage()});
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	    }
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate     }
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate     // Refresh the listener socket on the interface. If there is no
1637c478bd9Sstevel@tonic-gate     //  listener, then simply return a new send socket.
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate     static DatagramSocket
refreshSocketOnInterface(InetAddress interfac)1667c478bd9Sstevel@tonic-gate 	refreshSocketOnInterface(InetAddress interfac) {
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	Listener listener = (Listener)listeners.get(interfac);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if (listener == null) {
1717c478bd9Sstevel@tonic-gate 	    return config.refreshMulticastSocketOnInterface(interfac, null);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	listener.dss.close();
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	listener.dss =
1787c478bd9Sstevel@tonic-gate 	    config.refreshMulticastSocketOnInterface(interfac,
1797c478bd9Sstevel@tonic-gate 						     listener.groups);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	return listener.dss;
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate     }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate     // Create a Listener for the interface.
1867c478bd9Sstevel@tonic-gate 
Listener(InetAddress interfac)1877c478bd9Sstevel@tonic-gate     private Listener(InetAddress interfac) throws ServiceLocationException {
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	// Get packet size.
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	this.pktsize = config.getMTU();
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	this.interfac = interfac;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	// Get a socket for this interface.
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	this.dss = config.getMulticastSocketOnInterface(interfac, false);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	// Record here so we can use standard utility to add to multicast
2007c478bd9Sstevel@tonic-gate 	// group.
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	listeners.put(interfac, this);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	// If we're multicasting, add to the default SLP group.
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	addListenerToMulticastGroup(interfac, config.getMulticastAddress());
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate     }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate     // Listen on multicast for incoming requests, spawn a RequestHandler
2117c478bd9Sstevel@tonic-gate     //  to process the datagram.
2127c478bd9Sstevel@tonic-gate 
run()2137c478bd9Sstevel@tonic-gate     public void run()  {
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	boolean retry = true;
2167c478bd9Sstevel@tonic-gate 	String castName = "Multicast";
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if (config.isBroadcastOnly()) {
2197c478bd9Sstevel@tonic-gate 	    castName = "Broadcast";
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	setName("SLP "+castName+" Datagram Listener:"+
2247c478bd9Sstevel@tonic-gate 		dss.getLocalAddress()+"/"+
2257c478bd9Sstevel@tonic-gate 		dss.getLocalPort());
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	// Loop forever, receiving datagrams and spawning a request handler
2287c478bd9Sstevel@tonic-gate 	//  to handle it.
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	while (true) {
2317c478bd9Sstevel@tonic-gate 	    byte[] inbuf = new byte[pktsize];
2327c478bd9Sstevel@tonic-gate 	    DatagramPacket incoming = new DatagramPacket(inbuf, pktsize);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	    // Block on datagram receive.
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	    try {
2377c478bd9Sstevel@tonic-gate 		dss.receive(incoming);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		if (config.traceMsg()) {
2407c478bd9Sstevel@tonic-gate 		    config.writeLog("request_in",
2417c478bd9Sstevel@tonic-gate 				    new Object[] {incoming.getAddress(),
2427c478bd9Sstevel@tonic-gate 						      interfac});
2437c478bd9Sstevel@tonic-gate 		}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 		RequestHandler rh =
2467c478bd9Sstevel@tonic-gate 		    new RequestHandler(incoming, interfac, config);
2477c478bd9Sstevel@tonic-gate 		rh.start();
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	    } catch (IOException ex) {
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 		// Die if we can't retry.
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 		Assert.slpassert(retry,
2547c478bd9Sstevel@tonic-gate 			      "datagram_io_error",
2557c478bd9Sstevel@tonic-gate 			      new Object[] {dss.getLocalAddress(),
2567c478bd9Sstevel@tonic-gate 						ex.getMessage()});
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		retry = false;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 		config.writeLog("datagram_io_error",
2617c478bd9Sstevel@tonic-gate 				new Object[] {dss.getLocalAddress(),
2627c478bd9Sstevel@tonic-gate 						  ex.getMessage()});
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		// Close cast socket, get a new one and try again.
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		dss.close();
2677c478bd9Sstevel@tonic-gate 		dss = config.refreshMulticastSocketOnInterface(interfac,
2687c478bd9Sstevel@tonic-gate 							       groups);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	    }
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate     }
2737c478bd9Sstevel@tonic-gate }
274