author | Mark J. Nelson <Mark.J.Nelson@Sun.COM> |
Wed, 06 Aug 2008 16:29:39 -0600 | |
changeset 7298 | b69e27387f74 |
parent 0 | 68f95e015346 |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
7298
b69e27387f74
6733918 Teamware has retired, please welcome your new manager, Mercurial
Mark J. Nelson <Mark.J.Nelson@Sun.COM>
parents:
0
diff
changeset
|
5 |
* Common Development and Distribution License (the "License"). |
b69e27387f74
6733918 Teamware has retired, please welcome your new manager, Mercurial
Mark J. Nelson <Mark.J.Nelson@Sun.COM>
parents:
0
diff
changeset
|
6 |
* You may not use this file except in compliance with the License. |
0 | 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 1999-2003 Sun Microsystems, Inc. All rights reserved. |
|
23 |
* Use is subject to license terms. |
|
24 |
* |
|
25 |
*/ |
|
26 |
||
27 |
// SLPConfig.java |
|
28 |
// |
|
29 |
||
30 |
/** |
|
31 |
* This class is a singleton - it has the configuration which |
|
32 |
* is the default. It reads from a configuration file and |
|
33 |
* this overrides the default. If the config file does not |
|
34 |
* expressly forbid it, the ServiceLocationManager interface |
|
35 |
* allows some of these configuration options to be modified. |
|
36 |
* This configuration is refered to by many points of the |
|
37 |
* implementation. Note that the class itself is abstract, |
|
38 |
* and is extended by two classes, one that allows slpd to |
|
39 |
* run as an SA server only, the other allows it to run |
|
40 |
* as a DA as well. |
|
41 |
* |
|
42 |
* @see com.sun.slp.ServiceLocationManager |
|
43 |
*/ |
|
44 |
||
45 |
package com.sun.slp; |
|
46 |
||
47 |
import java.net.*; |
|
48 |
import java.util.*; |
|
49 |
import java.text.*; |
|
50 |
import java.io.*; |
|
51 |
||
52 |
/* |
|
53 |
* This class contains all configuration information. It |
|
54 |
* is hard coded to know the defaults, and will read a config |
|
55 |
* file if it is present. The config file will override the |
|
56 |
* default values and policy. If the config file allows it |
|
57 |
* the user may reset some of these values using the |
|
58 |
* ServiceLocationManager interface. |
|
59 |
* |
|
60 |
*/ |
|
61 |
class SLPConfig { |
|
62 |
||
63 |
/** |
|
64 |
* A Java properties file defines `\' as an escape character, which |
|
65 |
* conflicts with the SLP API escape convention. Therefore, we need |
|
66 |
* to subclass properties so we can parse in the file ourselves. |
|
67 |
*/ |
|
68 |
||
69 |
public static class SLPProperties extends Properties { |
|
70 |
||
71 |
SLPProperties(Properties p) { |
|
72 |
super(p); |
|
73 |
||
74 |
} |
|
75 |
||
76 |
// Parse the SLP properties file ourselves. Groan! We don't recognize |
|
77 |
// backslash as an escape. |
|
78 |
||
79 |
public synchronized void load(InputStream in) throws IOException { |
|
80 |
||
81 |
BufferedReader rd = new BufferedReader(new InputStreamReader(in)); |
|
82 |
||
83 |
while (rd.ready()) { |
|
84 |
String ln = rd.readLine(); |
|
85 |
||
86 |
// Throw out anything that begins with '#' or ';'. |
|
87 |
||
88 |
if (ln.startsWith("#") || |
|
89 |
ln.startsWith(";") || |
|
90 |
ln.length() <= 0) { |
|
91 |
continue; |
|
92 |
||
93 |
} |
|
94 |
||
95 |
// Parse out equals sign, if any. Note that we trim any |
|
96 |
// white space preceding or following data strings. |
|
97 |
// Although the grammar doesn't allow it, users may |
|
98 |
// enter blanks in their configuration files. |
|
99 |
// NOTE: White space is not allowed in the data of |
|
100 |
// property tag or values. If included, according |
|
101 |
// to RFC 2614, Section 2.1 these MUST be escaped, |
|
102 |
// ie. space would be represented with '\20'. |
|
103 |
// Therefore, it is *completely* safe to perform |
|
104 |
// these trim()s. They will catch errors resulting |
|
105 |
// from sloppy data entry in slp.conf files and |
|
106 |
// never corrupt or alter correctly formatted |
|
107 |
// properties. |
|
108 |
||
109 |
SLPTokenizer tk = new SLPTokenizer(ln, "="); |
|
110 |
||
111 |
if (!tk.hasMoreTokens()) {// empty line... |
|
112 |
continue; |
|
113 |
||
114 |
} |
|
115 |
||
116 |
String prop = tk.nextToken().trim(); |
|
117 |
||
118 |
if (prop.trim().length() <= 0) {// line has just spaces... |
|
119 |
continue; |
|
120 |
||
121 |
} |
|
122 |
||
123 |
if (!tk.hasMoreTokens()) {// line has no definition... |
|
124 |
continue; |
|
125 |
||
126 |
} |
|
127 |
||
128 |
// Register the property. |
|
129 |
String def = tk.nextToken().trim(); |
|
130 |
this.setProperty(prop, def); |
|
131 |
} |
|
132 |
} |
|
133 |
||
134 |
} |
|
135 |
||
136 |
protected SLPConfig() { |
|
137 |
||
138 |
// Create a temporary, default log to report any errors during |
|
139 |
// configuration. |
|
140 |
log = new StderrLog(); |
|
141 |
||
142 |
// Initialize properties. Properties on command line override config |
|
143 |
// file properties, and both override defaults. |
|
144 |
||
145 |
Properties sysProps = (Properties)(System.getProperties().clone()); |
|
146 |
||
147 |
// Load Defalts. |
|
148 |
||
149 |
try { |
|
150 |
Class.forName("com.sun.slp.Defaults"); |
|
151 |
||
152 |
} catch (ClassNotFoundException ex) { |
|
153 |
||
154 |
Assert.printMessageAndDie(this, |
|
155 |
"no_class", |
|
156 |
new Object[] {"com.sun.slp.Defaults"}); |
|
157 |
} |
|
158 |
||
159 |
// System properties now contain Defaults |
|
160 |
Properties defaultProps = System.getProperties(); |
|
161 |
||
162 |
// Load config file. |
|
163 |
||
164 |
SLPProperties slpProps = new SLPProperties(new Properties()); |
|
165 |
try { |
|
166 |
InputStream fis = getConfigURLStream(); |
|
167 |
if (fis != null) { |
|
168 |
slpProps.load(fis); |
|
169 |
System.setProperties(slpProps); |
|
170 |
} |
|
171 |
||
172 |
} catch (IOException ex) { |
|
173 |
writeLog("unparsable_config_file", |
|
174 |
new Object[] {ex.getMessage()}); |
|
175 |
} |
|
176 |
||
177 |
// Add config properties to Defaults, overwritting any pre-existing |
|
178 |
// entries |
|
179 |
defaultProps.putAll(slpProps); |
|
180 |
||
181 |
// Now add in system props, overwritting any pre-existing entries |
|
182 |
defaultProps.putAll(sysProps); |
|
183 |
||
184 |
System.setProperties(defaultProps); |
|
185 |
||
186 |
||
187 |
// Initialize useScopes property. This is read-only after the file |
|
188 |
// has been loaded. |
|
189 |
||
190 |
configuredScopes = initializeScopes("net.slp.useScopes"); |
|
191 |
saConfiguredScopes = (Vector)configuredScopes.clone(); |
|
192 |
||
193 |
// Add default scope to scopes for SA. |
|
194 |
||
195 |
if (saConfiguredScopes.size() <= 0) { |
|
196 |
saConfiguredScopes.addElement(Defaults.DEFAULT_SCOPE); |
|
197 |
||
198 |
} |
|
199 |
||
200 |
// Initialize SA scopes. This uses a Sun specific property for |
|
201 |
// scopes only used by the SA and adds in the DA scopes. |
|
202 |
||
203 |
saOnlyScopes = initializeScopes(DATable.SA_ONLY_SCOPES_PROP); |
|
204 |
||
205 |
// Initialized preconfigured DAs. |
|
206 |
||
207 |
preconfiguredDAs = initializePreconfiguredDAs(); |
|
208 |
||
209 |
// Initialize broadcast flag. |
|
210 |
||
211 |
broadcastOnly = Boolean.getBoolean("net.slp.isBroadcastOnly"); |
|
212 |
||
213 |
// Initialize logging. Default is stderr, first check for alternate. |
|
214 |
||
215 |
String failed = null; |
|
216 |
||
217 |
try { |
|
218 |
String loggerClassName = |
|
219 |
System.getProperty("sun.net.slp.loggerClass"); |
|
220 |
if (loggerClassName != null) { |
|
221 |
Class loggerClass = Class.forName(loggerClassName); |
|
222 |
// Protect against disastrous pilot error, such as trying |
|
223 |
// to use com.sun.slp.SLPConfig as the log class |
|
224 |
// (causes stack recursion) |
|
225 |
if (Class.forName("java.io.Writer").isAssignableFrom( |
|
226 |
loggerClass)) { |
|
227 |
Object logger = loggerClass.newInstance(); |
|
228 |
log = (Writer) logger; |
|
229 |
} else { |
|
230 |
failed = formatMessage( |
|
231 |
"bad_log_class", |
|
232 |
new Object[] { |
|
233 |
loggerClass.toString()}) + "\n"; |
|
234 |
} |
|
235 |
} |
|
236 |
||
237 |
} catch (Throwable ex) { |
|
238 |
log = null; |
|
239 |
failed = formatMessage( |
|
240 |
"bad_log", |
|
241 |
new Object[] { |
|
242 |
ex.toString()}) + "\n"; |
|
243 |
} |
|
244 |
||
245 |
// If no alternate log, revert to minimal default |
|
246 |
if (log == null) { |
|
247 |
log = new StderrLog(); |
|
248 |
||
249 |
// If the alternate log failed, log it through the default log |
|
250 |
if (failed != null) { |
|
251 |
try { |
|
252 |
synchronized (log) { |
|
253 |
log.write(failed); |
|
254 |
log.flush(); |
|
255 |
} |
|
256 |
} catch (IOException giveUp) {} |
|
257 |
} |
|
258 |
} |
|
259 |
||
260 |
} |
|
261 |
||
262 |
private InputStream getConfigURLStream() { |
|
263 |
||
264 |
// Open a URL onto the configuration file. |
|
265 |
||
266 |
String conf = System.getProperty("sun.net.slp.configURL"); |
|
267 |
||
268 |
if (conf == null) { |
|
269 |
conf = Defaults.SOLARIS_CONF; |
|
270 |
||
271 |
} |
|
272 |
||
273 |
InputStream str = null; |
|
274 |
||
275 |
try { |
|
276 |
||
277 |
URL confURL = new URL(conf); |
|
278 |
||
279 |
str = confURL.openStream(); |
|
280 |
||
281 |
} catch (MalformedURLException ex) { |
|
282 |
writeLog("url_malformed", |
|
283 |
new Object[] {conf}); |
|
284 |
||
285 |
} catch (IOException ex) { |
|
286 |
if (conf != Defaults.SOLARIS_CONF) { |
|
287 |
// don't complain if we can't find our own default |
|
288 |
writeLog("unparsable_config_file", |
|
289 |
new Object[] {ex.getMessage()}); |
|
290 |
} |
|
291 |
||
292 |
} |
|
293 |
||
294 |
return str; |
|
295 |
} |
|
296 |
||
297 |
// ------------------------------------------------------------ |
|
298 |
// Property manipulation functions |
|
299 |
// |
|
300 |
||
301 |
private boolean OKBound(int i, int lb, int ub) { |
|
302 |
if (i < lb || i > ub) |
|
303 |
return false; |
|
304 |
else |
|
305 |
return true; |
|
306 |
} |
|
307 |
||
308 |
int getIntProperty(String prop, int df, int lb, int ub) { |
|
309 |
||
310 |
int i = Integer.getInteger(prop, df).intValue(); |
|
311 |
||
312 |
if (OKBound(i, lb, ub)) { |
|
313 |
return i; |
|
314 |
||
315 |
} else { |
|
316 |
writeLog("bad_prop_tag", new Object[] {prop}); |
|
317 |
||
318 |
return df; |
|
319 |
} |
|
320 |
} |
|
321 |
||
322 |
// ------------------------------------------------------------ |
|
323 |
// Multicast radius |
|
324 |
// |
|
325 |
private int iMinMCRadius = 1; // link local scope |
|
326 |
private int iMaxMCRadius = 255; // universal scope |
|
327 |
||
328 |
int getMCRadius() { |
|
329 |
return getIntProperty("net.slp.multicastTTL", |
|
330 |
Defaults.iMulticastRadius, |
|
331 |
iMinMCRadius, |
|
332 |
iMaxMCRadius); |
|
333 |
} |
|
334 |
||
335 |
// ------------------------------------------------------------ |
|
336 |
// Heartbeat interval, seconds. |
|
337 |
// |
|
338 |
private final int iMinHeart = 2000; // 10 minutes |
|
339 |
private final int iMaxHeart = 259200000; // 3 days |
|
340 |
||
341 |
int getAdvertHeartbeatTime() { |
|
342 |
return getIntProperty("net.slp.DAHeartBeat", |
|
343 |
Defaults.iHeartbeat, |
|
344 |
iMinHeart, |
|
345 |
iMaxHeart); |
|
346 |
} |
|
347 |
||
348 |
// ------------------------------------------------------------ |
|
349 |
// Active discovery interval, seconds. |
|
350 |
// |
|
351 |
||
352 |
private final int iMinDisc = 300; // 5 minutes |
|
353 |
private final int iMaxDisc = 10800; // 3 hours |
|
354 |
||
355 |
int getActiveDiscoveryInterval() { |
|
356 |
||
357 |
// We allow zero in order to turn active discovery off, but |
|
358 |
// if 5 minutes is the smallest actual time. |
|
359 |
||
360 |
int prop = getIntProperty("net.slp.DAActiveDiscoveryInterval", |
|
361 |
Defaults.iActiveDiscoveryInterval, |
|
362 |
0, |
|
363 |
iMaxDisc); |
|
364 |
if (prop > 0 && prop < iMinDisc) { |
|
365 |
writeLog("bad_prop_tag", |
|
366 |
new Object[] {"net.slp.DAActiveDiscoveryInterval"}); |
|
367 |
return iMinDisc; |
|
368 |
||
369 |
} |
|
370 |
||
371 |
return prop; |
|
372 |
} |
|
373 |
||
374 |
||
375 |
// ------------------------------------------------------------ |
|
376 |
// Active discovery granularity, seconds. |
|
377 |
// |
|
378 |
||
379 |
private int iMaxDiscGran = iMaxDisc * 2; |
|
380 |
||
381 |
int getActiveDiscoveryGranularity() { |
|
382 |
return getIntProperty("sun.net.slp.DAActiveDiscoveryGranularity", |
|
383 |
Defaults.iActiveDiscoveryGranularity, |
|
384 |
0, |
|
385 |
iMaxDiscGran); |
|
386 |
} |
|
387 |
||
388 |
// ------------------------------------------------------------ |
|
389 |
// Bound for random wait, milliseconds. |
|
390 |
// |
|
391 |
||
392 |
private final int iMinWait = 1000; // 1 sec. |
|
393 |
private final int iMaxWait = 3000; // 3 sec. |
|
394 |
||
395 |
int getRandomWaitBound() { |
|
396 |
return getIntProperty("net.slp.randomWaitBound", |
|
397 |
Defaults.iRandomWaitBound, |
|
398 |
iMinWait, |
|
399 |
iMaxWait); |
|
400 |
} |
|
401 |
||
402 |
private static Random randomWait = null; |
|
403 |
||
404 |
long getRandomWait() { |
|
405 |
||
406 |
if (randomWait == null) { |
|
407 |
randomWait = new Random(); |
|
408 |
} |
|
409 |
||
410 |
double r = randomWait.nextDouble(); |
|
411 |
double max = (double)getRandomWaitBound(); |
|
412 |
||
413 |
return (long)(max * r); |
|
414 |
} |
|
415 |
||
416 |
// ------------------------------------------------------------ |
|
417 |
// TCP timeout, milliseconds. |
|
418 |
// |
|
419 |
final static private int iMinTimeout = 100; |
|
420 |
final static private int iMaxTimeout = 360000; |
|
421 |
||
422 |
int getTCPTimeout() { |
|
423 |
return getIntProperty("sun.net.slp.TCPTimeout", |
|
424 |
Defaults.iTCPTimeout, |
|
425 |
iMinTimeout, |
|
426 |
iMaxTimeout); |
|
427 |
} |
|
428 |
||
429 |
// ------------------------------------------------------------ |
|
430 |
// Path MTU |
|
431 |
// |
|
432 |
private final int iMinMTU = 128; // used for some ppp connections |
|
433 |
private final int iMaxMTU = 8192; // used on some LANs |
|
434 |
||
435 |
int getMTU() { |
|
436 |
return getIntProperty("net.slp.MTU", |
|
437 |
Defaults.iMTU, |
|
438 |
iMinMTU, |
|
439 |
iMaxMTU); |
|
440 |
} |
|
441 |
||
442 |
||
443 |
// ------------------------------------------------------------ |
|
444 |
// Serialized registrations. |
|
445 |
// |
|
446 |
||
447 |
String getSerializedRegURL() { |
|
448 |
||
449 |
return System.getProperty("net.slp.serializedRegURL", null); |
|
450 |
||
451 |
} |
|
452 |
||
453 |
// ------------------------------------------------------------ |
|
454 |
// Are we running as a DA or SA server? |
|
455 |
// |
|
456 |
||
457 |
protected static boolean isSA = false; |
|
458 |
||
459 |
boolean isDA() { |
|
460 |
return false; |
|
461 |
} |
|
462 |
||
463 |
boolean isSA() { |
|
464 |
return isSA; |
|
465 |
} |
|
466 |
||
467 |
// ------------------------------------------------------------ |
|
468 |
// DA and SA attributes |
|
469 |
// |
|
470 |
||
471 |
Vector getDAAttributes() { |
|
472 |
return getAttributes("net.slp.DAAttributes", |
|
473 |
Defaults.defaultDAAttributes, |
|
474 |
true); |
|
475 |
} |
|
476 |
||
477 |
Vector getSAAttributes() { |
|
478 |
return getAttributes("net.slp.SAAttributes", |
|
479 |
Defaults.defaultSAAttributes, |
|
480 |
false); |
|
481 |
} |
|
482 |
||
483 |
private Vector getAttributes(String prop, |
|
484 |
Vector defaults, |
|
485 |
boolean daAttrs) { |
|
486 |
String attrList = |
|
487 |
System.getProperty(prop); |
|
488 |
||
489 |
if (attrList == null || attrList.length() <= 0) { |
|
490 |
return (Vector)defaults.clone(); |
|
491 |
||
492 |
} |
|
493 |
||
494 |
try { |
|
495 |
Vector sAttrs = |
|
496 |
SrvLocHeader.parseCommaSeparatedListIn(attrList, false); |
|
497 |
||
498 |
Vector attrs = new Vector(); |
|
499 |
int i, n = sAttrs.size(); |
|
500 |
||
501 |
// Create attribute objects. |
|
502 |
||
503 |
for (i = 0; i < n; i++) { |
|
504 |
String attrExp = (String)sAttrs.elementAt(i); |
|
505 |
ServiceLocationAttribute attr = |
|
506 |
new ServiceLocationAttribute(attrExp, false); |
|
507 |
||
508 |
// If this is the min-refresh-interval, then check the value. |
|
509 |
||
510 |
if (daAttrs && |
|
511 |
attr.getId().equals( |
|
512 |
Defaults.MIN_REFRESH_INTERVAL_ATTR_ID)) { |
|
513 |
Vector values = attr.getValues(); |
|
514 |
boolean errorp = true; |
|
515 |
||
516 |
if (values != null && values.size() == 1) { |
|
517 |
Object val = values.elementAt(0); |
|
518 |
||
519 |
if (val instanceof Integer) { |
|
520 |
int ival = ((Integer)val).intValue(); |
|
521 |
||
522 |
if (ival >= 0 && |
|
523 |
ival <= ServiceURL.LIFETIME_MAXIMUM) { |
|
524 |
errorp = false; |
|
525 |
||
526 |
} |
|
527 |
} |
|
528 |
} |
|
529 |
||
530 |
// Throw exception if it didn't work. |
|
531 |
||
532 |
if (errorp) { |
|
533 |
throw new ServiceLocationException( |
|
534 |
ServiceLocationException.PARSE_ERROR, |
|
535 |
"syntax_error_prop", |
|
536 |
new Object[] {prop, attrs}); |
|
537 |
||
538 |
} |
|
539 |
} |
|
540 |
||
541 |
// Add attribute to vector. |
|
542 |
||
543 |
attrs.addElement(attr); |
|
544 |
||
545 |
} |
|
546 |
||
547 |
return attrs; |
|
548 |
||
549 |
} catch (Exception ex) { |
|
550 |
||
551 |
writeLog("syntax_error_prop", |
|
552 |
new Object[] {prop, attrList}); |
|
553 |
return (Vector)defaults.clone(); |
|
554 |
||
555 |
} |
|
556 |
} |
|
557 |
||
558 |
// ------------------------------------------------------------- |
|
559 |
// Do we support V1? |
|
560 |
// |
|
561 |
||
562 |
boolean isV1Supported() { |
|
563 |
return false; |
|
564 |
} |
|
565 |
||
566 |
// ------------------------------------------------------------- |
|
567 |
// Queue length for server socket. |
|
568 |
// |
|
569 |
||
570 |
int getServerSocketQueueLength() { |
|
571 |
return getIntProperty("sun.net.slp.serverSocketQueueLength", |
|
572 |
Defaults.iSocketQueueLength, |
|
573 |
0, |
|
574 |
Integer.MAX_VALUE); |
|
575 |
} |
|
576 |
||
577 |
// ------------------------------------------------------------ |
|
578 |
// Testing options |
|
579 |
// |
|
580 |
||
581 |
||
582 |
boolean traceAll() {// not official! |
|
583 |
return Boolean.getBoolean("sun.net.slp.traceALL"); |
|
584 |
} |
|
585 |
||
586 |
boolean regTest() { |
|
587 |
if (Boolean.getBoolean("sun.net.slp.traceALL") || |
|
588 |
Boolean.getBoolean("net.slp.traceReg")) |
|
589 |
return true; |
|
590 |
else |
|
591 |
return false; |
|
592 |
} |
|
593 |
||
594 |
boolean traceMsg() { |
|
595 |
if (Boolean.getBoolean("sun.net.slp.traceALL") || |
|
596 |
Boolean.getBoolean("net.slp.traceMsg")) |
|
597 |
return true; |
|
598 |
else |
|
599 |
return false; |
|
600 |
} |
|
601 |
||
602 |
boolean traceDrop() { |
|
603 |
if (Boolean.getBoolean("sun.net.slp.traceALL") || |
|
604 |
Boolean.getBoolean("net.slp.traceDrop")) |
|
605 |
return true; |
|
606 |
else |
|
607 |
return false; |
|
608 |
} |
|
609 |
||
610 |
boolean traceDATraffic() { |
|
611 |
if (Boolean.getBoolean("sun.net.slp.traceALL") || |
|
612 |
Boolean.getBoolean("net.slp.traceDATraffic")) |
|
613 |
return true; |
|
614 |
else |
|
615 |
return false; |
|
616 |
} |
|
617 |
||
618 |
// cannot use Boolean.getBoolean as the default is 'true' |
|
619 |
// using that mechanism, absense would be considered 'false' |
|
620 |
||
621 |
boolean passiveDADetection() { |
|
622 |
||
623 |
String sPassive = |
|
624 |
System.getProperty("net.slp.passiveDADetection", "true"); |
|
625 |
if (sPassive.equalsIgnoreCase("true")) |
|
626 |
return true; |
|
627 |
else |
|
628 |
return false; |
|
629 |
||
630 |
} |
|
631 |
||
632 |
// Initialized when the SLPConfig object is created to avoid changing |
|
633 |
// during the program. |
|
634 |
private boolean broadcastOnly = false; |
|
635 |
||
636 |
boolean isBroadcastOnly() { |
|
637 |
return broadcastOnly; |
|
638 |
} |
|
639 |
||
640 |
||
641 |
// ------------------------------------------------------------ |
|
642 |
// Multicast/broadcast socket mangement. |
|
643 |
// |
|
644 |
DatagramSocket broadSocket = null; // cached broadcast socket. |
|
645 |
||
646 |
||
647 |
// Reopen the multicast/broadcast socket bound to the |
|
648 |
// interface. If groups is not null, then join all |
|
649 |
// the groups. Otherwise, this is send only. |
|
650 |
||
651 |
DatagramSocket |
|
652 |
refreshMulticastSocketOnInterface(InetAddress interfac, |
|
653 |
Vector groups) { |
|
654 |
||
655 |
try { |
|
656 |
||
657 |
// Reopen it. |
|
658 |
||
659 |
DatagramSocket dss = |
|
660 |
getMulticastSocketOnInterface(interfac, |
|
661 |
(groups == null ? true:false)); |
|
662 |
||
663 |
if ((groups != null) && (dss instanceof MulticastSocket)) { |
|
664 |
int i, n = groups.size(); |
|
665 |
MulticastSocket mss = (MulticastSocket)dss; |
|
666 |
||
667 |
for (i = 0; i < n; i++) { |
|
668 |
InetAddress maddr = (InetAddress)groups.elementAt(i); |
|
669 |
||
670 |
mss.joinGroup(maddr); |
|
671 |
||
672 |
} |
|
673 |
} |
|
674 |
||
675 |
return dss; |
|
676 |
||
677 |
} catch (Exception ex) { |
|
678 |
||
679 |
// Any exception in error recovery causes program to die. |
|
680 |
||
681 |
Assert.slpassert(false, |
|
682 |
"cast_socket_failure", |
|
683 |
new Object[] {ex, ex.getMessage()}); |
|
684 |
||
685 |
} |
|
686 |
||
687 |
return null; |
|
688 |
} |
|
689 |
||
690 |
// Open a multicast/broadcast socket on the interface. Note that if |
|
691 |
// the socket is broadcast, the network interface is not specified in the |
|
692 |
// creation message. Is it bound to all interfaces? The isSend parameter |
|
693 |
// specifies whether the socket is for send only. |
|
694 |
||
695 |
DatagramSocket |
|
696 |
getMulticastSocketOnInterface(InetAddress interfac, boolean isSend) |
|
697 |
throws ServiceLocationException { |
|
698 |
||
699 |
DatagramSocket castSocket = null; |
|
700 |
||
701 |
// Substitute broadcast if we are configured for it. |
|
702 |
||
703 |
if (isBroadcastOnly()) { |
|
704 |
||
705 |
try { |
|
706 |
||
707 |
// If transmit, then simply return a new socket. |
|
708 |
||
709 |
if (isSend) { |
|
710 |
castSocket = new DatagramSocket(); |
|
711 |
||
712 |
} else { |
|
713 |
||
714 |
// Return cached socket if there. |
|
715 |
||
716 |
if (broadSocket != null) { |
|
717 |
castSocket = broadSocket; |
|
718 |
||
719 |
} else { |
|
720 |
||
721 |
// Make a new broadcast socket. |
|
722 |
||
723 |
castSocket = |
|
724 |
new DatagramSocket(Defaults.iSLPPort, |
|
725 |
getBroadcastAddress()); |
|
726 |
||
727 |
} |
|
728 |
||
729 |
// Cache for future reference. |
|
730 |
||
731 |
broadSocket = castSocket; |
|
732 |
} |
|
733 |
} catch (SocketException ex) { |
|
734 |
throw |
|
735 |
new ServiceLocationException( |
|
736 |
ServiceLocationException.NETWORK_INIT_FAILED, |
|
737 |
"socket_creation_failure", |
|
738 |
new Object[] { |
|
739 |
getBroadcastAddress(), ex.getMessage()}); |
|
740 |
} |
|
741 |
||
742 |
} else { |
|
743 |
||
744 |
// Create a multicast socket. |
|
745 |
||
746 |
MulticastSocket ms; |
|
747 |
||
748 |
try { |
|
749 |
||
750 |
if (isSend) { |
|
751 |
ms = new MulticastSocket(); |
|
752 |
||
753 |
} else { |
|
754 |
ms = new MulticastSocket(Defaults.iSLPPort); |
|
755 |
||
756 |
} |
|
757 |
||
758 |
} catch (IOException ex) { |
|
759 |
throw |
|
760 |
new ServiceLocationException( |
|
761 |
ServiceLocationException.NETWORK_INIT_FAILED, |
|
762 |
"socket_creation_failure", |
|
763 |
new Object[] {interfac, ex.getMessage()}); |
|
764 |
} |
|
765 |
||
766 |
||
767 |
try { |
|
768 |
||
769 |
// Set the TTL and the interface on the multicast socket. |
|
770 |
// Client is responsible for joining group. |
|
771 |
||
772 |
ms.setTimeToLive(getMCRadius()); |
|
773 |
ms.setInterface(interfac); |
|
774 |
||
775 |
} catch (IOException ex) { |
|
776 |
throw |
|
777 |
new ServiceLocationException( |
|
778 |
ServiceLocationException.NETWORK_INIT_FAILED, |
|
779 |
"socket_initializtion_failure", |
|
780 |
new Object[] {interfac, ex.getMessage()}); |
|
781 |
} |
|
782 |
||
783 |
castSocket = ms; |
|
784 |
||
785 |
} |
|
786 |
||
787 |
return castSocket; |
|
788 |
} |
|
789 |
||
790 |
// ------------------------------------------------------------ |
|
791 |
// Type hint |
|
792 |
// |
|
793 |
||
794 |
// Return a vector of ServiceType objects for the type hint. |
|
795 |
||
796 |
Vector getTypeHint() { |
|
797 |
Vector hint = new Vector(); |
|
798 |
String sTypeList = System.getProperty("net.slp.typeHint", ""); |
|
799 |
||
800 |
if (sTypeList.length() <= 0) { |
|
801 |
return hint; |
|
802 |
||
803 |
} |
|
804 |
||
805 |
// Create a vector of ServiceType objects for the type hint. |
|
806 |
||
807 |
try { |
|
808 |
||
809 |
hint = SrvLocHeader.parseCommaSeparatedListIn(sTypeList, true); |
|
810 |
||
811 |
int i, n = hint.size(); |
|
812 |
||
813 |
for (i = 0; i < n; i++) { |
|
814 |
String type = (String)hint.elementAt(i); |
|
815 |
||
816 |
hint.setElementAt(new ServiceType(type), i); |
|
817 |
||
818 |
} |
|
819 |
} catch (ServiceLocationException ex) { |
|
820 |
||
821 |
writeLog("syntax_error_prop", |
|
822 |
new Object[] {"net.slp.typeHint", sTypeList}); |
|
823 |
||
824 |
hint.removeAllElements(); |
|
825 |
||
826 |
} |
|
827 |
||
828 |
return hint; |
|
829 |
||
830 |
} |
|
831 |
||
832 |
// ------------------------------------------------------------ |
|
833 |
// Configured scope handling |
|
834 |
// |
|
835 |
||
836 |
// Vector of configured scopes. |
|
837 |
||
838 |
private Vector configuredScopes = null; |
|
839 |
||
840 |
// Vector of configures scopes for SA. |
|
841 |
||
842 |
private Vector saConfiguredScopes = null; |
|
843 |
||
844 |
// Vector of scopes only in the sa server. |
|
845 |
||
846 |
private Vector saOnlyScopes = null; |
|
847 |
||
848 |
// Return the configured scopes. |
|
849 |
||
850 |
Vector getConfiguredScopes() { |
|
851 |
return (Vector)configuredScopes.clone(); |
|
852 |
} |
|
853 |
||
854 |
// Return SA scopes. |
|
855 |
||
856 |
Vector getSAOnlyScopes() { |
|
857 |
return (Vector)saOnlyScopes.clone(); |
|
858 |
||
859 |
} |
|
860 |
||
861 |
// Return the configured scopes for the SA. |
|
862 |
||
863 |
Vector getSAConfiguredScopes() { |
|
864 |
return (Vector)saConfiguredScopes.clone(); |
|
865 |
||
866 |
} |
|
867 |
||
868 |
// Add scopes discovered during preconfigured DA contact. |
|
869 |
// These count as configured scopes. |
|
870 |
||
871 |
void addPreconfiguredDAScopes(Vector scopes) { |
|
872 |
||
873 |
int i, n = scopes.size(); |
|
874 |
||
875 |
for (i = 0; i < n; i++) { |
|
876 |
Object scope = scopes.elementAt(i); |
|
877 |
||
878 |
if (!configuredScopes.contains(scope)) { |
|
879 |
configuredScopes.addElement(scope); |
|
880 |
||
881 |
} |
|
882 |
||
883 |
// There better be none extra here for the SA server/DA. |
|
884 |
||
885 |
if (isSA() || isDA()) { |
|
886 |
Assert.slpassert(saConfiguredScopes.contains(scope), |
|
887 |
"sa_new_scope", |
|
888 |
new Object[] {scope, saConfiguredScopes}); |
|
889 |
||
890 |
} |
|
891 |
} |
|
892 |
} |
|
893 |
||
894 |
// Initialize the scopes list on property. |
|
895 |
||
896 |
private Vector initializeScopes(String prop) { |
|
897 |
||
898 |
String sScopes = System.getProperty(prop); |
|
899 |
||
900 |
if (sScopes == null || sScopes.length() <= 0) { |
|
901 |
return new Vector(); |
|
902 |
} |
|
903 |
||
904 |
try { |
|
905 |
||
906 |
Vector vv = |
|
907 |
SrvLocHeader.parseCommaSeparatedListIn(sScopes, true); |
|
908 |
||
909 |
// Unescape scope strings. |
|
910 |
||
911 |
SLPHeaderV2.unescapeScopeStrings(vv); |
|
912 |
||
913 |
// Validate, lower case scope names. |
|
914 |
||
915 |
DATable.validateScopes(vv, getLocale()); |
|
916 |
||
917 |
if (vv.size() > 0) { |
|
918 |
return vv; |
|
919 |
} |
|
920 |
||
921 |
} catch (ServiceLocationException ex) { |
|
922 |
writeLog("syntax_error_prop", |
|
923 |
new Object[] { |
|
924 |
prop, |
|
925 |
sScopes}); |
|
926 |
||
927 |
||
928 |
} |
|
929 |
||
930 |
return new Vector(); |
|
931 |
} |
|
932 |
||
933 |
// Vector of preconfigured DAs. Read only after initialized. |
|
934 |
||
935 |
private Vector preconfiguredDAs = null; |
|
936 |
||
937 |
// Return a vector of DA addresses. |
|
938 |
||
939 |
Vector getPreconfiguredDAs() { |
|
940 |
return (Vector)preconfiguredDAs.clone(); |
|
941 |
||
942 |
} |
|
943 |
||
944 |
// Initialize preconfigured DA list. |
|
945 |
||
946 |
private Vector initializePreconfiguredDAs() { |
|
947 |
String sDAList = System.getProperty("net.slp.DAAddresses", ""); |
|
948 |
Vector ret = new Vector(); |
|
949 |
||
950 |
sDAList.trim(); |
|
951 |
||
952 |
if (sDAList.length() <= 0) { |
|
953 |
return ret; |
|
954 |
||
955 |
} |
|
956 |
||
957 |
try { |
|
958 |
||
959 |
ret = SrvLocHeader.parseCommaSeparatedListIn(sDAList, true); |
|
960 |
||
961 |
} catch (ServiceLocationException ex) { |
|
962 |
||
963 |
writeLog("syntax_error_prop", |
|
964 |
new Object[] {"net.slp.DAAddress", sDAList}); |
|
965 |
||
966 |
return ret; |
|
967 |
||
968 |
} |
|
969 |
||
970 |
// Convert to InetAddress objects. |
|
971 |
||
972 |
int i; |
|
973 |
||
974 |
for (i = 0; i < ret.size(); i++) { |
|
975 |
String da = ""; |
|
976 |
||
977 |
try { |
|
978 |
da = ((String)ret.elementAt(i)).trim(); |
|
979 |
InetAddress daAddr = InetAddress.getByName(da); |
|
980 |
||
981 |
ret.setElementAt(daAddr, i); |
|
982 |
||
983 |
} catch (UnknownHostException ex) { |
|
984 |
||
985 |
writeLog("resolve_failed", |
|
986 |
new Object[] {da}); |
|
987 |
||
988 |
/* |
|
989 |
* Must decrement the index 'i' otherwise the next iteration |
|
990 |
* around the loop will miss the element immediately after |
|
991 |
* the element removed. |
|
992 |
* |
|
993 |
* WARNING: Do not use 'i' again until the loop has |
|
994 |
* iterated as it may, after decrementing, |
|
995 |
* be negative. |
|
996 |
*/ |
|
997 |
ret.removeElementAt(i); |
|
998 |
i--; |
|
999 |
continue; |
|
1000 |
} |
|
1001 |
} |
|
1002 |
||
1003 |
||
1004 |
return ret; |
|
1005 |
} |
|
1006 |
||
1007 |
// ------------------------------------------------------------ |
|
1008 |
// SLPv1 Support Switches |
|
1009 |
// |
|
1010 |
||
1011 |
boolean getSLPv1NotSupported() {// not official! |
|
1012 |
return Boolean.getBoolean("sun.net.slp.SLPv1NotSupported"); |
|
1013 |
||
1014 |
} |
|
1015 |
||
1016 |
boolean getAcceptSLPv1UnscopedRegs() {// not official! |
|
1017 |
||
1018 |
if (!getSLPv1NotSupported()) { |
|
1019 |
return Boolean.getBoolean("sun.net.slp.acceptSLPv1UnscopedRegs"); |
|
1020 |
||
1021 |
} |
|
1022 |
||
1023 |
return false; |
|
1024 |
} |
|
1025 |
||
1026 |
// ------------------------------------------------------------ |
|
1027 |
// Accessor for SLPConfig object |
|
1028 |
// |
|
1029 |
||
1030 |
protected static SLPConfig theSLPConfig = null; |
|
1031 |
||
1032 |
static SLPConfig getSLPConfig() { |
|
1033 |
||
1034 |
if (theSLPConfig == null) { |
|
1035 |
theSLPConfig = new SLPConfig(); |
|
1036 |
} |
|
1037 |
||
1038 |
return theSLPConfig; |
|
1039 |
||
1040 |
} |
|
1041 |
||
1042 |
/** |
|
1043 |
* @return Maximum number of messages/objects to return. |
|
1044 |
*/ |
|
1045 |
||
1046 |
int getMaximumResults() { |
|
1047 |
int i = Integer.getInteger("net.slp.maxResults", |
|
1048 |
Defaults.iMaximumResults).intValue(); |
|
1049 |
if (i == -1) { |
|
1050 |
i = Integer.MAX_VALUE; |
|
1051 |
||
1052 |
} |
|
1053 |
||
1054 |
if (OKBound(i, 1, Integer.MAX_VALUE)) { |
|
1055 |
return i; |
|
1056 |
||
1057 |
} else { |
|
1058 |
||
1059 |
writeLog("bad_prop_tag", |
|
1060 |
new Object[] { |
|
1061 |
"net.slp.maxResults"}); |
|
1062 |
||
1063 |
return Defaults.iMaximumResults; |
|
1064 |
||
1065 |
} |
|
1066 |
} |
|
1067 |
||
1068 |
/** |
|
1069 |
* Convert a language tag into a locale. |
|
1070 |
*/ |
|
1071 |
||
1072 |
static Locale langTagToLocale(String ltag) { |
|
1073 |
||
1074 |
// We treat the first part as the ISO 639 language and the |
|
1075 |
// second part as the ISO 3166 country tag, even though RFC |
|
1076 |
// 1766 doesn't necessarily require that. We should probably |
|
1077 |
// use a lookup table here to determine if they are correct. |
|
1078 |
||
1079 |
StringTokenizer tk = new StringTokenizer(ltag, "-"); |
|
1080 |
String lang = ""; |
|
1081 |
String country = ""; |
|
1082 |
||
1083 |
if (tk.hasMoreTokens()) { |
|
1084 |
lang = tk.nextToken(); |
|
1085 |
||
1086 |
if (tk.hasMoreTokens()) { |
|
1087 |
country = tk.nextToken(""); |
|
1088 |
// country name may have "-" in it... |
|
1089 |
||
1090 |
} |
|
1091 |
} |
|
1092 |
||
1093 |
return new Locale(lang, country); |
|
1094 |
} |
|
1095 |
||
1096 |
/** |
|
1097 |
* Convert a Locale object into a language tag for output. |
|
1098 |
* |
|
1099 |
* @param locale The Locale. |
|
1100 |
* @return String with the language tag encoded. |
|
1101 |
*/ |
|
1102 |
||
1103 |
static String localeToLangTag(Locale locale) { |
|
1104 |
||
1105 |
// Construct the language tag. |
|
1106 |
||
1107 |
String ltag = locale.getCountry(); |
|
1108 |
ltag = locale.getLanguage() + (ltag.length() <= 0 ? "" : ("-" + ltag)); |
|
1109 |
||
1110 |
return ltag; |
|
1111 |
||
1112 |
} |
|
1113 |
||
1114 |
/** |
|
1115 |
* @return the language requests will be made in. |
|
1116 |
*/ |
|
1117 |
static Locale getLocale() { |
|
1118 |
String s = System.getProperty("net.slp.locale"); |
|
1119 |
||
1120 |
if (s != null && s.length() > 0) { |
|
1121 |
return langTagToLocale(s); |
|
1122 |
||
1123 |
} else { |
|
1124 |
||
1125 |
// Return the Java default if the SLP property is not set. |
|
1126 |
||
1127 |
return Locale.getDefault(); |
|
1128 |
||
1129 |
} |
|
1130 |
} |
|
1131 |
||
1132 |
/** |
|
1133 |
* @return the InetAddress of the broadcast interface. |
|
1134 |
*/ |
|
1135 |
||
1136 |
static private InetAddress broadcastAddress; |
|
1137 |
||
1138 |
static InetAddress getBroadcastAddress() { |
|
1139 |
if (broadcastAddress == null) { |
|
1140 |
||
1141 |
try { |
|
1142 |
broadcastAddress = |
|
1143 |
InetAddress.getByName(Defaults.sBroadcast); |
|
1144 |
} catch (UnknownHostException uhe) { |
|
1145 |
||
1146 |
Assert.slpassert(false, |
|
1147 |
"cast_address_failure", |
|
1148 |
new Object[] {Defaults.sBroadcast}); |
|
1149 |
||
1150 |
} |
|
1151 |
} |
|
1152 |
return broadcastAddress; |
|
1153 |
} |
|
1154 |
||
1155 |
||
1156 |
/** |
|
1157 |
* @return the InetAddress of the multicast group. |
|
1158 |
*/ |
|
1159 |
||
1160 |
static private InetAddress multicastAddress; |
|
1161 |
||
1162 |
static InetAddress getMulticastAddress() { |
|
1163 |
if (multicastAddress == null) { |
|
1164 |
||
1165 |
try { |
|
1166 |
multicastAddress = |
|
1167 |
InetAddress.getByName(Defaults.sGeneralSLPMCAddress); |
|
1168 |
} catch (UnknownHostException uhe) { |
|
1169 |
Assert.slpassert(false, |
|
1170 |
"cast_address_failure", |
|
1171 |
new Object[] {Defaults.sGeneralSLPMCAddress}); |
|
1172 |
||
1173 |
} |
|
1174 |
} |
|
1175 |
return multicastAddress; |
|
1176 |
} |
|
1177 |
||
1178 |
/** |
|
1179 |
* @return the interfaces on which SLP should listen and transmit. |
|
1180 |
*/ |
|
1181 |
||
1182 |
private static Vector interfaces = null; |
|
1183 |
||
1184 |
Vector getInterfaces() { |
|
1185 |
||
1186 |
if (interfaces == null) { |
|
1187 |
InetAddress iaLocal = null; |
|
1188 |
||
1189 |
// Get local host. |
|
1190 |
||
1191 |
try { |
|
1192 |
iaLocal = InetAddress.getLocalHost(); |
|
1193 |
||
1194 |
} catch (UnknownHostException ex) { |
|
1195 |
Assert.slpassert(false, |
|
1196 |
"resolve_failed", |
|
1197 |
new Object[] {"localhost"}); |
|
1198 |
} |
|
1199 |
||
1200 |
String mcastI = System.getProperty("net.slp.interfaces"); |
|
1201 |
interfaces = new Vector(); |
|
1202 |
||
1203 |
// Only add local host if nothing else is given. |
|
1204 |
||
1205 |
if (mcastI == null || mcastI.length() <= 0) { |
|
1206 |
interfaces.addElement(iaLocal); |
|
1207 |
return interfaces; |
|
1208 |
||
1209 |
} |
|
1210 |
||
1211 |
Vector nintr; |
|
1212 |
||
1213 |
try { |
|
1214 |
||
1215 |
nintr = SrvLocHeader.parseCommaSeparatedListIn(mcastI, true); |
|
1216 |
||
1217 |
} catch (ServiceLocationException ex) { |
|
1218 |
writeLog("syntax_error_prop", |
|
1219 |
new Object[] { |
|
1220 |
"net.slp.multicastInterfaces", |
|
1221 |
mcastI}); |
|
1222 |
||
1223 |
// Add local host. |
|
1224 |
||
1225 |
interfaces.addElement(iaLocal); |
|
1226 |
||
1227 |
return interfaces; |
|
1228 |
||
1229 |
} |
|
1230 |
||
1231 |
// See if they are really there. |
|
1232 |
||
1233 |
int i, n = nintr.size(); |
|
1234 |
||
1235 |
for (i = 0; i < n; i++) { |
|
1236 |
InetAddress ia; |
|
1237 |
String host = (String)nintr.elementAt(i); |
|
1238 |
||
1239 |
try { |
|
1240 |
||
1241 |
ia = InetAddress.getByName(host); |
|
1242 |
||
1243 |
} catch (UnknownHostException ex) { |
|
1244 |
writeLog("unknown_interface", |
|
1245 |
new Object[] {host, |
|
1246 |
"net.slp.multicastInterfaces"}); |
|
1247 |
continue; |
|
1248 |
||
1249 |
} |
|
1250 |
||
1251 |
if (!interfaces.contains(ia)) { |
|
1252 |
||
1253 |
// Add default at beginning. |
|
1254 |
||
1255 |
if (ia.equals(iaLocal)) { |
|
1256 |
interfaces.insertElementAt(ia, 0); |
|
1257 |
||
1258 |
} else { |
|
1259 |
interfaces.addElement(ia); |
|
1260 |
||
1261 |
} |
|
1262 |
} |
|
1263 |
} |
|
1264 |
} |
|
1265 |
||
1266 |
return interfaces; |
|
1267 |
||
1268 |
} |
|
1269 |
||
1270 |
/** |
|
1271 |
* @return An InetAddress object representing 127.0.0.1 |
|
1272 |
*/ |
|
1273 |
InetAddress getLoopback() { |
|
1274 |
InetAddress iaLoopback = null; |
|
1275 |
||
1276 |
try { |
|
1277 |
iaLoopback = InetAddress.getByName(Defaults.LOOPBACK_ADDRESS); |
|
1278 |
||
1279 |
} catch (UnknownHostException ex) { |
|
1280 |
Assert.slpassert(false, |
|
1281 |
"resolve_failed", |
|
1282 |
new Object[] {"localhost loopback"}); |
|
1283 |
} |
|
1284 |
||
1285 |
return iaLoopback; |
|
1286 |
} |
|
1287 |
||
1288 |
/** |
|
1289 |
* @return The default interface, which should be the first in the |
|
1290 |
* interfaces vector Vector. |
|
1291 |
*/ |
|
1292 |
||
1293 |
InetAddress getLocalHost() { |
|
1294 |
Vector inter = getInterfaces(); |
|
1295 |
return (InetAddress)inter.elementAt(0); |
|
1296 |
||
1297 |
} |
|
1298 |
||
1299 |
// Return true if the address is one of the local interfaces. |
|
1300 |
||
1301 |
boolean isLocalHostSource(InetAddress addr) { |
|
1302 |
||
1303 |
// First check loopback |
|
1304 |
||
1305 |
if (addr.equals(getLoopback())) { |
|
1306 |
return true; |
|
1307 |
||
1308 |
} |
|
1309 |
||
1310 |
return interfaces.contains(addr); |
|
1311 |
||
1312 |
} |
|
1313 |
||
1314 |
// ----------------- |
|
1315 |
// Timeouts |
|
1316 |
// |
|
1317 |
||
1318 |
// Return the maximum wait for multicast convergence. |
|
1319 |
||
1320 |
final static private int iMultiMin = 1000; // one second |
|
1321 |
final static private int iMultiMax = 60000; // one minute |
|
1322 |
||
1323 |
int getMulticastMaximumWait() { |
|
1324 |
||
1325 |
return getIntProperty("net.slp.multicastMaximumWait", |
|
1326 |
Defaults.iMulticastMaxWait, |
|
1327 |
iMultiMin, |
|
1328 |
iMultiMax); |
|
1329 |
} |
|
1330 |
||
1331 |
/* |
|
1332 |
* @return Vector of timeouts for multicast convergence. |
|
1333 |
*/ |
|
1334 |
||
1335 |
int[] getMulticastTimeouts() { |
|
1336 |
int[] timeouts = parseTimeouts("net.slp.multicastTimeouts", |
|
1337 |
Defaults.a_iConvergeTimeout); |
|
1338 |
||
1339 |
timeouts = capTimeouts("net.slp.multicastTimeouts", |
|
1340 |
timeouts, |
|
1341 |
false, |
|
1342 |
0, |
|
1343 |
0); |
|
1344 |
||
1345 |
return timeouts; |
|
1346 |
} |
|
1347 |
||
1348 |
/** |
|
1349 |
* @return Vector of timeouts to try for datagram transmission. |
|
1350 |
*/ |
|
1351 |
||
1352 |
int[] getDatagramTimeouts() { |
|
1353 |
int[] timeouts = parseTimeouts("net.slp.datagramTimeouts", |
|
1354 |
Defaults.a_iDatagramTimeout); |
|
1355 |
||
1356 |
timeouts = capTimeouts("net.slp.datagramTimeouts", |
|
1357 |
timeouts, |
|
1358 |
true, |
|
1359 |
iMultiMin, |
|
1360 |
iMultiMax); |
|
1361 |
||
1362 |
return timeouts; |
|
1363 |
} |
|
1364 |
||
1365 |
/** |
|
1366 |
* @return Vector of timeouts for DA discovery multicast. |
|
1367 |
*/ |
|
1368 |
||
1369 |
int[] getDADiscoveryTimeouts() { |
|
1370 |
int[] timeouts = parseTimeouts("net.slp.DADiscoveryTimeouts", |
|
1371 |
Defaults.a_iDADiscoveryTimeout); |
|
1372 |
||
1373 |
timeouts = capTimeouts("net.slp.DADiscoveryTimeouts", |
|
1374 |
timeouts, |
|
1375 |
false, |
|
1376 |
0, |
|
1377 |
0); |
|
1378 |
||
1379 |
return timeouts; |
|
1380 |
} |
|
1381 |
||
1382 |
/** |
|
1383 |
* This method ensures that all the timeouts are within valid ranges. |
|
1384 |
* The sum of all timeouts for the given property name must not |
|
1385 |
* exceed the value returned by <i>getMulticastMaximumWait()</i>. If |
|
1386 |
* the sum of all timeouts does exceed the maximum wait period the |
|
1387 |
* timeouts are averaged out so that the sum equals the maximum wait |
|
1388 |
* period. |
|
1389 |
* <br> |
|
1390 |
* Additional range checking is also performed when <i>rangeCheck</i> |
|
1391 |
* is true. Then the sum of all timeouts must also be between <i>min</i> |
|
1392 |
* and <i>max</i>. If the sum of all timeouts is not within the range |
|
1393 |
* the average is taken from the closest range boundary. |
|
1394 |
* |
|
1395 |
* @param property |
|
1396 |
* Name of timeout property being capped. This is only present for |
|
1397 |
* reporting purposes and no actual manipulation of the property |
|
1398 |
* is made within this method. |
|
1399 |
* @param timeouts |
|
1400 |
* Array of timeout values. |
|
1401 |
* @param rangeCheck |
|
1402 |
* Indicator of whether additional range checking is required. When |
|
1403 |
* false <i>min</i> and <i>max</i> are ignored. |
|
1404 |
* @param min |
|
1405 |
* Additional range checking lower boundary. |
|
1406 |
* @param max |
|
1407 |
* Additional range checking upper boundary. |
|
1408 |
* @return |
|
1409 |
* Array of capped timeouts. Note this may be the same array as |
|
1410 |
* passed in (<i>timeouts</i>). |
|
1411 |
*/ |
|
1412 |
private int[] capTimeouts(String property, |
|
1413 |
int[] timeouts, |
|
1414 |
boolean rangeCheck, |
|
1415 |
int min, |
|
1416 |
int max) { |
|
1417 |
||
1418 |
int averagedTimeout; |
|
1419 |
int totalWait = 0; |
|
1420 |
||
1421 |
for (int index = 0; index < timeouts.length; index++) { |
|
1422 |
totalWait += timeouts[index]; |
|
1423 |
} |
|
1424 |
||
1425 |
if (rangeCheck) { |
|
1426 |
// If sum of timeouts within limits then finished. |
|
1427 |
if (totalWait >= min && totalWait <= max) { |
|
1428 |
return timeouts; |
|
1429 |
} |
|
1430 |
||
1431 |
// Average out the timeouts so the sum is equal to the closest |
|
1432 |
// range boundary. |
|
1433 |
if (totalWait < min) { |
|
1434 |
averagedTimeout = min / timeouts.length; |
|
1435 |
} else { |
|
1436 |
averagedTimeout = max / timeouts.length; |
|
1437 |
} |
|
1438 |
||
1439 |
writeLog("capped_range_timeout_prop", |
|
1440 |
new Object[] {property, |
|
1441 |
String.valueOf(totalWait), |
|
1442 |
String.valueOf(min), |
|
1443 |
String.valueOf(max), |
|
1444 |
String.valueOf(timeouts.length), |
|
1445 |
String.valueOf(averagedTimeout)}); |
|
1446 |
} else { |
|
1447 |
// Sum of all timeouts must not exceed this value. |
|
1448 |
int maximumWait = getMulticastMaximumWait(); |
|
1449 |
||
1450 |
// If sum of timeouts within limits then finished. |
|
1451 |
if (totalWait <= maximumWait) { |
|
1452 |
return timeouts; |
|
1453 |
} |
|
1454 |
||
1455 |
// Average out the timeouts so the sum is equal to the maximum |
|
1456 |
// timeout. |
|
1457 |
averagedTimeout = maximumWait / timeouts.length; |
|
1458 |
||
1459 |
writeLog("capped_timeout_prop", |
|
1460 |
new Object[] {property, |
|
1461 |
String.valueOf(totalWait), |
|
1462 |
String.valueOf(maximumWait), |
|
1463 |
String.valueOf(timeouts.length), |
|
1464 |
String.valueOf(averagedTimeout)}); |
|
1465 |
} |
|
1466 |
||
1467 |
for (int index = 0; index < timeouts.length; index++) { |
|
1468 |
timeouts[index] = averagedTimeout; |
|
1469 |
} |
|
1470 |
||
1471 |
return timeouts; |
|
1472 |
} |
|
1473 |
||
1474 |
private int[] parseTimeouts(String property, int[] defaults) { |
|
1475 |
||
1476 |
String sTimeouts = System.getProperty(property); |
|
1477 |
||
1478 |
if (sTimeouts == null || sTimeouts.length() <= 0) { |
|
1479 |
return defaults; |
|
1480 |
||
1481 |
} |
|
1482 |
||
1483 |
Vector timeouts = null; |
|
1484 |
||
1485 |
try { |
|
1486 |
timeouts = SrvLocHeader.parseCommaSeparatedListIn(sTimeouts, true); |
|
1487 |
||
1488 |
} catch (ServiceLocationException ex) { |
|
1489 |
writeLog("syntax_error_prop", |
|
1490 |
new Object[] {property, sTimeouts}); |
|
1491 |
return defaults; |
|
1492 |
||
1493 |
} |
|
1494 |
||
1495 |
int iCount = 0; |
|
1496 |
int[] iTOs = new int[timeouts.size()]; |
|
1497 |
||
1498 |
for (Enumeration en = timeouts.elements(); en.hasMoreElements(); ) { |
|
1499 |
String s1 = (String)en.nextElement(); |
|
1500 |
||
1501 |
try { |
|
1502 |
iTOs[iCount] = Integer.parseInt(s1); |
|
1503 |
||
1504 |
} catch (NumberFormatException nfe) { |
|
1505 |
writeLog("syntax_error_prop", |
|
1506 |
new Object[] {property, sTimeouts}); |
|
1507 |
return defaults; |
|
1508 |
||
1509 |
} |
|
1510 |
||
1511 |
if (iTOs[iCount] < 0) { |
|
1512 |
writeLog("invalid_timeout_prop", |
|
1513 |
new Object[] {property, String.valueOf(iTOs[iCount])}); |
|
1514 |
return defaults; |
|
1515 |
} |
|
1516 |
||
1517 |
iCount++; |
|
1518 |
} |
|
1519 |
||
1520 |
return iTOs; |
|
1521 |
} |
|
1522 |
||
1523 |
// ----------------------------- |
|
1524 |
// SLP Time Calculation |
|
1525 |
// |
|
1526 |
||
1527 |
/** |
|
1528 |
* Returns the number of seconds since 00:00 Universal Coordinated |
|
1529 |
* Time, January 1, 1970. |
|
1530 |
* |
|
1531 |
* Java returns the number of milliseconds, so all the method does is |
|
1532 |
* divide by 1000. |
|
1533 |
* |
|
1534 |
* This implementation still will have a problem when the Java time |
|
1535 |
* values wraps, but there isn't much we can do now. |
|
1536 |
*/ |
|
1537 |
static long currentSLPTime() { |
|
1538 |
return (System.currentTimeMillis() / 1000); |
|
1539 |
} |
|
1540 |
||
1541 |
/* security */ |
|
1542 |
||
1543 |
// Indicates whether security class is available. |
|
1544 |
||
1545 |
boolean getSecurityEnabled() { |
|
1546 |
return securityEnabled; |
|
1547 |
||
1548 |
} |
|
1549 |
||
1550 |
private static boolean securityEnabled; |
|
1551 |
||
1552 |
// Indicates whether the securityEnabled property is true |
|
1553 |
||
1554 |
boolean getHasSecurity() { |
|
1555 |
return securityEnabled && |
|
1556 |
(new Boolean(System.getProperty("net.slp.securityEnabled", |
|
1557 |
"false")).booleanValue()); |
|
1558 |
} |
|
1559 |
||
1560 |
// I18N Support. |
|
1561 |
||
1562 |
private static final String BASE_BUNDLE_NAME = "com/sun/slp/ClientLib"; |
|
1563 |
||
1564 |
ResourceBundle getMessageBundle(Locale locale) { |
|
1565 |
||
1566 |
ResourceBundle msgBundle = null; |
|
1567 |
||
1568 |
// First try the Solaris Java locale area |
|
1569 |
||
1570 |
try { |
|
1571 |
URL[] urls = new URL[] {new URL("file:/usr/share/lib/locale/")}; |
|
1572 |
||
1573 |
URLClassLoader ld = new URLClassLoader(urls); |
|
1574 |
||
1575 |
msgBundle = ResourceBundle.getBundle(BASE_BUNDLE_NAME, locale, ld); |
|
1576 |
||
1577 |
return msgBundle; |
|
1578 |
} catch (MalformedURLException e) { // shouldn't get here |
|
1579 |
} catch (MissingResourceException ex) { |
|
1580 |
System.err.println("Missing resource bundle ``"+ |
|
1581 |
"/usr/share/lib/locale/" + BASE_BUNDLE_NAME + |
|
1582 |
"'' for locale ``" + |
|
1583 |
locale + "''; trying default..."); |
|
1584 |
} |
|
1585 |
||
1586 |
try { |
|
1587 |
msgBundle = ResourceBundle.getBundle(BASE_BUNDLE_NAME, locale); |
|
1588 |
||
1589 |
} catch (MissingResourceException ex) { // can't localize this one! |
|
1590 |
||
1591 |
// We can't print out to the log, because we may be in the |
|
1592 |
// process of trying to. |
|
1593 |
||
1594 |
System.err.println("Missing resource bundle ``"+ |
|
1595 |
BASE_BUNDLE_NAME+ |
|
1596 |
"'' for locale ``"+ |
|
1597 |
locale+ |
|
1598 |
"''"); |
|
1599 |
// Hosed if the default locale is missing. |
|
1600 |
||
1601 |
if (locale.equals(Defaults.locale)) { |
|
1602 |
||
1603 |
System.err.println("Exiting..."); |
|
1604 |
System.exit(1); |
|
1605 |
} |
|
1606 |
||
1607 |
// Otherwise, return the default locale. |
|
1608 |
||
1609 |
System.err.println("Using SLP default locale ``" + |
|
1610 |
Defaults.locale + |
|
1611 |
"''"); |
|
1612 |
||
1613 |
msgBundle = getMessageBundle(Defaults.locale); |
|
1614 |
||
1615 |
} |
|
1616 |
||
1617 |
return msgBundle; |
|
1618 |
} |
|
1619 |
||
1620 |
String formatMessage(String msgTag, Object[] params) { |
|
1621 |
ResourceBundle bundle = getMessageBundle(getLocale()); |
|
1622 |
return formatMessageInternal(msgTag, params, bundle); |
|
1623 |
||
1624 |
} |
|
1625 |
||
1626 |
// MessageFormat is picky about types. Convert the params into strings. |
|
1627 |
||
1628 |
static void convertToString(Object[] params) { |
|
1629 |
int i, n = params.length; |
|
1630 |
||
1631 |
for (i = 0; i < n; i++) { |
|
1632 |
||
1633 |
if (params[i] != null) { |
|
1634 |
params[i] = params[i].toString(); |
|
1635 |
||
1636 |
} else { |
|
1637 |
params[i] = "<null>"; |
|
1638 |
||
1639 |
} |
|
1640 |
} |
|
1641 |
} |
|
1642 |
||
1643 |
static String |
|
1644 |
formatMessageInternal(String msgTag, |
|
1645 |
Object[] params, |
|
1646 |
ResourceBundle bundle) { |
|
1647 |
String pattern = ""; |
|
1648 |
||
1649 |
try { |
|
1650 |
pattern = bundle.getString(msgTag); |
|
1651 |
||
1652 |
} catch (MissingResourceException ex) { |
|
1653 |
||
1654 |
// Attempt to report error. Can't use Assert here because it |
|
1655 |
// calls back into SLPConfig. |
|
1656 |
String msg = "Can''t find message ``{0}''''."; |
|
1657 |
||
1658 |
try { |
|
1659 |
pattern = bundle.getString("cant_find_resource"); |
|
1660 |
msg = MessageFormat.format(pattern, new Object[] {msgTag}); |
|
1661 |
||
1662 |
} catch (MissingResourceException exx) { |
|
1663 |
||
1664 |
} |
|
1665 |
||
1666 |
System.err.println(msg); |
|
1667 |
System.exit(-1); |
|
1668 |
} |
|
1669 |
||
1670 |
convertToString(params); |
|
1671 |
||
1672 |
return MessageFormat.format(pattern, params); |
|
1673 |
} |
|
1674 |
||
1675 |
// logging. |
|
1676 |
||
1677 |
// Protected so slpd can replace it. |
|
1678 |
||
1679 |
protected Writer log; |
|
1680 |
||
1681 |
// Synchronized so writes from multiple threads don't get interleaved. |
|
1682 |
||
1683 |
void writeLog(String msgTag, Object[] params) { |
|
1684 |
||
1685 |
// MessageFormat is picky about types. Convert the params into strings. |
|
1686 |
||
1687 |
convertToString(params); |
|
1688 |
||
1689 |
try { |
|
1690 |
synchronized (log) { |
|
1691 |
log.write(formatMessage(msgTag, params)); |
|
1692 |
log.flush(); |
|
1693 |
} |
|
1694 |
} catch (IOException ex) {} |
|
1695 |
} |
|
1696 |
||
1697 |
void writeLogLine(String msgTag, Object[] params) { |
|
1698 |
||
1699 |
try { |
|
1700 |
String pattern = getMessageBundle(getLocale()).getString(msgTag); |
|
1701 |
||
1702 |
synchronized (log) { |
|
1703 |
log.write(formatMessage(msgTag, params)); |
|
1704 |
log.write("\n"); |
|
1705 |
log.flush(); |
|
1706 |
} |
|
1707 |
} catch (IOException ex) {} |
|
1708 |
||
1709 |
} |
|
1710 |
||
1711 |
static String getDateString() { |
|
1712 |
||
1713 |
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, |
|
1714 |
DateFormat.DEFAULT, |
|
1715 |
getLocale()); |
|
1716 |
Calendar calendar = Calendar.getInstance(getLocale()); |
|
1717 |
return df.format(calendar.getTime()); |
|
1718 |
||
1719 |
} |
|
1720 |
||
1721 |
||
1722 |
// On load, check whether the signature class is available, and turn |
|
1723 |
// security off if not. |
|
1724 |
||
1725 |
static { |
|
1726 |
||
1727 |
securityEnabled = true; |
|
1728 |
try { |
|
1729 |
Class c = Class.forName("com.sun.slp.AuthBlock"); |
|
1730 |
||
1731 |
} catch (ClassNotFoundException e) { |
|
1732 |
securityEnabled = false; |
|
1733 |
} |
|
1734 |
} |
|
1735 |
||
1736 |
} |