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 (c) 2001 by Sun Microsystems, Inc.
23  * All rights reserved.
24  *
25  */
26 
27 //  Listener.java:    Organize basic listening for slpd and specifically
28 //                    support datagram listening.
29 //  Author:           James Kempf
30 //  Created On:       Mon May 18 12:43:50 1998
31 //  Last Modified By: James Kempf
32 //  Last Modified On: Thu Jan  7 08:39:19 1999
33 //  Update Count:     54
34 //
35 
36 package com.sun.slp;
37 
38 import java.util.*;
39 import java.net.*;
40 import java.io.*;
41 
42 /**
43  * This class supplies the basic listening function for the DA
44  * and SA. On creation, a StreamListener is created to listen for
45  * clients that need to initiate unicast connections. The main object
46  * listens on the SLP multicast address for SLP multicasts, and
47  * passes the results off to the RequestHandler for direction to
48  * the proper table. The RequestHandler object is executed in a different
49  * thread to maximize throughput. Note that unicast datagram requests
50  * may also enter through this class, since many systems don't distinguish
51  * between the multicast and datagram queues for a port.
52  *
53  * @author James Kempf, Erik Guttman
54  */
55 
56 class Listener extends Thread {
57 
58     private DatagramSocket dss = null; 	    // SLP multicast/broadcast socket.
59     private InetAddress interfac = null;    // Interface on which we listen.
60     private int pktsize = 0;	    	    // MTU of network packet.
61     private Vector groups = new Vector();   // Multicast groups monitored.
62 
63     static private SLPConfig config = null; // Config object for properties
64     static private Hashtable listeners =
65 			new Hashtable();    // Listeners keyed by interface.
66 
67     // Initialize the complex of listener/sender objects on the interface.
68     //  This includes a datagram listener, a DAAdvertiser (which shares
69     //  the same socket as the datagram listener) if a DA, and a
70     //  stream listener.
71 
initializeInterfaceManagers(InetAddress interfac)72     static void initializeInterfaceManagers(InetAddress interfac)
73 	throws ServiceLocationException {
74 
75 	// If we've done the intializtion, forget it.
76 
77 	if (listeners.get(interfac) != null) {
78 	    return;
79 
80 	}
81 
82 	// Get config object.
83 
84 	if (config == null) {
85 	    config = SLPConfig.getSLPConfig();
86 
87 	}
88 
89 	// Create a listener object for this interface.
90 
91 	Listener listener = new Listener(interfac);
92 
93 	// Start thread to listen for incoming datagram request.
94 
95 	listener.start();
96 
97 	// Create a stream listener object for this interface.
98 
99 	StreamListener.initializeStreamListenerOnInterface(interfac);
100 
101 	// We wait until this point to advertise ourselves as DAs. At
102 	//  this point, we have the listeners up to handle any messages
103 	//  that might come in as a result.
104 
105     }
106 
107     // Return the socket for the listener on the designated interface.
108     //  DAAdvertisers and the SLPv1 codes uses this to share the
109     //  same socket as the main datagram listener.
110 
returnListenerSocketOnInterface( InetAddress interfac)111     static DatagramSocket returnListenerSocketOnInterface(
112 						InetAddress interfac) {
113 
114 	Listener listener = (Listener)listeners.get(interfac);
115 
116 	if (listener != null) {
117 	    return listener.dss;
118 	}
119 
120 	return null;
121     }
122 
123     // Add the listener on the interface to the multicast group.
124 
125     static void
addListenerToMulticastGroup(InetAddress interfac, InetAddress maddr)126 	addListenerToMulticastGroup(InetAddress interfac, InetAddress maddr)
127 	throws ServiceLocationException {
128 
129 	Listener listener = (Listener)listeners.get(interfac);
130 
131 	// Ignore if we haven't got it.
132 
133 	if (listener == null) {
134 	    return;
135 
136 	}
137 
138 	DatagramSocket dss = listener.dss;
139 
140 	// Only add if we're multicast.
141 
142 	if (dss instanceof MulticastSocket) {
143 	    MulticastSocket mss = (MulticastSocket)dss;
144 
145 	    try {
146 		mss.joinGroup(maddr);
147 
148 		// Record the groups monitored.
149 
150 		listener.groups.addElement(maddr);
151 
152 	    } catch (IOException ex) {
153 		new ServiceLocationException(
154 				ServiceLocationException.NETWORK_INIT_FAILED,
155 				"socket_initializtion_failure",
156 				new Object[] {maddr, ex.getMessage()});
157 
158 	    }
159 	}
160     }
161 
162     // Refresh the listener socket on the interface. If there is no
163     //  listener, then simply return a new send socket.
164 
165     static DatagramSocket
refreshSocketOnInterface(InetAddress interfac)166 	refreshSocketOnInterface(InetAddress interfac) {
167 
168 	Listener listener = (Listener)listeners.get(interfac);
169 
170 	if (listener == null) {
171 	    return config.refreshMulticastSocketOnInterface(interfac, null);
172 
173 	}
174 
175 	listener.dss.close();
176 
177 	listener.dss =
178 	    config.refreshMulticastSocketOnInterface(interfac,
179 						     listener.groups);
180 
181 	return listener.dss;
182 
183     }
184 
185     // Create a Listener for the interface.
186 
Listener(InetAddress interfac)187     private Listener(InetAddress interfac) throws ServiceLocationException {
188 
189 	// Get packet size.
190 
191 	this.pktsize = config.getMTU();
192 
193 	this.interfac = interfac;
194 
195 	// Get a socket for this interface.
196 
197 	this.dss = config.getMulticastSocketOnInterface(interfac, false);
198 
199 	// Record here so we can use standard utility to add to multicast
200 	// group.
201 
202 	listeners.put(interfac, this);
203 
204 	// If we're multicasting, add to the default SLP group.
205 
206 	addListenerToMulticastGroup(interfac, config.getMulticastAddress());
207 
208     }
209 
210     // Listen on multicast for incoming requests, spawn a RequestHandler
211     //  to process the datagram.
212 
run()213     public void run()  {
214 
215 	boolean retry = true;
216 	String castName = "Multicast";
217 
218 	if (config.isBroadcastOnly()) {
219 	    castName = "Broadcast";
220 
221 	}
222 
223 	setName("SLP "+castName+" Datagram Listener:"+
224 		dss.getLocalAddress()+"/"+
225 		dss.getLocalPort());
226 
227 	// Loop forever, receiving datagrams and spawning a request handler
228 	//  to handle it.
229 
230 	while (true) {
231 	    byte[] inbuf = new byte[pktsize];
232 	    DatagramPacket incoming = new DatagramPacket(inbuf, pktsize);
233 
234 	    // Block on datagram receive.
235 
236 	    try {
237 		dss.receive(incoming);
238 
239 		if (config.traceMsg()) {
240 		    config.writeLog("request_in",
241 				    new Object[] {incoming.getAddress(),
242 						      interfac});
243 		}
244 
245 		RequestHandler rh =
246 		    new RequestHandler(incoming, interfac, config);
247 		rh.start();
248 
249 	    } catch (IOException ex) {
250 
251 		// Die if we can't retry.
252 
253 		Assert.slpassert(retry,
254 			      "datagram_io_error",
255 			      new Object[] {dss.getLocalAddress(),
256 						ex.getMessage()});
257 
258 		retry = false;
259 
260 		config.writeLog("datagram_io_error",
261 				new Object[] {dss.getLocalAddress(),
262 						  ex.getMessage()});
263 
264 		// Close cast socket, get a new one and try again.
265 
266 		dss.close();
267 		dss = config.refreshMulticastSocketOnInterface(interfac,
268 							       groups);
269 
270 	    }
271 	}
272     }
273 }
274