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