1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 */ 26 27 // RequestHandler.java: Handle an incoming request in a separate thread. 28 // Author: James Kempf 29 // Created On: Mon May 18 14:00:27 1998 30 // Last Modified By: James Kempf 31 // Last Modified On: Mon Mar 8 16:12:13 1999 32 // Update Count: 173 33 // 34 35 package com.sun.slp; 36 37 import java.io.*; 38 import java.net.*; 39 import java.util.*; 40 41 /** 42 * Handle an incoming request in a separate thread. The request 43 * may have arrived via datagram, or it may have arrived via 44 * stream. 45 * 46 * @author James Kempf, Erik Guttman 47 */ 48 49 50 class RequestHandler extends Thread { 51 52 private SLPConfig config; // Config for system properties. 53 private ServerDATable daTable; // DA table in server for reg and dereg 54 private InetAddress interfac = null; // Interface on which request came in. 55 private Socket sock = null; // Socket for incoming stream request. 56 private DatagramPacket packet = null; // Packet for datagram requests. 57 private InetAddress clientAddr = null; // Internet address of the client. 58 private int port = 0; // Port to use. 59 private ServiceTable serviceTable = null; 60 private SrvLocMsg toForward = null; // Reg or dereg to forward. 61 private InputStream inStream = null; 62 private OutputStream outStream = null; 63 64 static private Hashtable inProgress = new Hashtable(); 65 // Keeps track of in progress requests 66 67 // When a request handler gets GC'd, make sure it's open socket is closed. 68 // We simply let the exception propagate, because it is ignored. 69 70 protected void finalize() throws IOException { 71 if (sock != null) sock.close(); 72 73 } 74 75 RequestHandler(InputStream in, OutputStream out, SLPConfig config_in) { 76 config = config_in; 77 sock = null; 78 inStream = in; 79 outStream = out; 80 clientAddr = config.getLoopback(); 81 port = 427; 82 interfac = clientAddr; 83 84 try { 85 serviceTable = ServiceTable.getServiceTable(); 86 87 } catch (ServiceLocationException ex) { 88 89 // Taken care of in initialization code. 90 91 } 92 } 93 94 // Request arrived via stream. Set the incoming socket, spawn 95 // a separate thread in which to run. 96 97 RequestHandler(Socket sock_in, InetAddress interfac, SLPConfig config_in) { 98 99 Assert.slpassert((sock_in != null), 100 "rh_null_sock", 101 new Object[0]); 102 Assert.slpassert((config_in != null), 103 "ls_null_config", 104 new Object[0]); 105 106 config = config_in; 107 sock = sock_in; 108 clientAddr = sock.getInetAddress(); 109 port = sock.getPort(); 110 this.interfac = interfac; 111 112 try { 113 serviceTable = ServiceTable.getServiceTable(); 114 115 } catch (ServiceLocationException ex) { 116 117 // Taken care of in initialization code. 118 119 } 120 } 121 122 // Request arrived via datagram. Set the incoming packet, spawn 123 // a separate thread in which to run. 124 125 RequestHandler(DatagramPacket packet_in, 126 InetAddress interfac, 127 SLPConfig config_in) { 128 129 Assert.slpassert((packet_in != null), 130 "rh_null_packy", 131 new Object[0]); 132 Assert.slpassert((config_in != null), 133 "ls_null_config", 134 new Object[0]); 135 136 config = config_in; 137 packet = packet_in; 138 clientAddr = packet.getAddress(); 139 port = packet.getPort(); 140 this.interfac = interfac; 141 142 try { 143 serviceTable = ServiceTable.getServiceTable(); 144 daTable = ServerDATable.getServerDATable(); 145 146 } catch (ServiceLocationException ex) { 147 148 // Taken care of in initialziation code. 149 150 } 151 152 } 153 154 /** 155 * Return a stringified buffer, suitable for printing, for 156 * debugging. 157 * 158 * @param bytes The byte buffer. 159 * @return A string with the ASCII characters as characters, otherwise 160 * convert to escape notation. 161 */ 162 163 static String stringifyBuffer(byte[] bytes) { 164 165 StringBuffer buf = new StringBuffer(); 166 int i, n = bytes.length; 167 168 for (i = 0; i < n; i++) { 169 byte b = bytes[i]; 170 171 if ((b >= 0x21) && (b < 0x7e)) { 172 buf.append((char)b); 173 } else { 174 buf.append("\\"+Integer.toHexString(((int)b) & 0xFF)); 175 } 176 } 177 178 return buf.toString(); 179 } 180 181 // If a stream thread, then get the request first. Process the 182 // request and reply to client. 183 184 public void run() { 185 186 // Is this a stream or datagram thread? 187 188 if (sock != null || inStream != null) { 189 190 // Label appropriately. 191 192 setName("Stream Request Handler "+clientAddr+":"+port); 193 194 if (sock != null) { 195 // Set the socket to block until there are bytes to read. 196 197 try { 198 sock.setSoTimeout(0); 199 200 } catch (SocketException ex) { 201 202 } 203 204 } 205 206 // get DA Table 207 208 try { 209 daTable = ServerDATable.getServerDATable(); 210 } catch (ServiceLocationException e) { 211 212 // Taken care of in initialziation code. 213 214 } 215 216 // Stream needs to loop through until requests are completed. 217 218 handleStream(); 219 220 if (sock != null) { 221 try { 222 223 sock.close(); 224 sock = null; 225 226 } catch (IOException ex) { 227 228 } 229 } 230 231 } else { 232 233 // Label appropriately. 234 235 setName("Datagram Request Handler "+clientAddr+":"+port); 236 237 byte[] inbuf = packet.getData(); 238 239 // Copy xid for use in hash key. 240 241 byte[] xidBuf = new byte[2]; 242 System.arraycopy(inbuf, SrvLocHeader.XID_OFFSET, xidBuf, 0, 2); 243 244 // If this request is already in progress, drop new request. 245 246 int xid = 0; 247 xid = (int)((char)xidBuf[0] & 0xFF) << 8; 248 xid += (int)((char)xidBuf[1] & 0xFF); 249 String syncTableKey = 250 (new Integer(xid)).toString() + clientAddr.getHostAddress(); 251 boolean there = false; 252 253 synchronized (inProgress) { 254 255 there = (inProgress.get(syncTableKey) != null); 256 257 if (!there) { 258 inProgress.put(syncTableKey, this); 259 260 } 261 } 262 263 // Drop if we are processing it already. 264 265 if (there) { 266 if (config.traceDrop()) { 267 config.writeLog("rh_rqst_in_progress", 268 new Object[] {clientAddr, 269 new Integer(port), 270 interfac}); 271 } 272 return; 273 274 } 275 276 // We can simply cut to the chase and process the datagram 277 // request. 278 279 DataInputStream dis = 280 new DataInputStream(new ByteArrayInputStream(inbuf)); 281 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 282 283 try { 284 285 handleRequest(dis, baos, false); 286 287 byte[] outbuf = baos.toByteArray(); 288 289 // Open a data output stream for the outgoing request. There 290 // is no buffer for reply or it is empty, the request was 291 // multicast and nothing was sent back. 292 293 if (outbuf != null && outbuf.length > 0) { 294 sendDatagramReply(outbuf); 295 296 } 297 298 } catch (IOException ex) { 299 300 // No excuse for an EOF exception here. 301 302 if (config.traceDrop()) { 303 config.writeLog("rh_datagram_ioe", 304 new Object[] {clientAddr, 305 new Integer(port), 306 interfac, 307 ex.getMessage()}); 308 309 } 310 } 311 312 // Remove the lock for this request. We do this just before the 313 // run() method exits and the thread expires to reduce the 314 // window in which a new copy of the request could come in. 315 // We need to be sure that we only remove if it is this 316 // request handler. 317 318 synchronized (inProgress) { 319 RequestHandler rh = 320 (RequestHandler)inProgress.get(syncTableKey); 321 322 if (rh == this) { 323 inProgress.remove(syncTableKey); 324 325 } 326 327 } 328 329 } 330 331 } 332 333 // Handle an incoming stream. 334 335 private void handleStream() { 336 337 try { 338 339 DataInputStream dis = null; 340 DataOutputStream dos = null; 341 342 if (inStream != null) { 343 dis = new DataInputStream(inStream); 344 dos = new DataOutputStream(outStream); 345 } else { 346 // use the socket 347 348 dis = new DataInputStream(sock.getInputStream()); 349 dos = new DataOutputStream(sock.getOutputStream()); 350 } 351 352 // Loop while the client still wants to send something. But we 353 // only read one SLP message at a time on the connection, 354 // returning if it there are no more bytes to read. Note that 355 // we have to use a do/while loop here so that the read hangs 356 // until something shows up. 357 358 do { 359 360 // Handle the new request. 361 362 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 363 364 boolean parseError = handleRequest(dis, baos, true); 365 366 dos.write(baos.toByteArray(), 0, baos.size()); 367 368 // Forward reg or dereg to foreign DAs that need to know 369 // about it. 370 371 if (toForward != null) { 372 373 try { 374 daTable.forwardSAMessage(toForward, clientAddr); 375 toForward = null; 376 377 } catch (ServiceLocationException ex) { 378 config.writeLog("sa_forwarding_exception", 379 new Object[] { 380 new Short(ex.getErrorCode()), 381 Integer.toHexString(toForward.getHeader().xid), 382 ex.getMessage()}); 383 } 384 } 385 386 // If there was a parse error, then break out and close the 387 // stream, because it may have lingering bytes. 388 389 if (parseError && config.traceMsg()) { 390 391 config.writeLog("rh_tcp_error", 392 new Object[] {clientAddr, 393 new Integer(port), 394 interfac}); 395 396 break; 397 398 } 399 400 } while (true); 401 402 } catch (EOFException ex) { 403 404 if (config.traceMsg()) { 405 config.writeLog("rh_socket_closed", 406 new Object[] {clientAddr, 407 new Integer(port), 408 interfac}); 409 } 410 411 412 } catch (IOException ex) { 413 414 // An error occured during input. 415 416 if (config.traceDrop()) { 417 config.writeLog("ioexception_server_stream", 418 new Object[] {clientAddr, 419 new Integer(port), 420 interfac, 421 ex.getMessage()}); 422 } 423 424 } 425 } 426 427 // Send a byte buffer reply through a datagram socket. 428 429 private void sendDatagramReply(byte[] outbuf) { 430 431 DatagramSocket ds = null; 432 433 try { 434 435 // Open the socket. 436 437 ds = new DatagramSocket(); 438 439 // Format the outgoing packet. 440 441 DatagramPacket dpOut = 442 new DatagramPacket(outbuf, outbuf.length, clientAddr, port); 443 444 // Send the reply. 445 446 ds.send(dpOut); 447 448 // Forward reg or dereg to foreign DAs that need to know about it. 449 450 if (toForward != null) { 451 452 try { 453 daTable.forwardSAMessage(toForward, clientAddr); 454 toForward = null; 455 456 } catch (ServiceLocationException ex) { 457 config.writeLog("sle_forward_error", 458 new Object[] { 459 new Integer(ex.getErrorCode()), 460 Integer.toHexString(toForward.getHeader().xid), 461 ex.getMessage()}); 462 } 463 } 464 465 } catch (SocketException ex) { 466 467 // Failure in reply. 468 469 if (config.traceDrop()) { 470 config.writeLog("rh_socket_error", 471 new Object[] {clientAddr, 472 new Integer(port), 473 interfac, 474 ex.getMessage()}); 475 } 476 } catch (IOException ex) { 477 478 // Failure in reply. 479 480 if (config.traceDrop()) { 481 config.writeLog( 482 "rh_ioexception_reply", 483 new Object[] {clientAddr, 484 new Integer(port), 485 interfac, 486 ex.getMessage()}); 487 } 488 489 } finally { 490 491 if (ds != null) { 492 ds.close(); 493 494 } 495 496 } 497 498 } 499 500 // Handle an incoming stream containing an SLP request. 501 502 private boolean 503 handleRequest(DataInputStream dis, 504 ByteArrayOutputStream baos, 505 boolean isTCP) 506 throws IOException { 507 508 boolean parseError = false; 509 510 // Decode the message. 511 512 SrvLocMsg msg = internalize(dis, isTCP); 513 514 // If there was an error converting the request, then don't 515 // process further. 516 517 SrvLocMsg rply = msg; 518 519 if (msg != null) { 520 SrvLocHeader hdr = msg.getHeader(); 521 522 if (hdr.errCode == ServiceLocationException.OK) { 523 524 if (config.traceMsg()) { 525 config.writeLog("rh_rqst_in", 526 new Object[] {Integer.toHexString(hdr.xid), 527 clientAddr, 528 new Integer(port), 529 interfac, 530 msg.getHeader()}); 531 } 532 533 534 // Dispatch the message to the service table. 535 536 rply = dispatch(msg); 537 538 // If no reply, then simply return. 539 540 if (rply == null) { 541 542 if (config.traceMsg()) { 543 config.writeLog("rh_rply_null", 544 new Object[] { 545 Integer.toHexString(hdr.xid), 546 clientAddr, 547 new Integer(port), 548 interfac}); 549 550 } 551 552 return parseError; 553 554 } 555 } else { 556 557 // Drop if multicast. 558 559 if (msg.getHeader().mcast) { 560 rply = null; 561 562 if (config.traceDrop()) { 563 config.writeLog("rh_multi_error", 564 new Object[] { 565 msg.getClass().getName(), 566 Integer.toHexString(hdr.xid), 567 clientAddr, 568 new Integer(port), 569 interfac}); 570 571 572 } 573 } else if (isTCP) { 574 575 // Set the parse error flag so that the stream gets closed. 576 // It's easier than trying to keep track of the number of 577 // bytes read. Otherwise, the remnents of the message 578 // hang around. 579 580 parseError = true; 581 582 } 583 } 584 } 585 586 // Reply to the client if necessary. Note that if the reply is null 587 // here, there was a problem parsing the message in and so formulating 588 // a reply may be impossible (for example, the message may not 589 // be parsable beyond the function code. 590 591 if (rply != null) { 592 SrvLocHeader hdr = rply.getHeader(); 593 ServiceLocationException ex = null; 594 595 // Parse out the message. 596 597 try { 598 hdr.externalize(baos, false, isTCP); 599 } catch (ServiceLocationException sle) { 600 ex = sle; 601 } 602 603 if (config.traceMsg()) { 604 config.writeLog("rh_rply_out", 605 new Object[] {Integer.toHexString(hdr.xid), 606 clientAddr, 607 new Integer(port), 608 interfac, 609 rply.getHeader()}); 610 } 611 612 if (ex != null) { 613 baos.reset(); 614 rply = hdr.makeErrorReply(ex); 615 616 Assert.slpassert(msg != null, 617 "rh_header_class_error", 618 new Object[] {ex.getMessage()}); 619 620 hdr = rply.getHeader(); 621 622 try { 623 hdr.externalize(baos, false, isTCP); 624 625 } catch (ServiceLocationException exx) { 626 627 } 628 } 629 } else if (config.traceMsg()) { 630 631 // Print error message. 632 633 String xidStr = "<null message>"; 634 635 if (msg != null) { 636 SrvLocHeader hdr = msg.getHeader(); 637 xidStr = Integer.toHexString(hdr.xid); 638 639 } 640 641 config.writeLog("rh_rply_null", 642 new Object[] {xidStr, 643 clientAddr, 644 new Integer(port), 645 interfac}); 646 } 647 648 return parseError; 649 } 650 651 /** 652 * Internalize the byte array in the input stream into a SrvLocMsg 653 * subclass. It will be an appropriate subclass for the SA/DA. 654 * 655 * @param dis The input stream containing the packet. 656 * @param viaTCP True if the outgoing stream is via TCP. 657 * @return The right SrvLocMsg subclass appropriate for the SA/DA. 658 * If null is returned, it means that the function code was 659 * not recognized. 660 * If any error occurs during creation, an error request is 661 * returned with the error code set. 662 */ 663 664 private SrvLocMsg 665 internalize(DataInputStream dis, boolean viaTCP) throws IOException { 666 667 int ver = 0, fun = 0; 668 669 Assert.slpassert((dis != null), 670 "rh_null_bais", 671 new Object[0]); 672 673 try { 674 675 // Pull off the version number and function code. 676 677 byte[] b = new byte[2]; 678 679 dis.readFully(b, 0, 2); 680 681 ver = (int) ((char)b[0] & 0XFF); 682 fun = (int) ((char)b[1] & 0XFF); 683 684 } catch (IOException ex) { 685 686 // Print an error message, but only if not EOF. 687 688 if (!(ex instanceof EOFException)) { 689 printInternalizeErrorMessage(ver, fun, ex); 690 691 } 692 693 // Throw the exception, so streams can terminate. 694 695 throw ex; 696 697 } 698 699 SrvLocMsg msg = null; 700 SrvLocHeader hdr = null; 701 702 try { 703 704 hdr = SrvLocHeader.newInstance(ver); 705 706 // Unrecognized version number if header not returned. 707 // We only throw an exception if the version number 708 // is greater than the current default version number. 709 // otherwise, the packet is from an earlier version 710 // of the protocol and should be ignored if we are 711 // not operating in compatibility mode. 712 713 if (hdr == null) { 714 715 if (ver > Defaults.version || 716 (config.isV1Supported() && config.isDA())) { 717 // code problem... 718 throw 719 new ServiceLocationException( 720 ServiceLocationException.VERSION_NOT_SUPPORTED, 721 "rh_version_number_error", 722 new Object[] {new Integer(ver), 723 clientAddr, 724 new Integer(port), 725 interfac}); 726 } else { 727 return null; 728 729 } 730 } 731 732 // If we've come via TCP, clear the packet length so the 733 // eventual reply won't be checked for overflow. 734 735 if (viaTCP) { 736 hdr.setPacketLength(Integer.MAX_VALUE); 737 738 } 739 740 // Parse the header. 741 742 hdr.parseHeader(fun, dis); 743 744 // Parse body. 745 746 if ((msg = hdr.parseMsg(dis)) != null) { 747 748 // Parse options, if any. 749 750 hdr.parseOptions(dis); 751 752 } 753 754 } catch (Exception ex) { 755 756 printInternalizeErrorMessage(ver, fun, ex); 757 758 msg = null; 759 760 // If this is a DAAdvert or an SAAdvert, or there's no header, 761 // return null cause we don't need to return anything or 762 // can't. 763 764 if (fun != SrvLocHeader.DAAdvert && 765 fun != SrvLocHeader.SAAdvert && 766 hdr != null) { 767 768 // Let header create message. 769 770 msg = hdr.makeErrorReply(ex); 771 772 } 773 774 } 775 776 return msg; 777 } 778 779 // Print an error message for errors during internalization. 780 781 private void printInternalizeErrorMessage(int ver, int fun, Exception ex) { 782 783 if (config.traceDrop()) { 784 785 StringWriter sw = new StringWriter(); 786 PrintWriter pw = new PrintWriter(sw); 787 788 ex.printStackTrace(pw); 789 790 short errCode = ServiceLocationException.INTERNAL_SYSTEM_ERROR; 791 792 if (ex instanceof ServiceLocationException) { 793 errCode = ((ServiceLocationException)ex).getErrorCode(); 794 795 } else if (ex instanceof IllegalArgumentException) { 796 errCode = ServiceLocationException.PARSE_ERROR; 797 798 } 799 800 String exMsg = "(" + errCode + "):" + ex.getMessage(); 801 802 config.writeLog("rh_unparse_exception", 803 new Object[] {clientAddr, 804 new Integer(port), 805 interfac, 806 new Integer(ver), 807 new Integer(fun), 808 exMsg, 809 sw.toString()}); 810 } 811 } 812 813 /** 814 * Dispatch the service request object to the service table. 815 * The SA table is used for the following: 816 * 817 * @param rqst Service request object. 818 * @return A SrvLocMsg object to reply with, or null if no reply. 819 */ 820 821 SrvLocMsg dispatch(SrvLocMsg rqst) { 822 823 SrvLocHeader hdr = rqst.getHeader(); 824 boolean mcast = hdr.mcast; 825 826 // Check CDAAdvert and CSAAdvert before we check the previous 827 // responders list, because they don't have any. 828 829 if (rqst instanceof CDAAdvert) { // DA advert... 830 CDAAdvert msg = (CDAAdvert)rqst; 831 832 // For V1, V2 messages know. 833 834 msg.setIsUnsolicited(true); 835 836 // If passive detection is off, ignore it, but only if it wasn't 837 // a signal to stop. 838 839 if (!config.passiveDADetection() && 840 msg.isUnsolicited() && 841 !msg.isGoingDown()) { 842 if (config.traceDrop()) { 843 config.writeLog("rh_passive_drop", 844 new Object[] {msg.URL, 845 hdr.scopes}); 846 847 } 848 849 } else if (msg.isGoingDown() && msg.isUnsolicited() && 850 isLocalHostURL(msg.URL) && config.isDA()) { 851 852 // We've been asked to terminate. 853 854 // Check scopes. 855 856 Vector scopes = (Vector)hdr.scopes.clone(); 857 858 DATable.filterScopes(scopes, 859 config.getSAConfiguredScopes(), true); 860 861 // If all scopes not equal, it isn't a shutdown message for us. 862 863 if (scopes.size() > 0) { 864 daTable.handleAdvertIn(msg); 865 866 } else { 867 868 Vector discoveredScopes = new Vector(); 869 870 try { 871 discoveredScopes = daTable.findScopes(); 872 873 } catch (ServiceLocationException ex) { 874 875 // Ignore, we're going down anyway and it's 876 // just a report. 877 878 } 879 880 // It is a shutdown message for us. 881 882 Vector serverScopes = config.getSAConfiguredScopes(); 883 Vector interfaces = config.getInterfaces(); 884 Vector daAttributes = config.getDAAttributes(); 885 886 if (config.traceAll() || 887 config.traceMsg() || 888 config.traceDrop() || 889 config.traceDATraffic()) { 890 891 config.writeLog("goodby_da", 892 new Object[] {interfaces, 893 serverScopes, 894 discoveredScopes, 895 daAttributes}); 896 } 897 898 899 // We don't reply, which means that the client will 900 // time out. 901 902 System.exit(0); 903 904 } 905 } else { 906 907 // The implementation specific DA table handles this. 908 909 daTable.handleAdvertIn(msg); 910 911 } 912 913 return null; 914 915 } else if (rqst instanceof CSAAdvert) {// SA advert... 916 CSAAdvert msg = (CSAAdvert)rqst; 917 918 // We are only interested in it if we may be going down. 919 920 if ((hdr.xid == 0) && isLocalHostURL(msg.URL) && !config.isDA()) { 921 922 // Check scopes. 923 924 Vector scopes = (Vector)hdr.scopes.clone(); 925 926 DATable.filterScopes(scopes, 927 config.getSAConfiguredScopes(), true); 928 929 // If all scopes not equal, it isn't a shutdown message for us. 930 931 if (scopes.size() <= 0) { 932 933 Vector discoveredScopes = new Vector(); 934 935 try { 936 discoveredScopes = daTable.findScopes(); 937 938 } catch (ServiceLocationException ex) { 939 940 // Ignore, we're going down anyway and it's just a 941 // report. 942 943 } 944 945 // It is a shutdown message for us. 946 947 Vector serverScopes = config.getSAConfiguredScopes(); 948 Vector interfaces = config.getInterfaces(); 949 Vector saAttributes = config.getSAAttributes(); 950 951 if (config.traceAll() || 952 config.traceMsg() || 953 config.traceDrop() || 954 config.traceDATraffic()) { 955 956 config.writeLog("goodby", 957 new Object[] {interfaces, 958 serverScopes, 959 discoveredScopes, 960 saAttributes}); 961 } 962 963 System.exit(0); 964 } 965 } 966 967 // Otherwise, drop it for now. 968 969 if (config.traceDrop()) { 970 config.writeLog("rh_client_sa_advert_drop", 971 new Object[] {Integer.toHexString(hdr.xid), 972 clientAddr, 973 new Integer(port), 974 interfac}); 975 } 976 977 return null; 978 979 } 980 981 if (rqst instanceof SSrvReg) { // registration... 982 983 return dispatchReg((SSrvReg)rqst, 984 serviceTable); 985 986 } else if (rqst instanceof SSrvDereg) { // deregistration... 987 988 return dispatchDereg((SSrvDereg)rqst, 989 serviceTable); 990 991 } 992 993 994 // If we are on the previous responder list, then ignore this 995 // request. 996 997 if (isPreviousResponder(hdr)) { 998 999 if (config.traceDrop()) { 1000 config.writeLog("rh_prev_resp", 1001 new Object[] {Integer.toHexString(hdr.xid), 1002 clientAddr, 1003 new Integer(port), 1004 interfac}); 1005 } 1006 1007 return null; 1008 1009 } 1010 1011 // Now check requests with previous responders. 1012 1013 if (rqst instanceof SSrvTypeMsg) { // service types... 1014 1015 return dispatchSrvType((SSrvTypeMsg)rqst, 1016 serviceTable); 1017 1018 } else if (rqst instanceof SAttrMsg) { // attributes... 1019 1020 return dispatchAttr((SAttrMsg)rqst, 1021 serviceTable); 1022 1023 } else if (rqst instanceof SSrvMsg) { // services... 1024 1025 return dispatchSrv((SSrvMsg)rqst, 1026 serviceTable); 1027 1028 } else { // error... 1029 1030 Assert.slpassert(false, 1031 "rh_rqst_type_err", 1032 new Object[] {rqst}); 1033 1034 } 1035 1036 return null; 1037 1038 } 1039 1040 1041 // Dispatch a service registration. 1042 1043 private SrvLocMsg dispatchReg(SSrvReg rqst, 1044 ServiceTable serviceTable) { 1045 1046 SrvLocHeader hdr = rqst.getHeader(); 1047 1048 // Report error if the message was multicast. 1049 1050 if (hdr.mcast && config.traceDrop()) { 1051 1052 if (config.traceDrop()) { 1053 config.writeLog("rh_no_multi", 1054 new Object[] {"SrvReg", 1055 Integer.toHexString(hdr.xid), 1056 clientAddr, 1057 new Integer(port), 1058 interfac}); 1059 } 1060 1061 return null; 1062 1063 } 1064 1065 // Register the request. 1066 1067 SrvLocMsg rply = serviceTable.register(rqst); 1068 1069 // Forward to foreign DAs if no error. 1070 1071 if (rply != null) { 1072 hdr = rply.getHeader(); 1073 1074 if (hdr.errCode == ServiceLocationException.OK) { 1075 toForward = rqst; 1076 1077 } 1078 } 1079 1080 return rply; 1081 } 1082 1083 // Dispatch a service deregistration. 1084 1085 private SrvLocMsg dispatchDereg(SSrvDereg rqst, 1086 ServiceTable serviceTable) { 1087 1088 SrvLocHeader hdr = rqst.getHeader(); 1089 1090 // Report error if the message was multicast. 1091 1092 if (hdr.mcast && config.traceDrop()) { 1093 1094 if (config.traceDrop()) { 1095 config.writeLog("rh_no_multi", 1096 new Object[] {"SrvDereg", 1097 Integer.toHexString(hdr.xid), 1098 clientAddr, 1099 new Integer(port), 1100 interfac}); 1101 } 1102 1103 return null; 1104 1105 } 1106 1107 // If the message came from the local host, use the SA store. 1108 1109 SrvLocMsg rply = serviceTable.deregister(rqst); 1110 1111 // Forward to foreign DAs if no error. 1112 1113 if (rply != null) { 1114 hdr = rply.getHeader(); 1115 1116 if (hdr.errCode == ServiceLocationException.OK) { 1117 toForward = rqst; 1118 1119 } 1120 } 1121 1122 return rply; 1123 } 1124 1125 // Dispatch a service type message. 1126 1127 private SrvLocMsg dispatchSrvType(SSrvTypeMsg rqst, 1128 ServiceTable serviceTable) { 1129 1130 SrvLocHeader hdr = rqst.getHeader(); 1131 boolean mcast = hdr.mcast; 1132 1133 // Drop if this is a DA and the request was multicast. DAs 1134 // do not respond to multicast, except for DAAdverts. 1135 1136 if (mcast && config.isDA()) { 1137 1138 if (config.traceDrop()) { 1139 config.writeLog("rh_drop_da_multi", 1140 new Object[] {"SrvTypeRqst", 1141 Integer.toHexString(hdr.xid), 1142 clientAddr, 1143 new Integer(port), 1144 interfac}); 1145 } 1146 1147 return null; 1148 1149 } 1150 1151 SrvLocMsg rply = serviceTable.findServiceTypes(rqst); 1152 hdr = rply.getHeader(); 1153 1154 // Filter multicast replies to remove null and error returns. 1155 1156 if (mcast && 1157 ((hdr.errCode != ServiceLocationException.OK) || 1158 (hdr.getNumReplies() == 0))) { 1159 1160 if (config.traceDrop()) { 1161 config.writeLog("rh_multi_error", 1162 new Object[] {"SrvTypeRqst", 1163 Integer.toHexString(hdr.xid), 1164 clientAddr, 1165 new Integer(port), 1166 interfac}); 1167 1168 1169 } 1170 1171 return null; 1172 1173 } 1174 1175 return rply; 1176 } 1177 1178 // Dispatch an attribute request. 1179 1180 private SrvLocMsg dispatchAttr(SAttrMsg rqst, 1181 ServiceTable serviceTable) { 1182 1183 SrvLocHeader hdr = rqst.getHeader(); 1184 boolean mcast = hdr.mcast; 1185 1186 // Drop if this is a DA and the request was multicast. DAs 1187 // do not respond to multicast, except for DAAdverts. 1188 1189 if (mcast && config.isDA()) { 1190 1191 if (config.traceDrop()) { 1192 config.writeLog("rh_drop_da_multi", 1193 new Object[] {"AttrRqst", 1194 Integer.toHexString(hdr.xid), 1195 clientAddr, 1196 new Integer(port), 1197 interfac}); 1198 } 1199 1200 return null; 1201 1202 } 1203 1204 SrvLocMsg rply = serviceTable.findAttributes(rqst); 1205 hdr = rply.getHeader(); 1206 1207 // Filter multicast replies to remove null and error returns. 1208 1209 if (mcast && 1210 ((hdr.errCode != ServiceLocationException.OK) || 1211 (hdr.getNumReplies() == 0))) { 1212 1213 if (config.traceDrop()) { 1214 config.writeLog("rh_multi_error", 1215 new Object[] {"AttrRqst", 1216 Integer.toHexString(hdr.xid), 1217 clientAddr, 1218 new Integer(port), 1219 interfac}); 1220 1221 } 1222 1223 return null; 1224 1225 } 1226 1227 return rply; 1228 } 1229 1230 // Dispatch a service request. 1231 1232 private SrvLocMsg dispatchSrv(SSrvMsg rqst, 1233 ServiceTable serviceTable) { 1234 1235 SrvLocHeader hdr = rqst.getHeader(); 1236 boolean mcast = hdr.mcast; 1237 String serviceType = rqst.serviceType; 1238 SrvLocMsg rply = null; 1239 1240 // We need to special case if this is a request for a DAAdvert 1241 // and we are a DA or an SAAdvert and we are an SA only. 1242 1243 if (serviceType.equals(Defaults.DA_SERVICE_TYPE.toString())) { 1244 1245 // Reply only if a DA. 1246 1247 if (config.isDA()) { 1248 1249 1250 // Return a DAAdvert for this DA. 1251 1252 rply = serviceTable.makeDAAdvert(rqst, 1253 interfac, 1254 config); 1255 1256 hdr = rply.getHeader(); 1257 1258 if ((hdr.errCode != ServiceLocationException.OK) && 1259 config.traceMsg()) { 1260 config.writeLog("rh_advert_error", 1261 new Object[] { new Integer(hdr.errCode), 1262 "DAAdvert", 1263 ""}); 1264 1265 } 1266 } 1267 1268 // If there was an error and the request was multicast, drop it 1269 // by returning null. 1270 1271 if (hdr.errCode != ServiceLocationException.OK && 1272 mcast) { 1273 1274 if (config.traceDrop()) { 1275 1276 config.writeLog("rh_drop_srv", 1277 new Object[] { 1278 "DA SrvRqst", 1279 Integer.toHexString(hdr.xid), 1280 clientAddr, 1281 new Integer(port), 1282 interfac}); 1283 1284 } 1285 1286 return null; 1287 1288 } 1289 1290 return rply; 1291 1292 } else if (serviceType.equals(Defaults.SA_SERVICE_TYPE.toString())) { 1293 1294 // Note that we reply if we are a DA because somebody may want 1295 // SA attributes. 1296 1297 // We report error for unicast SA service request. 1298 1299 if (!mcast) { 1300 1301 if (config.traceDrop()) { 1302 1303 config.writeLog("rh_no_srv_uni", 1304 new Object[] { 1305 "SA SrvRqst", 1306 Integer.toHexString(hdr.xid), 1307 clientAddr, 1308 new Integer(port), 1309 interfac}); 1310 1311 } 1312 1313 return null; 1314 1315 } 1316 1317 // Return a SAAdvert for this SA. 1318 1319 try { 1320 rply = serviceTable.makeSAAdvert(rqst, 1321 interfac, 1322 config); 1323 1324 } catch (ServiceLocationException ex) { 1325 config.writeLog("rh_advert_error", 1326 new Object [] {new Integer(ex.getErrorCode()), 1327 "SAAdvert", 1328 ex.getMessage()}); 1329 1330 } 1331 1332 1333 if (rply == null && config.traceDrop()) { 1334 1335 config.writeLog("rh_drop_srv", 1336 new Object[] {"SA SrvRqst", 1337 Integer.toHexString(hdr.xid), 1338 clientAddr, 1339 new Integer(port), 1340 interfac}); 1341 1342 } 1343 1344 return rply; 1345 1346 } 1347 1348 // Drop if this is a DA and the request was multicast. DAs 1349 // do not respond to multicast, except for DAAdverts. 1350 1351 if (mcast && config.isDA()) { 1352 1353 if (config.traceDrop()) { 1354 config.writeLog("rh_drop_da_multi", 1355 new Object[] {"SrvRqst", 1356 Integer.toHexString(hdr.xid), 1357 clientAddr, 1358 new Integer(port), 1359 interfac}); 1360 } 1361 1362 return null; 1363 1364 } 1365 1366 SrvLocMsg smrply = serviceTable.findServices(rqst); 1367 hdr = smrply.getHeader(); 1368 1369 // Filter multicast replies to remove null and error returns. 1370 1371 if (mcast && 1372 ((hdr.errCode != ServiceLocationException.OK) || 1373 (hdr.getNumReplies() == 0))) { 1374 1375 if (config.traceDrop()) { 1376 config.writeLog("rh_multi_error", 1377 new Object[] {"SrvRqst", 1378 Integer.toHexString(hdr.xid), 1379 clientAddr, 1380 new Integer(port), 1381 interfac}); 1382 1383 } 1384 1385 return null; 1386 1387 } 1388 1389 return smrply; 1390 } 1391 1392 // Return true if the host address matches one of the local interfaces. 1393 1394 boolean isLocalHostURL(ServiceURL url) { 1395 String hostAddr = url.getHost(); 1396 Vector interfaces = config.getInterfaces(); 1397 InetAddress addr = null; 1398 1399 try { 1400 addr = InetAddress.getByName(hostAddr); 1401 1402 } catch (UnknownHostException ex) { 1403 1404 // We simply ignore it. 1405 1406 return false; 1407 1408 } 1409 1410 if (interfaces.contains(addr)) { 1411 return true; 1412 1413 } 1414 1415 return false; 1416 } 1417 1418 /** 1419 * Return whether this was previous responder. Only do so if the 1420 * request was multicast. 1421 * 1422 * @return True if this host was a previous responder. 1423 */ 1424 1425 public boolean isPreviousResponder(SrvLocHeader hdr) { 1426 1427 // If there are no previous responders, then return false, 1428 // because they aren't used for this message. Also for 1429 // messages that are not multicast. 1430 1431 if ((hdr.previousResponders == null) || 1432 (hdr.mcast == false)) { 1433 return false; 1434 1435 } 1436 1437 Vector previousResponders = hdr.previousResponders; 1438 Enumeration e = null; 1439 Vector interfaces = config.getInterfaces(); 1440 1441 // Check for matches against this address. 1442 1443 for (e = previousResponders.elements(); e.hasMoreElements(); ) { 1444 try { 1445 String sHost = ((String)e.nextElement()); 1446 InetAddress iaHost = InetAddress.getByName(sHost); 1447 1448 if (interfaces.contains(iaHost)) { 1449 return true; 1450 } 1451 1452 } catch (UnknownHostException ex) { 1453 1454 } 1455 } 1456 1457 return false; 1458 } 1459 1460 1461 // Initialize the SLPv2 header parser class when we are loaded. 1462 1463 static { 1464 1465 SrvLocHeader.addHeaderClass(Defaults.DEFAULT_SERVER_HEADER_CLASS, 1466 Defaults.version); 1467 1468 } 1469 1470 } 1471