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