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
36package com.sun.slp;
37
38import java.util.*;
39import java.net.*;
40import 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
56class 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
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
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
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
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
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
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