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 1998-2003 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 package com.sun.dhcpmgr.data;
30
31 import java.util.*;
32
33 /**
34 * Option is a simple data class which encapsulates an option record in
35 * the dhcptab. See dhcptab(4) for the gory details on options (aka symbols).
36 *
37 * @see DhcptabRecord
38 * @see Macro
39 */
40 public class Option extends DhcptabRecord implements Cloneable {
41 private byte context;
42 private short code;
43 private byte type;
44 private int granularity;
45 private int maximum;
46 private Vector vendors;
47 private boolean valueClean = false;
48 private boolean validValue = true;
49
50 // The Option attributes that must match their native values.
51
52 // Definition for attribute limits
53 public static short MAX_NAME_SIZE = 128;
54
55 // Option contexts.
56 public static byte STANDARD = 0;
57 public static byte EXTEND = 1;
58 public static byte VENDOR = 2;
59 public static byte SITE = 3;
60 public static byte CONTEXTS = 4;
61 public static OptionContext [] ctxts = {
62 new OptionContext(STANDARD, "Standard", "standard_option"),
63 new OptionContext(EXTEND, "Extend", "extended_option"),
64 new OptionContext(VENDOR, "Vendor=", "vendor_option"),
65 new OptionContext(SITE, "Site", "site_option") };
66
67 // Option types.
68 public static byte ASCII = 0;
69 public static byte OCTET = 1;
70 public static byte IP = 2;
71 public static byte NUMBER = 3;
72 public static byte BOOLEAN = 4;
73 public static byte UNUMBER8 = 5;
74 public static byte UNUMBER16 = 6;
75 public static byte UNUMBER32 = 7;
76 public static byte UNUMBER64 = 8;
77 public static byte SNUMBER8 = 9;
78 public static byte SNUMBER16 = 10;
79 public static byte SNUMBER32 = 11;
80 public static byte SNUMBER64 = 12;
81 public static byte TYPES = 13;
82
83 public static OptionType [] types = {
84 new OptionType((byte)0, "ASCII", "ascii_type"),
85 new OptionType((byte)1, "OCTET", "octet_type"),
86 new OptionType((byte)2, "IP", "ip_type"),
87 new OptionType((byte)3, "NUMBER", "number_type"),
88 new OptionType((byte)4, "BOOL", "boolean_type"),
89 new OptionType((byte)6, "UNUMBER8", "unumber8_type"),
90 new OptionType((byte)7, "UNUMBER16", "unumber16_type"),
91 new OptionType((byte)8, "UNUMBER32", "unumber32_type"),
92 new OptionType((byte)9, "UNUMBER64", "unumber64_type"),
93 new OptionType((byte)10, "SNUMBER8", "snumber8_type"),
94 new OptionType((byte)11, "SNUMBER16", "snumber16_type"),
95 new OptionType((byte)12, "SNUMBER32", "snumber32_type"),
96 new OptionType((byte)13, "SNUMBER64", "snumber64_type") };
97
98 /*
99 * These need to be the same as the definitions in libdhcputil's
100 * parser in dhcp_symbol.c
101 */
102 public static String DSYM_CLASS_DEL_SPACE = " ";
103 public static String DSYM_CLASS_DEL = DSYM_CLASS_DEL_SPACE + "\t\n";
104 public static String DSYM_CLASS_DEL_REGEXP = ".*[" + DSYM_CLASS_DEL + "].*";
105 public static char DSYM_FIELD_DEL = ',';
106 public static char DSYM_QUOTE = '"';
107
108
109 // Serialization id for this class
110 static final long serialVersionUID = 7468266817375654444L;
111
112 /**
113 * Construct an empty instance. Default to Site option, IP type.
114 */
115 public Option() {
116 super("", DhcptabRecord.OPTION, "");
117 valueClean = false;
118 vendors = new Vector();
119 context = ctxts[SITE].getCode();
120 type = types[IP].getCode();
121 granularity = 1;
122 }
123
124 /**
125 * Construct a fully defined instance. Used by the server to create
126 * Options.
127 * @param name the option name/key
128 * @param context the option context/category code
129 * @param vendors the list of vendors (if any)
130 * @param code the option code
131 * @param type the option type code
132 * @param gran the option granularity
133 * @param max the option maximum
134 * @param sig the signature from the dhcptab
135 * @param isValid the flag indicating option definition validity
136 */
137 public Option(String name, byte context, String [] vendors, short code,
138 byte type, int gran, int max, String sig, boolean isValid) {
139
140 super("", DhcptabRecord.OPTION, "");
141
142 valueClean = false;
143 validValue = isValid;
144
145 setKey(name);
146 setContext(context);
147 setVendors(vendors);
148 setCode(code);
149 setType(type);
150 setGranularity(gran);
151 setMaximum(max);
152
153 if (sig != null) {
154 setSignature(sig);
155 }
156 }
157
158 /**
159 * Set the option name as specified.
160 * @param name a string representing the option name.
161 */
162 public void setKey(String name) {
163 try {
164 super.setKey(name);
165 } catch (ValidationException e) {
166 // Can't happen.
167 }
168 }
169
170 /**
171 * Get the context for this option
172 * @return a byte for the option context (context codes are
173 * defined by the OptionContext objects in the ctxts array).
174 */
175 public byte getContext() {
176 return context;
177 }
178
179 /**
180 * Set the context for this option (context codes are defined
181 * by the OptionContext objects in the ctxts array).
182 */
183 public void setContext(byte c) {
184 context = c;
185 valueClean = false;
186 }
187
188 /**
189 * Enumerate the vendor list.
190 * @return an Enumeration of the vendors, which will be empty for
191 * non-vendor options.
192 */
193 public Enumeration getVendors() {
194 return vendors.elements();
195 }
196
197 /**
198 * Get the number of vendors for this option.
199 * @return an int count of the vendors, zero for non-vendor options.
200 */
201 public int getVendorCount() {
202 return vendors.size();
203 }
204
205 /**
206 * Add a vendor to the list for this option.
207 * @param v the vendor name as a String.
208 */
209 public void addVendor(String v) throws ValidationException {
210 if (v.indexOf(DSYM_FIELD_DEL) != -1) {
211 throw new ValidationException(v);
212 }
213 vendors.addElement(v);
214 valueClean = false;
215 }
216
217 /**
218 * Empty the vendor list.
219 */
220 public void clearVendors() {
221 vendors = new Vector();
222 valueClean = false;
223 }
224
225 /**
226 * Remove a vendor from the list.
227 * @param index the position of the vendor to remove in the list of vendors
228 */
229 public void removeVendorAt(int index) {
230 vendors.removeElementAt(index);
231 valueClean = false;
232 }
233
234 /**
235 * Get the vendor at a specified index in the vendor list.
236 * @param index the index of the vendor to retrieve
237 * @return the vendor name
238 */
239 public String getVendorAt(int index) {
240 return (String)vendors.elementAt(index);
241 }
242
243 private void setVendors(String [] vendors) {
244
245 this.vendors = new Vector();
246
247 if (vendors == null) {
248 return;
249 }
250
251 for (int i = 0; i < vendors.length; i++) {
252 this.vendors.addElement(vendors[i]);
253 }
254
255 }
256
257 /**
258 * Set the vendor name at a specified index in the list.
259 * @param vendor the vendor name
260 * @param index the position in the list to set.
261 */
262 public void setVendorAt(String vendor, int index) {
263 if (index >= vendors.size()) {
264 vendors.setSize(index+1);
265 }
266 vendors.setElementAt(vendor, index);
267 valueClean = false;
268 }
269
270 /**
271 * Get the option code.
272 * @return the code as a short.
273 */
274 public short getCode() {
275 return code;
276 }
277
278 /**
279 * Set the option code.
280 * @param c the code to use
281 */
282 public void setCode(short c) {
283 code = c;
284 valueClean = false;
285 }
286
287 /**
288 * Get the type.
289 * @return a byte value for the type (type codes are
290 * defined by the OptionTypes objects in the type array).
291 * OCTET
292 */
293 public byte getType() {
294 return type;
295 }
296
297 /**
298 * Set the type.
299 * @param t the type code (type codes are defined by the
300 * OptionTypes objects in the type array).
301 * or OCTET.
302 */
303 public void setType(byte t) {
304 type = t;
305 valueClean = false;
306 }
307
308 /**
309 * Get the granularity. See dhcptab(4) for an explanation of granularity
310 * interpretations.
311 * @return the granularity as an int
312 */
313 public int getGranularity() {
314 return granularity;
315 }
316
317 /**
318 * Set the granularity. See dhcptab(4) for an explanation of granularity
319 * interpretations.
320 * @param g the granularity as an int.
321 */
322 public void setGranularity(int g) {
323 granularity = g;
324 valueClean = false;
325 }
326
327 /**
328 * Get the maximum. See dhcptab(4) for an explanation of maximum.
329 * @return the maximum as an int.
330 */
331 public int getMaximum() {
332 return maximum;
333 }
334
335 /**
336 * Set the maximum. See dhcptab(4) for an explanation of maximum.
337 * @param m the maximum as an int.
338 */
339 public void setMaximum(int m) {
340 maximum = m;
341 valueClean = false;
342 }
343
344 /**
345 * Return validity of this option.
346 * @return true if the option is correctly defined, false if not
347 */
348 public boolean isValid() {
349 return (validValue);
350 }
351
352 /**
353 * Get the definition as a string in the format specified by dhcptab(4)
354 * @return a String containing the definition
355 */
356 public String getValue() {
357 /* The value string stored is not clean, regenerate */
358 if (!valueClean) {
359 StringBuffer b = new StringBuffer();
360 // Start with context
361 b.append(getContextDhcptabString(context));
362 // Vendor context next adds the vendors, separate by blanks
363 if (context == ctxts[VENDOR].getCode()) {
364 boolean first = true;
365 for (Enumeration e = getVendors(); e.hasMoreElements(); ) {
366 String s = (String)e.nextElement();
367 if (!first) {
368 b.append(DSYM_CLASS_DEL_SPACE);
369 } else {
370 first = false;
371 }
372 // If vendor class contains whitespace, need to quote it
373 boolean needQuoting = s.matches(DSYM_CLASS_DEL_REGEXP);
374 if (needQuoting) {
375 b.append(DSYM_QUOTE);
376 }
377 b.append(s);
378 if (needQuoting) {
379 b.append(DSYM_QUOTE);
380 }
381 }
382 }
383 b.append(DSYM_FIELD_DEL);
384 // Add the code
385 b.append(code);
386 b.append(DSYM_FIELD_DEL);
387 // Add the type
388 b.append(getTypeDhcptabString(type));
389 b.append(DSYM_FIELD_DEL);
390 // Add the granularity
391 b.append(granularity);
392 b.append(DSYM_FIELD_DEL);
393 // Add the maximum
394 b.append(maximum);
395 // Save it and note as such so we can avoid doing this again
396 try {
397 super.setValue(b.toString());
398 } catch (ValidationException e) {
399 // This should never happen!
400 }
401 valueClean = true;
402 }
403 return super.getValue();
404 }
405
406 // Make a copy of this option
407 public Object clone() {
408 Option o = new Option();
409
410 o.setKey(getKey());
411 o.setContext(getContext());
412 o.setCode(getCode());
413 o.vendors = new Vector();
414 for (Enumeration en = vendors.elements(); en.hasMoreElements(); ) {
415 String s = (String)en.nextElement();
416 o.vendors.addElement(new String(s));
417 }
418 o.setType(getType());
419 o.setGranularity(getGranularity());
420 o.setMaximum(getMaximum());
421 o.setSignature(getSignature());
422
423 return o;
424 }
425
426 /**
427 * Returns a string representation of this object.
428 * @return a string representation of this object.
429 */
430 public String toString() {
431 return (getKey() + " s " + getValue());
432 }
433
434 /**
435 * Returns the context definition for the specified context.
436 * @param code the context code.
437 * @return the OptionContext for the context.
438 */
439 public static OptionContext findContext(byte code) {
440
441 OptionContext ctxt = null;
442
443 for (int i = 0; i < CONTEXTS; i++) {
444 if (ctxts[i].getCode() == code) {
445 ctxt = ctxts[i];
446 break;
447 }
448 }
449
450 return (ctxt);
451 }
452
453 /**
454 * Returns the dhcptab string representation of the specified context.
455 * @param code the context code.
456 * @return the dhcptab string representation of the context.
457 */
458 public static String getContextDhcptabString(byte code) {
459
460 OptionContext ctxt = findContext(code);
461
462 if (ctxt == null) {
463 return ("undefined");
464 } else {
465 return (ctxt.getDhcptabString());
466 }
467 }
468
469 /**
470 * Returns the string representation of the specified context.
471 * @param code the context code.
472 * @return a string representation of the context.
473 */
474 public static String getContextString(byte code) {
475
476 OptionContext ctxt = findContext(code);
477
478 if (ctxt == null) {
479 return ("undefined");
480 } else {
481 return (ctxt.toString());
482 }
483 }
484
485 /**
486 * Returns the type definition for the specified type.
487 * @param code the type code.
488 * @return the OptionType for the type.
489 */
490 public static OptionType findType(byte code) {
491
492 OptionType type = null;
493
494 for (int i = 0; i < TYPES; i++) {
495 if (types[i].getCode() == code) {
496 type = types[i];
497 break;
498 }
499 }
500
501 return (type);
502 }
503
504 /**
505 * Returns the dhcptab string representation of the specified type.
506 * @param code the type code.
507 * @return the dhcptab string representation of the type.
508 */
509 public static String getTypeDhcptabString(byte code) {
510
511 OptionType type = findType(code);
512
513 if (type == null) {
514 return ("undefined"); // should never happen
515 } else {
516 return (type.getDhcptabString());
517 }
518 }
519
520 /**
521 * Returns the string representation of the specified type.
522 * @param code the type code.
523 * @return a string representation of the type.
524 */
525 public static String getTypeString(byte code) {
526
527 OptionType type = findType(code);
528
529 if (type == null) {
530 return ("undefined"); // should never happen
531 } else {
532 return (type.toString());
533 }
534 }
535 }