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-2002 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.Date; 32 import java.text.SimpleDateFormat; 33 import java.text.DateFormat; 34 import java.util.StringTokenizer; 35 import java.io.Serializable; 36 37 /** 38 * This class represents a record in a DHCP network table. It can also be used 39 * to manage an associated hosts record by setting the client name; that effect 40 * is not part of this class, but rather is provided by the DhcpNetMgr. 41 */ 42 public class DhcpClientRecord implements Serializable, Comparable, Cloneable { 43 44 /** 45 * Default values for class attributes. 46 */ 47 public static final String DEFAULT_CLIENT_ID = new String("00"); 48 public static final String DEFAULT_FLAGS = new String("00"); 49 public static final String DEFAULT_CLIENT_NAME = new String(); 50 public static final String DEFAULT_EXPIRATION = new String("0"); 51 public static final String DEFAULT_SIGNATURE = new String("0"); 52 public static final String DEFAULT_MACRO = new String("UNKNOWN"); 53 public static final String DEFAULT_COMMENT = new String(); 54 55 /** 56 * Expiration special values. 57 */ 58 private static final String EXPIRATION_ZERO = new String("0"); 59 private static final String EXPIRATION_FOREVER = new String("-1"); 60 61 private String clientId; 62 private byte flags; 63 private IPAddress clientIP; 64 private IPAddress serverIP; 65 private Date expiration; 66 private String signature = DEFAULT_SIGNATURE; 67 private String macro; 68 private String comment; 69 private String clientName = null; 70 private String serverName = null; 71 72 // Serialization id of this class 73 static final long serialVersionUID = 5007310554198923085L; 74 75 /** 76 * Constructs a basic, empty client record. 77 */ DhcpClientRecord()78 public DhcpClientRecord() { 79 clientId = DEFAULT_CLIENT_ID; 80 macro = comment = null; 81 flags = 0; 82 clientIP = serverIP = null; 83 expiration = null; 84 signature = DEFAULT_SIGNATURE; 85 } 86 87 /** 88 * Constructs a client record with a client IP. 89 * @param clientIP the client IP address for the record. 90 */ DhcpClientRecord(String clientIP)91 public DhcpClientRecord(String clientIP) throws ValidationException { 92 setDefaults(); 93 setClientIP(new IPAddress(clientIP)); 94 } 95 96 /** 97 * Constructs a fully specified client record 98 * @param clientId Client's unique identifier 99 * @param flags Status flags for the record 100 * @param clientIP Client's IP address 101 * @param serverIP IP address of owning server 102 * @param expiration Lease expiration time in seconds since Unix epoch 103 * @param macro Configuration macro associated with this record 104 * @param comment User notes on this record 105 */ DhcpClientRecord(String clientId, String flags, String clientIP, String serverIP, String expiration, String macro, String comment)106 public DhcpClientRecord(String clientId, String flags, String clientIP, 107 String serverIP, String expiration, String macro, 108 String comment) throws ValidationException { 109 110 this(clientId, flags, clientIP, serverIP, expiration, macro, 111 comment, DEFAULT_SIGNATURE); 112 } 113 114 /** 115 * Constructs a fully specified client record 116 * @param clientId Client's unique identifier 117 * @param flags Status flags for the record 118 * @param clientIP Client's IP address 119 * @param serverIP IP address of owning server 120 * @param expiration Lease expiration time in seconds since Unix epoch 121 * @param macro Configuration macro associated with this record 122 * @param comment User notes on this record 123 * @param signature Opaque signature 124 */ DhcpClientRecord(String clientId, String flags, String clientIP, String serverIP, String expiration, String macro, String comment, String signature)125 public DhcpClientRecord(String clientId, String flags, String clientIP, 126 String serverIP, String expiration, String macro, 127 String comment, String signature) 128 throws ValidationException { 129 setClientId(clientId); 130 this.flags = Byte.parseByte(flags); 131 setClientIP(new IPAddress(clientIP)); 132 setServerIP(new IPAddress(serverIP)); 133 setExpiration(expiration); 134 this.macro = macro; 135 this.comment = comment; 136 this.signature = signature; 137 } 138 139 /** 140 * Make a copy of this record 141 */ clone()142 public Object clone() { 143 DhcpClientRecord newrec = new DhcpClientRecord(); 144 newrec.clientId = clientId; 145 newrec.flags = flags; 146 if (clientIP != null) { 147 newrec.clientIP = (IPAddress)clientIP.clone(); 148 } 149 if (serverIP != null) { 150 newrec.serverIP = (IPAddress)serverIP.clone(); 151 } 152 if (expiration != null) { 153 newrec.expiration = (Date)expiration.clone(); 154 } 155 newrec.macro = macro; 156 newrec.comment = comment; 157 newrec.clientName = clientName; 158 newrec.serverName = serverName; 159 newrec.signature = signature; 160 return newrec; 161 } 162 163 /** 164 * Fully specifies the defaults for a client record 165 */ setDefaults()166 public void setDefaults() 167 throws ValidationException { 168 setClientId(DEFAULT_CLIENT_ID); 169 setFlags(DEFAULT_FLAGS); 170 setClientName(DEFAULT_CLIENT_NAME); 171 setExpiration(DEFAULT_EXPIRATION); 172 setMacro(DEFAULT_MACRO); 173 setComment(DEFAULT_COMMENT); 174 } 175 176 /** 177 * Retrieve the client ID 178 * @return Client ID as a String 179 */ getClientId()180 public String getClientId() { 181 return clientId; 182 } 183 184 /** 185 * Set the client ID. See dhcp_network(4) for the rules about client 186 * ID syntax which are implemented here. 187 * @param clientId Client's unique identifier 188 */ setClientId(String clientId)189 public void setClientId(String clientId) throws ValidationException { 190 if (clientId.length() > 128 || clientId.length() % 2 != 0) { 191 // Must be even number of characters, no more than 128 characters 192 String msg = ResourceStrings.getString("dcr_invalid_clientid"); 193 throw new ValidationException(msg); 194 } 195 char [] c = clientId.toCharArray(); 196 for (int i = 0; i < c.length; ++i) { 197 if ((c[i] < '0' || c[i] > '9') && (c[i] < 'A' || c[i] > 'F')) { 198 String msg = ResourceStrings.getString("dcr_invalid_clientid"); 199 throw new ValidationException(msg); 200 } 201 } 202 this.clientId = clientId; 203 if (this.clientId.length() == 0) { 204 this.clientId = DEFAULT_CLIENT_ID; 205 } 206 } 207 208 /** 209 * Get the flags byte 210 * @return A <code>byte</code> containing the record's status flags 211 */ getFlags()212 public byte getFlags() { 213 return flags; 214 } 215 216 /** 217 * Get the flags as a string 218 * @return The flag byte converted to a String 219 */ getFlagString()220 public String getFlagString() { 221 return getFlagString(false); 222 } 223 getFlagString(boolean verbose)224 public String getFlagString(boolean verbose) { 225 226 StringBuffer b = new StringBuffer(); 227 if (!verbose) { 228 b.append(flags); 229 // Make sure we always have a 2-character representation. 230 if (flags < 10) { 231 b.insert(0, 0); 232 } 233 } 234 else { 235 if (flags == 0) { 236 b.append(DhcpClientFlagTypes.DYNAMIC.getCharVal()); 237 } else { 238 if (isPermanent()) { 239 b.append(DhcpClientFlagTypes.PERMANENT.getCharVal()); 240 } 241 if (isManual()) { 242 b.append(DhcpClientFlagTypes.MANUAL.getCharVal()); 243 } 244 if (isUnusable()) { 245 b.append(DhcpClientFlagTypes.UNUSABLE.getCharVal()); 246 } 247 if (isBootp()) { 248 b.append(DhcpClientFlagTypes.BOOTP.getCharVal()); 249 } 250 } 251 } 252 return b.toString(); 253 } 254 255 /** 256 * Test for setting of unusable flag 257 * @return <code>true</code> if the unusable flag is set, 258 * <code>false</code> if not. 259 */ isUnusable()260 public boolean isUnusable() { 261 return DhcpClientFlagTypes.UNUSABLE.isSet(flags); 262 } 263 264 /** 265 * Set/reset the unusable flag. 266 * @param state <code>true</code> if address is to be unusable 267 */ setUnusable(boolean state)268 public void setUnusable(boolean state) { 269 if (state) { 270 flags |= DhcpClientFlagTypes.UNUSABLE.getNumericVal(); 271 } else { 272 flags &= ~DhcpClientFlagTypes.UNUSABLE.getNumericVal(); 273 } 274 } 275 276 /** 277 * Test for setting of bootp flag 278 * @return <code>true</code> if the bootp flag is set, 279 * <code>false</code> if not. 280 */ isBootp()281 public boolean isBootp() { 282 return DhcpClientFlagTypes.BOOTP.isSet(flags); 283 } 284 285 /** 286 * Set/reset the bootp flag 287 * @param state <code>true</code> if address is reserved for BOOTP clients 288 */ setBootp(boolean state)289 public void setBootp(boolean state) { 290 if (state) { 291 flags |= DhcpClientFlagTypes.BOOTP.getNumericVal(); 292 } else { 293 flags &= ~DhcpClientFlagTypes.BOOTP.getNumericVal(); 294 } 295 } 296 297 /** 298 * Test for setting of manual assignment flag 299 * @return <code>true</code> if address is manually assigned, 300 * <code>false</code> if not. 301 */ isManual()302 public boolean isManual() { 303 return DhcpClientFlagTypes.MANUAL.isSet(flags); 304 } 305 306 /** 307 * Set/reset the manual assignment flag 308 * @param state <code>true</code> if the address is manually assigned 309 */ setManual(boolean state)310 public void setManual(boolean state) { 311 if (state) { 312 flags |= DhcpClientFlagTypes.MANUAL.getNumericVal(); 313 } else { 314 flags &= ~DhcpClientFlagTypes.MANUAL.getNumericVal(); 315 } 316 } 317 318 /** 319 * Test for setting of permanent assignment flag 320 * @return <code>true</code> if lease is permanent, 321 * <code>false</code> if dynamic 322 */ isPermanent()323 public boolean isPermanent() { 324 return DhcpClientFlagTypes.PERMANENT.isSet(flags); 325 } 326 327 /** 328 * Set/reset the permanent assignment flag 329 * @param state <code>true</code> if the address is permanently leased 330 */ setPermanent(boolean state)331 public void setPermanent(boolean state) { 332 if (state) { 333 flags |= DhcpClientFlagTypes.PERMANENT.getNumericVal(); 334 } else { 335 flags &= ~DhcpClientFlagTypes.PERMANENT.getNumericVal(); 336 } 337 } 338 339 /** 340 * Set the flags as a unit 341 * @param flags a <code>byte</code> setting for the flags 342 */ setFlags(String flags)343 public void setFlags(String flags) throws ValidationException { 344 if (flags.charAt(0) >= '0' && flags.charAt(0) <= '9') { 345 this.flags = Byte.parseByte(flags); 346 } else { 347 this.flags = 0; 348 StringTokenizer flagTokenizer = new StringTokenizer(flags, "+"); 349 while (flagTokenizer.hasMoreTokens()) { 350 String keyword = flagTokenizer.nextToken(); 351 if (keyword.equalsIgnoreCase( 352 DhcpClientFlagTypes.DYNAMIC.getKeyword())) { 353 // nothing to do, default is Dynamic. 354 } else if (keyword.equalsIgnoreCase( 355 DhcpClientFlagTypes.PERMANENT.getKeyword())) { 356 this.flags |= DhcpClientFlagTypes.PERMANENT.getNumericVal(); 357 } else if (keyword.equalsIgnoreCase( 358 DhcpClientFlagTypes.MANUAL.getKeyword())) { 359 this.flags |= DhcpClientFlagTypes.MANUAL.getNumericVal(); 360 } else if (keyword.equalsIgnoreCase( 361 DhcpClientFlagTypes.UNUSABLE.getKeyword())) { 362 this.flags |= DhcpClientFlagTypes.UNUSABLE.getNumericVal(); 363 } else if (keyword.equalsIgnoreCase( 364 DhcpClientFlagTypes.BOOTP.getKeyword())) { 365 this.flags |= DhcpClientFlagTypes.BOOTP.getNumericVal(); 366 } else { 367 String msg = ResourceStrings.getString("dcr_invalid_flags"); 368 throw new ValidationException(msg); 369 } 370 } 371 } 372 } 373 374 /** 375 * Set the flags as a unit 376 * @param flags a <code>byte</code> setting for the flags 377 */ setFlags(byte flags)378 public void setFlags(byte flags) { 379 this.flags = flags; 380 } 381 382 /** 383 * Retrieve the client's IP address 384 * @return the client's IP address 385 */ getClientIP()386 public IPAddress getClientIP() { 387 return clientIP; 388 } 389 390 /** 391 * Retrieve a string version of the client's IP address 392 * @return A <code>String</code> containing the dotted decimal IP address. 393 */ getClientIPAddress()394 public String getClientIPAddress() { 395 if (clientIP == null) { 396 return ""; 397 } else { 398 return clientIP.getHostAddress(); 399 } 400 } 401 402 /** 403 * Set the client's IP address 404 * @param clientIP A String representation of the <code>IPAddress</code> 405 * to assign from this record. 406 */ setClientIP(String clientIP)407 public void setClientIP(String clientIP) throws ValidationException { 408 if (clientIP == null) { 409 String msg = ResourceStrings.getString("dcr_invalid_null_clientip"); 410 throw new ValidationException(msg); 411 } 412 413 try { 414 setClientIP(new IPAddress(clientIP)); 415 } catch (Throwable e) { 416 String msg = ResourceStrings.getString("dcr_invalid_clientip"); 417 throw new ValidationException(msg); 418 } 419 } 420 421 /** 422 * Set the client's IP address 423 * @param clientIP An <code>IPAddress</code> to assign from this record. 424 */ setClientIP(IPAddress clientIP)425 public void setClientIP(IPAddress clientIP) throws ValidationException { 426 if (clientIP == null) { 427 String msg = ResourceStrings.getString("dcr_invalid_null_clientip"); 428 throw new ValidationException(msg); 429 } 430 this.clientIP = clientIP; 431 } 432 433 /** 434 * Retrieve the IP address of the owning server. 435 * @return An <code>IPAddress</code> for the server controlling this record. 436 */ getServerIP()437 public IPAddress getServerIP() { 438 return serverIP; 439 } 440 441 /** 442 * Retrieve a string version of the owning server's IP address 443 * @return The server's dotted decimal IP address as a <code>String</code> 444 */ getServerIPAddress()445 public String getServerIPAddress() { 446 if (serverIP == null) { 447 return ""; 448 } else { 449 return serverIP.getHostAddress(); 450 } 451 } 452 453 /** 454 * Set the server's IP address 455 * @param serverIP A String representation of the <code>IPAddress</code> 456 * to assign from this record. 457 */ setServerIP(String serverIP)458 public void setServerIP(String serverIP) throws ValidationException { 459 if (serverIP == null) { 460 String msg = ResourceStrings.getString("dcr_invalid_null_serverip"); 461 throw new ValidationException(msg); 462 } 463 464 try { 465 setServerIP(new IPAddress(serverIP)); 466 } catch (Throwable e) { 467 String msg = ResourceStrings.getString("dcr_invalid_serverip"); 468 throw new ValidationException(msg); 469 } 470 } 471 472 /** 473 * Assign this address to a server denoted by its IP address 474 * @param serverIP The <code>IPAddress</code> of the owning server. 475 */ setServerIP(IPAddress serverIP)476 public void setServerIP(IPAddress serverIP) throws ValidationException { 477 if (serverIP == null) { 478 String msg = ResourceStrings.getString("dcr_invalid_null_serverip"); 479 throw new ValidationException(msg); 480 } 481 this.serverIP = serverIP; 482 } 483 484 /** 485 * @return The expiration time of this record's lease as a <code>Date</code> 486 */ getExpiration()487 public Date getExpiration() { 488 return expiration; 489 } 490 491 /** 492 * @return The expiration time of this record's lease in seconds 493 * since the epoch, as a <code>String</code> 494 */ getExpirationTime()495 public String getExpirationTime() { 496 if (expiration == null) { 497 return null; 498 } 499 if (expiration.getTime() == Long.parseLong(EXPIRATION_FOREVER)) { 500 return EXPIRATION_FOREVER; 501 } else { 502 return String.valueOf((expiration.getTime()/(long)1000)); 503 } 504 } 505 506 /** 507 * Set the lease expiration date. 508 * @param expiration Lease expiration time in seconds since Unix epoch 509 */ setExpiration(String expiration)510 public void setExpiration(String expiration) { 511 this.expiration = new Date((long)(Long.parseLong(expiration)*1000)); 512 } 513 514 /** 515 * Set the lease expiration date. 516 * @param expiration The <code>Date</code> when the lease expires. 517 */ setExpiration(Date expiration)518 public void setExpiration(Date expiration) { 519 this.expiration = expiration; 520 } 521 522 /** 523 * Set the lease expiration date by parsing a formatted string. Also 524 * provides special handling of the "0" and "-1" values. 525 * @param dateFormat A DateFormat used to parse the expiration date 526 * @param date Lease expiration in desired format. 527 */ setExpiration(DateFormat dateFormat, String date)528 public void setExpiration(DateFormat dateFormat, String date) 529 throws ValidationException { 530 531 if (date == null) { 532 setExpiration(date); 533 } else if (date.equals(EXPIRATION_ZERO)) { 534 setExpiration(date); 535 } else if (date.equals(EXPIRATION_FOREVER)) { 536 setExpiration(date); 537 } else { 538 try { 539 expiration = dateFormat.parse(date); 540 } catch (Exception ex) { 541 String msg = 542 ResourceStrings.getString("dcr_invalid_expiration"); 543 throw new ValidationException(msg); 544 } 545 } 546 } 547 548 /** 549 * @return The name of the macro used to explicitly configure this address 550 */ getMacro()551 public String getMacro() { 552 return macro; 553 } 554 555 /** 556 * Set the name of the macro used to explicitly configure this address 557 */ setMacro(String macro)558 public void setMacro(String macro) { 559 this.macro = macro; 560 } 561 562 /** 563 * @return The descriptive comment for this record 564 */ getComment()565 public String getComment() { 566 return comment; 567 } 568 569 /** 570 * Set a descriptive comment for this record 571 * @param comment The comment 572 */ setComment(String comment)573 public void setComment(String comment) { 574 this.comment = comment; 575 } 576 577 /** 578 * @return The signature for this record 579 */ getSignature()580 public String getSignature() { 581 return signature; 582 } 583 584 /** 585 * Set the signature for this record 586 * @param signature The new signature value 587 */ setSignature(String signature)588 public void setSignature(String signature) { 589 this.signature = signature; 590 } 591 592 /** 593 * Perform comparisons to another DhcpClientRecord instance. This is used 594 * for sorting a network table by client address. 595 * @param o A <code>DhcpClientRecord</code> to compare against. 596 * @return 0 if the objects have the same address, 597 * a negative number if this record has a lower IP address than the 598 * supplied record, a positive number if this record has a higher IP 599 * address than the supplied record. 600 */ compareTo(Object o)601 public int compareTo(Object o) { 602 DhcpClientRecord r = (DhcpClientRecord)o; 603 return (int)(getBinaryAddress() - r.getBinaryAddress()); 604 } 605 606 /** 607 * Retrieve the IP address as a number suitable for arithmetic operations. 608 * We use a <code>long</code> rather than an <code>int</code> in order to 609 * be able to treat it as an unsigned value, since all Java types are 610 * signed. 611 * @return The IP address as a <code>long</code>. 612 */ getBinaryAddress()613 public long getBinaryAddress() { 614 return (clientIP.getBinaryAddress()); 615 } 616 617 /** 618 * @return The client's hostname 619 */ getClientName()620 public String getClientName() { 621 if (clientName == null && clientIP != null) { 622 clientName = clientIP.getHostName(); 623 } 624 return clientName; 625 } 626 627 /** 628 * @param name The hostname for the client. 629 */ setClientName(String name)630 public void setClientName(String name) { 631 clientName = name; 632 } 633 634 /** 635 * @return The server's hostname 636 */ getServerName()637 public String getServerName() { 638 if (serverName == null && serverIP != null) { 639 serverName = serverIP.getHostName(); 640 } 641 return serverName; 642 } 643 644 /** 645 * @param name The server's hostname 646 */ setServerName(String name)647 public void setServerName(String name) { 648 serverName = name; 649 } 650 toString()651 public String toString() { 652 653 String server = null; 654 if (serverIP != null) { 655 server = serverIP.getHostAddress(); 656 } 657 658 String client = null; 659 if (clientIP != null) { 660 client = clientIP.getHostAddress(); 661 } 662 663 String expiration = null; 664 if (this.expiration != null) { 665 expiration = this.expiration.toString(); 666 } 667 668 String s = clientId + " " + String.valueOf(flags) + " " 669 + client + " " + server 670 + " " + expiration + " " + signature 671 + " " + macro + " " + comment; 672 return s; 673 } 674 } 675