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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * ident	"%Z%%M%	%I%	%E% SMI"
24  *
25  * Copyright (c) 2001 by Sun Microsystems, Inc.
26  * All rights reserved.
27  *
28  */
29 
30 //  SCCS Status:      %W%	%G%
31 //  SLPV1Manager.java: Manages V1 Compatibility
32 //  Author:           James Kempf
33 //  Created On:       Wed Sep  9 09:51:40 1998
34 //  Last Modified By: James Kempf
35 //  Last Modified On: Thu Mar  4 10:39:11 1999
36 //  Update Count:     46
37 //
38 
39 package com.sun.slp;
40 
41 import java.io.*;
42 import java.util.*;
43 import java.net.*;
44 
45 
46 /**
47  * The SLPV1Manager manages access between the DA and the V1 compatibility
48  * framework. The DA calls into the SLPV1Manager to initialize
49  * active and passive DA advertising, and to decode an incoming V1
50  * message. However, the ServiceTable does *not* call into SLPV1Manager
51  * to handle an outgoing message, since each individual message type is
52  * handled separately. SLPV1Manager also handles V1 defaults.
53  *
54  * @version %R%.%L% %D%
55  * @author James Kempf
56  */
57 
58 abstract class SLPV1Manager extends Object {
59 
60     // V1 Header class.
61 
62     static final String V1_HEADER_CLASS = "com.sun.slp.SLPHeaderV1";
63 
64     // V1 multicast addresses.
65 
66     static final String sGeneralSLPMCAddress = "224.0.1.22";
67     static final String sDADiscSLPMCAddress  = "224.0.1.35";
68 
69     static InetAddress v1SLPGSAddr = null;
70     static InetAddress v1SLPDAAddr = null;
71 
72     /**
73      * The SLPV1Advertiser implements the SLPv1 DAAdvert xid incrementing
74      * algorithm. In SLPv1, the xid of an unsolicited DAAdvert is only
75      * 0 if it came up stateless. If it comes up with preexisting state,
76      * it sets the counter to 0x100. Also, when the xid counter wraps,
77      * it must wrap to 0x100 and not 0x0.
78      */
79 
80     static class SLPV1Advertiser extends DAAdvertiser {
81 
82 	// For implementing the V1 xid algorithm.
83 
84 	private short xid = 0;
85 
86 	private static final short STATEFUL_XID = 0x100;
87 
88 	private static final long STATEFUL_TIME_BOUND = 300L;
89 
90 	// Service table.
91 
92 	private ServiceTable table = null;
93 
94 	// Scopes to use. We need to map from V2, so default corresponds to
95 	//  the empty scope.
96 
97 	Vector useScopes = new Vector();
98 
99 	// Create an SLPv1 Advertiser and start it running.
100 
101 	SLPV1Advertiser(InetAddress interfac,
102 			InetAddress maddr,
103 			ServiceTable table)
104 	    throws ServiceLocationException {
105 	    super();
106 
107 	    this.table = table;
108 
109 	    initialize();
110 
111 	    //  There will be NO listener on this multicast address,
112 	    //  so the superclass will simply create a scoket for it.
113 	    //  We don't want to create a new Listener
114 	    //  because we are not interested in multicast requests since
115 	    //  only SAs answer multicast requests.
116 
117 	    initializeNetworking(interfac, maddr);
118 	}
119 
120 	// Initialize the xid for passive advertising. We need to determine
121 	//  whether we came up stateless or not. We do this by asking the
122 	//  the service store for the stateless reboot time. If the
123 	//  stateless reboot time is within the last 5 minutes, we
124 	//  assume we came up stateless. Otherwise, we're stateful.
125 	//  We also initialize the URL and scopes.
126 
127 	private void initialize() throws ServiceLocationException {
128 
129 	    // Initialize the xid.
130 
131 	    ServiceStore store = ServiceTable.getServiceTable().store;
132 	    long timestamp = store.getStateTimestamp();
133 	    long currentTime = SLPConfig.currentSLPTime();
134 
135 	    if ((currentTime - timestamp) > STATEFUL_TIME_BOUND) {
136 		xid = STATEFUL_XID;
137 
138 	    }
139 
140 	    // Initialize the scopes.
141 
142 	    useScopes = config.getSAConfiguredScopes();
143 
144 	}
145 
146 	// Return the output buffer for a passive advert. We need to create
147 	//  the advert, rolling over the xid if necessary for the next one.
148 
149 	protected byte[] getOutbuf() {
150 
151 	    SDAAdvert daadvert = null;
152 
153 	    try {
154 
155 		SLPHeaderV1 hdr = new SLPHeaderV1();
156 		hdr.functionCode = SrvLocHeader.DAAdvert;
157 		hdr.locale = config.getLocale();
158 
159 		daadvert = (SDAAdvert)table.makeDAAdvert(hdr,
160 							 interfac,
161 							 xid,
162 							 useScopes,
163 							 config);
164 		hdr = (SLPHeaderV1)daadvert.getHeader();
165 
166 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
167 
168 		hdr.externalize(baos, true, false);
169 		byte[] outbuf = baos.toByteArray();
170 
171 		bumpXid();
172 
173 		return outbuf;
174 
175 	    } catch (ServiceLocationException ex) {
176 		Assert.slpassert(false,
177 			      "v1_advert_error",
178 			      new Object[0]);
179 
180 	    }
181 
182 	    return null;
183 	}
184 
185 	private void bumpXid() {
186 
187 	    int newXID = (int)xid + 1;
188 
189 	    if (newXID > Short.MAX_VALUE) {
190 		xid = STATEFUL_XID;
191 
192 	    } else {
193 		xid = (short)newXID;
194 
195 	    }
196 	}
197     }
198 
199 
200     // Start up listener, active and passive listeners for SLPv1.
201 
202     static public void
203 	start(SLPConfig config, ServerDATable table, ServiceTable stable) {
204 
205 	// We do not handle SLPv1 if security is enabled, because SLPv1
206 	//  security is not implemented.
207 
208 	if (config.getHasSecurity()) {
209 
210 	    if (config.regTest() ||
211 		config.traceMsg() ||
212 		config.traceDrop() ||
213 		config.traceDATraffic()) {
214 
215 		config.writeLog("v1_security_enabled",
216 				new Object[0]);
217 	    }
218 
219 	    return;
220 
221 	}
222 
223 	Vector interfaces = config.getInterfaces();
224 	int i = 0, n = interfaces.size();
225 	Vector advs = new Vector();
226 
227 	try {
228 
229 	    InetAddress v1SLPDAAddr = null;
230 
231 	    // Get address for DA discovery multicast.
232 
233 	    v1SLPDAAddr = InetAddress.getByName(sDADiscSLPMCAddress);
234 	    v1SLPGSAddr = InetAddress.getByName(sGeneralSLPMCAddress);
235 
236 	    // Add all listeners onto the SLPv1 DA multicast address and
237 	    //  create a DAAdvertiser on all network interfaces for the
238 	    //  general multicast group.
239 
240 	    for (i = 0; i < n; i++) {
241 		InetAddress interfac = (InetAddress)interfaces.elementAt(i);
242 
243 		// Listen for SLPv1 multicast DA service requests. Only DA
244 		//  service requests are multicast on this address.
245 
246 		Listener.addListenerToMulticastGroup(interfac, v1SLPDAAddr);
247 
248 		// We don't need to listen to the SLPv1 general multicast
249 		//  address because we never want any multicast service
250 		//  requests. But we do need to advertise as an SLPv1 DA.
251 		//  So we have a special DAAdvertiser subclass to do it.
252 
253 		DAAdvertiser ad =
254 		    new SLPV1Advertiser(interfac, v1SLPGSAddr, stable);
255 		ad.start();
256 
257 		advs.addElement(ad);
258 
259 	    }
260 
261 	    // Let admin know we are running in SLPv1 compatibility mode
262 	    //  if tracing is on
263 
264 	    if (config.regTest() ||
265 		config.traceMsg() ||
266 		config.traceDrop() ||
267 		config.traceDATraffic()) {
268 
269 		config.writeLog("v1_hello",
270 				new Object[] {config.getSAConfiguredScopes()});
271 	    }
272 
273 	    return;
274 
275 	} catch (ServiceLocationException ex) {
276 
277 	    config.writeLog("v1_init_error",
278 			    new Object[] {ex.getMessage()});
279 
280 	}  catch (UnknownHostException ex) {
281 
282 	    config.writeLog("v1_init_error",
283 			    new Object[] {ex.getMessage()});
284 
285 	}
286 
287 	// Remove Listeners from multicast group, stop DAAdvertisers.
288 	// An error occured.
289 
290 	int j;
291 
292 	for (j = 0; j < i; i++) {
293 	    InetAddress interfac = (InetAddress)interfaces.elementAt(i);
294 	    DatagramSocket dss =
295 		Listener.returnListenerSocketOnInterface(interfac);
296 
297 	    if (dss instanceof MulticastSocket) {
298 		MulticastSocket mss = (MulticastSocket)dss;
299 
300 		try {
301 		    mss.leaveGroup(v1SLPDAAddr);
302 
303 		} catch (IOException ex) {
304 
305 		    // Ignore it.
306 
307 		}
308 
309 		DAAdvertiser ad = (DAAdvertiser)advs.elementAt(j);
310 
311 		ad.stopThread();
312 	    }
313 	}
314     }
315 
316     // Initialize CSrvReg, CSrvDereg, CSrvMsg, and SDAAdvert classes for SLPv1,
317     //  also V1 header class.
318 
319     static {
320 
321 	SrvLocHeader.addHeaderClass(V1_HEADER_CLASS, SLPHeaderV1.VERSION);
322 
323     }
324 }
325