1 /* 2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* Test utilities 25 * 26 */ 27 28 import java.io.*; 29 import java.net.*; 30 import java.nio.*; 31 import java.nio.channels.*; 32 import java.util.Random; 33 34 35 public class TestUtil { 36 37 // Test hosts used by the channels tests - change these when 38 // executing in a different network. 39 public static final String HOST = "javaweb.sfbay.sun.com"; 40 public static final String REFUSING_HOST = "jano1.sfbay.sun.com"; 41 public static final String FAR_HOST = "irejano.ireland.sun.com"; 42 public static final String UNRESOLVABLE_HOST = "blah-blah.blah-blah.blah"; 43 44 private TestUtil() { } 45 46 // Repeatedly try random ports until we bind to one. You might be tempted 47 // to do this: 48 // 49 // ServerSocketChannel ssc = ServerSocketChannel.open(); 50 // ssc.socket().bind(new InetSocketAddress(0)); 51 // SocketAddress sa = ssc.socket().getLocalSocketAddress(); 52 // 53 // but unfortunately it doesn't work on NT 4.0. 54 // 55 // Returns the bound port. 56 // 57 static int bind(ServerSocketChannel ssc) throws IOException { 58 InetAddress lh = InetAddress.getLocalHost(); 59 Random r = new Random(); 60 for (;;) { 61 int p = r.nextInt((1 << 16) - 1024) + 1024; 71 72 // A more convenient form of bind(ServerSocketChannel) that returns a full 73 // socket address. 74 // 75 static InetSocketAddress bindToRandomPort(ServerSocketChannel ssc) 76 throws IOException 77 { 78 int p = bind(ssc); 79 return new InetSocketAddress(InetAddress.getLocalHost(), p); 80 } 81 82 private static String osName = System.getProperty("os.name"); 83 84 static boolean onSolaris() { 85 return osName.startsWith("SunOS"); 86 } 87 88 static boolean onWindows() { 89 return osName.startsWith("Windows"); 90 } 91 } | 1 /* 2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* Test utilities 25 * 26 */ 27 28 import java.io.*; 29 import java.net.*; 30 import java.nio.channels.*; 31 import java.util.ArrayList; 32 import java.util.Date; 33 import java.util.List; 34 import java.util.Random; 35 36 37 public class TestUtil { 38 39 // Test hosts used by the channels tests - change these when 40 // executing in a different network. 41 public static final String UNRESOLVABLE_HOST = "blah-blah.blah-blah.blah"; 42 43 private TestUtil() { } 44 45 // Repeatedly try random ports until we bind to one. You might be tempted 46 // to do this: 47 // 48 // ServerSocketChannel ssc = ServerSocketChannel.open(); 49 // ssc.socket().bind(new InetSocketAddress(0)); 50 // SocketAddress sa = ssc.socket().getLocalSocketAddress(); 51 // 52 // but unfortunately it doesn't work on NT 4.0. 53 // 54 // Returns the bound port. 55 // 56 static int bind(ServerSocketChannel ssc) throws IOException { 57 InetAddress lh = InetAddress.getLocalHost(); 58 Random r = new Random(); 59 for (;;) { 60 int p = r.nextInt((1 << 16) - 1024) + 1024; 70 71 // A more convenient form of bind(ServerSocketChannel) that returns a full 72 // socket address. 73 // 74 static InetSocketAddress bindToRandomPort(ServerSocketChannel ssc) 75 throws IOException 76 { 77 int p = bind(ssc); 78 return new InetSocketAddress(InetAddress.getLocalHost(), p); 79 } 80 81 private static String osName = System.getProperty("os.name"); 82 83 static boolean onSolaris() { 84 return osName.startsWith("SunOS"); 85 } 86 87 static boolean onWindows() { 88 return osName.startsWith("Windows"); 89 } 90 91 /** 92 * An abstract server identifies a server which listens on a port on on a 93 * given machine. 94 */ 95 static abstract class AbstractServer { 96 97 private AbstractServer() { 98 } 99 100 public abstract int getPort(); 101 102 public abstract InetAddress getAddress(); 103 } 104 105 /** 106 * A downgraded type of AbstractServer which will refuse connections. Note: 107 * use it once and throw it away - this implementation opens an anonymous 108 * socket and closes it, returning the address of the closed socket. If 109 * other servers are started afterwards, the address/port might get reused 110 * and become connectable again - so it's not a good idea to assume that 111 * connections using this address/port will always be refused. Connections 112 * will be refused as long as the address/port of the refusing server has 113 * not been reused. 114 */ 115 static class RefusingServer extends AbstractServer { 116 117 final InetAddress address; 118 final int port; 119 120 private RefusingServer(InetAddress address, int port) { 121 this.address = address; 122 this.port = port; 123 } 124 125 @Override 126 public int getPort() { 127 return port; 128 } 129 130 @Override 131 public InetAddress getAddress() { 132 return address; 133 } 134 135 public static RefusingServer startNewServer() throws IOException { 136 ServerSocket socket = new ServerSocket(0, 100, 137 InetAddress.getLocalHost()); 138 RefusingServer server = new RefusingServer(socket.getInetAddress(), 139 socket.getLocalPort()); 140 socket.close(); 141 return server; 142 } 143 } 144 145 /** 146 * An abstract class for implementing small TCP servers for the nio tests 147 * purposes. Disclaimer: This is a naive implementation that uses the old 148 * networking APIs (not those from {@code java.nio.*}) and shamelessly 149 * extends/creates Threads instead of using an executor service. 150 */ 151 static abstract class AbstractTcpServer extends AbstractServer 152 implements Runnable, Closeable { 153 154 protected final long linger; // #of ms to wait before responding 155 private Thread acceptThread; // thread waiting for accept 156 // list of opened connections that should be closed on close. 157 private List<TcpConnectionThread> connections = new ArrayList<>(); 158 private ServerSocket serverSocket; // the server socket 159 private boolean started = false; // whether the server is started 160 Throwable error = null; 161 162 /** 163 * Creates a new abstract TCP server. 164 * 165 * @param linger the amount of time the server should wait before 166 * responding to requests. 167 */ 168 protected AbstractTcpServer(long linger) { 169 this.linger = linger; 170 } 171 172 /** 173 * The local port to which the server is bound. 174 * 175 * @return The local port to which the server is bound. 176 * @exception IllegalStateException is thrown if the server is not 177 * started. 178 */ 179 @Override 180 public final synchronized int getPort() { 181 if (!started) { 182 throw new IllegalStateException("Not started"); 183 } 184 return serverSocket.getLocalPort(); 185 } 186 187 /** 188 * The local address to which the server is bound. 189 * 190 * @return The local address to which the server is bound. 191 * @exception IllegalStateException is thrown if the server is not 192 * started. 193 */ 194 @Override 195 public final synchronized InetAddress getAddress() { 196 if (!started) { 197 throw new IllegalStateException("Not started"); 198 } 199 return serverSocket.getInetAddress(); 200 } 201 202 /** 203 * Tells whether the server is started. 204 * 205 * @return true if the server is started. 206 */ 207 public final synchronized boolean isStarted() { 208 return started; 209 } 210 211 /** 212 * Creates a new server socket. 213 * 214 * @param port local port to bind to. 215 * @param backlog requested maximum length of the queue of incoming 216 * connections. 217 * @param address local address to bind to. 218 * @return a new bound server socket ready to accept connections. 219 * @throws IOException if the socket cannot be created or bound. 220 */ 221 protected ServerSocket newServerSocket(int port, int backlog, 222 InetAddress address) 223 throws IOException { 224 return new ServerSocket(port, backlog, address); 225 } 226 227 /** 228 * Starts listening for connections. 229 * 230 * @throws IOException if the server socket cannot be created or bound. 231 */ 232 public final synchronized void start() throws IOException { 233 if (started) { 234 return; 235 } 236 final ServerSocket socket = 237 newServerSocket(0, 100, InetAddress.getLocalHost()); 238 serverSocket = socket; 239 acceptThread = new Thread(this); 240 acceptThread.setDaemon(true); 241 acceptThread.start(); 242 started = true; 243 } 244 245 /** 246 * Calls {@code Thread.sleep(linger);} 247 */ 248 protected final void lingerIfRequired() { 249 if (linger > 0) { 250 try { 251 Thread.sleep(linger); 252 } catch (InterruptedException x) { 253 Thread.interrupted(); 254 final ServerSocket socket = serverSocket(); 255 if (socket != null && !socket.isClosed()) { 256 System.err.println("Thread interrupted..."); 257 } 258 } 259 } 260 } 261 262 final synchronized ServerSocket serverSocket() { 263 return this.serverSocket; 264 } 265 266 /** 267 * The main accept loop. 268 */ 269 @Override 270 public final void run() { 271 final ServerSocket sSocket = serverSocket(); 272 try { 273 Socket s; 274 while (isStarted() && !Thread.interrupted() 275 && (s = sSocket.accept()) != null) { 276 lingerIfRequired(); 277 listen(s); 278 } 279 } catch (Exception x) { 280 error = x; 281 } finally { 282 synchronized (this) { 283 if (!sSocket.isClosed()) { 284 try { 285 sSocket.close(); 286 } catch (IOException x) { 287 System.err.println("Failed to close server socket"); 288 } 289 } 290 if (started && this.serverSocket == sSocket) { 291 started = false; 292 this.serverSocket = null; 293 this.acceptThread = null; 294 } 295 } 296 } 297 } 298 299 /** 300 * Represents a connection accepted by the server. 301 */ 302 protected abstract class TcpConnectionThread extends Thread { 303 304 protected final Socket socket; 305 306 protected TcpConnectionThread(Socket socket) { 307 this.socket = socket; 308 this.setDaemon(true); 309 } 310 311 public void close() throws IOException { 312 socket.close(); 313 interrupt(); 314 } 315 } 316 317 /** 318 * Creates a new TcpConnnectionThread to handle the connection through 319 * an accepted socket. 320 * 321 * @param s the socket returned by {@code serverSocket.accept()}. 322 * @return a new TcpConnnectionThread to handle the connection through 323 * an accepted socket. 324 */ 325 protected abstract TcpConnectionThread createConnection(Socket s); 326 327 /** 328 * Creates and starts a new TcpConnectionThread to handle the accepted 329 * socket. 330 * 331 * @param s the socket returned by {@code serverSocket.accept()}. 332 */ 333 private synchronized void listen(Socket s) { 334 TcpConnectionThread c = createConnection(s); 335 c.start(); 336 addConnection(c); 337 } 338 339 /** 340 * Add the connection to the list of accepted connections. 341 * 342 * @param connection an accepted connection. 343 */ 344 protected synchronized void addConnection( 345 TcpConnectionThread connection) { 346 connections.add(connection); 347 } 348 349 /** 350 * Remove the connection from the list of accepted connections. 351 * 352 * @param connection an accepted connection. 353 */ 354 protected synchronized void removeConnection( 355 TcpConnectionThread connection) { 356 connections.remove(connection); 357 } 358 359 /** 360 * Close the server socket and all the connections present in the list 361 * of accepted connections. 362 * 363 * @throws IOException 364 */ 365 @Override 366 public synchronized void close() throws IOException { 367 if (serverSocket != null && !serverSocket.isClosed()) { 368 serverSocket.close(); 369 } 370 if (acceptThread != null) { 371 acceptThread.interrupt(); 372 } 373 int failed = 0; 374 for (TcpConnectionThread c : connections) { 375 try { 376 c.close(); 377 } catch (IOException x) { 378 // no matter - we're closing. 379 failed++; 380 } 381 } 382 connections.clear(); 383 if (failed > 0) { 384 throw new IOException("Failed to close some connections"); 385 } 386 } 387 } 388 389 /** 390 * A small TCP Server that emulates the echo service for tests purposes. See 391 * http://en.wikipedia.org/wiki/Echo_Protocol This server uses an anonymous 392 * port - NOT the standard port 7. We don't guarantee that its behavior 393 * exactly matches the RFC - the only purpose of this server is to have 394 * something that responds to nio tests... 395 */ 396 static final class EchoServer extends AbstractTcpServer { 397 398 public EchoServer() { 399 this(0L); 400 } 401 402 public EchoServer(long linger) { 403 super(linger); 404 } 405 406 @Override 407 protected TcpConnectionThread createConnection(Socket s) { 408 return new EchoConnection(s); 409 } 410 411 private final class EchoConnection extends TcpConnectionThread { 412 413 public EchoConnection(Socket socket) { 414 super(socket); 415 } 416 417 @Override 418 public void run() { 419 try { 420 final InputStream is = socket.getInputStream(); 421 final OutputStream out = socket.getOutputStream(); 422 byte[] b = new byte[255]; 423 int n; 424 while ((n = is.read(b)) > 0) { 425 lingerIfRequired(); 426 out.write(b, 0, n); 427 } 428 } catch (IOException io) { 429 // fall through to finally 430 } finally { 431 if (!socket.isClosed()) { 432 try { 433 socket.close(); 434 } catch (IOException x) { 435 System.err.println( 436 "Failed to close echo connection socket"); 437 } 438 } 439 removeConnection(this); 440 } 441 } 442 } 443 444 public static EchoServer startNewServer() throws IOException { 445 return startNewServer(0); 446 } 447 448 public static EchoServer startNewServer(long linger) throws IOException { 449 final EchoServer echoServer = new EchoServer(linger); 450 echoServer.start(); 451 return echoServer; 452 } 453 } 454 455 /** 456 * A small TCP server that emulates the Day & Time service for tests 457 * purposes. See http://en.wikipedia.org/wiki/Daytime_Protocol This server 458 * uses an anonymous port - NOT the standard port 13. We don't guarantee 459 * that its behavior exactly matches the RFC - the only purpose of this 460 * server is to have something that responds to nio tests... 461 */ 462 static final class DayTimeServer extends AbstractTcpServer { 463 464 public DayTimeServer() { 465 this(0L); 466 } 467 468 public DayTimeServer(long linger) { 469 super(linger); 470 } 471 472 @Override 473 protected TcpConnectionThread createConnection(Socket s) { 474 return new DayTimeServerConnection(s); 475 } 476 477 @Override 478 protected void addConnection(TcpConnectionThread connection) { 479 // do nothing - the connection just write the date and terminates. 480 } 481 482 @Override 483 protected void removeConnection(TcpConnectionThread connection) { 484 // do nothing - we're not adding connections to the list... 485 } 486 487 private final class DayTimeServerConnection extends TcpConnectionThread { 488 489 public DayTimeServerConnection(Socket socket) { 490 super(socket); 491 } 492 493 @Override 494 public void run() { 495 try { 496 final OutputStream out = socket.getOutputStream(); 497 lingerIfRequired(); 498 out.write(new Date(System.currentTimeMillis()) 499 .toString().getBytes("US-ASCII")); 500 out.flush(); 501 } catch (IOException io) { 502 // fall through to finally 503 } finally { 504 if (!socket.isClosed()) { 505 try { 506 socket.close(); 507 } catch (IOException x) { 508 System.err.println( 509 "Failed to close echo connection socket"); 510 } 511 } 512 } 513 } 514 } 515 516 public static DayTimeServer startNewServer() 517 throws IOException { 518 return startNewServer(0); 519 } 520 521 public static DayTimeServer startNewServer(long linger) 522 throws IOException { 523 final DayTimeServer daytimeServer = new DayTimeServer(linger); 524 daytimeServer.start(); 525 return daytimeServer; 526 } 527 } 528 529 /** 530 * An abstract class for implementing small UDP Servers for the nio tests 531 * purposes. Disclaimer: This is a naive implementation that uses the old 532 * networking APIs (not those from {@code java.nio.*}) and shamelessly 533 * extends/creates Threads instead of using an executor service. 534 */ 535 static abstract class AbstractUdpServer extends AbstractServer 536 implements Runnable, Closeable { 537 538 protected final long linger; // #of ms to wait before responding 539 private Thread acceptThread; // thread waiting for packets 540 private DatagramSocket serverSocket; // the server socket 541 private boolean started = false; // whether the server is started 542 Throwable error = null; 543 544 /** 545 * Creates a new abstract UDP server. 546 * 547 * @param linger the amount of time the server should wait before 548 * responding to requests. 549 */ 550 protected AbstractUdpServer(long linger) { 551 this.linger = linger; 552 } 553 554 /** 555 * The local port to which the server is bound. 556 * 557 * @return The local port to which the server is bound. 558 * @exception IllegalStateException is thrown if the server is not 559 * started. 560 */ 561 @Override 562 public final synchronized int getPort() { 563 if (!started) { 564 throw new IllegalStateException("Not started"); 565 } 566 return serverSocket.getLocalPort(); 567 } 568 569 /** 570 * The local address to which the server is bound. 571 * 572 * @return The local address to which the server is bound. 573 * @exception IllegalStateException is thrown if the server is not 574 * started. 575 */ 576 @Override 577 public final synchronized InetAddress getAddress() { 578 if (!started) { 579 throw new IllegalStateException("Not started"); 580 } 581 return serverSocket.getLocalAddress(); 582 } 583 584 /** 585 * Tells whether the server is started. 586 * 587 * @return true if the server is started. 588 */ 589 public final synchronized boolean isStarted() { 590 return started; 591 } 592 593 /** 594 * Creates a new datagram socket. 595 * 596 * @param port local port to bind to. 597 * @param address local address to bind to. 598 * @return a new bound server socket ready to listen for packets. 599 * @throws IOException if the socket cannot be created or bound. 600 */ 601 protected DatagramSocket newDatagramSocket(int port, 602 InetAddress address) 603 throws IOException { 604 return new DatagramSocket(port, address); 605 } 606 607 /** 608 * Starts listening for connections. 609 * 610 * @throws IOException if the server socket cannot be created or bound. 611 */ 612 public final synchronized void start() throws IOException { 613 if (started) { 614 return; 615 } 616 final DatagramSocket socket = 617 newDatagramSocket(0, InetAddress.getLocalHost()); 618 serverSocket = socket; 619 acceptThread = new Thread(this); 620 acceptThread.setDaemon(true); 621 acceptThread.start(); 622 started = true; 623 } 624 625 /** 626 * Calls {@code Thread.sleep(linger);} 627 */ 628 protected final void lingerIfRequired() { 629 if (linger > 0) { 630 try { 631 Thread.sleep(linger); 632 } catch (InterruptedException x) { 633 Thread.interrupted(); 634 final DatagramSocket socket = serverSocket(); 635 if (socket != null && !socket.isClosed()) { 636 System.err.println("Thread interrupted..."); 637 } 638 } 639 } 640 } 641 642 final synchronized DatagramSocket serverSocket() { 643 return this.serverSocket; 644 } 645 646 final synchronized boolean send(DatagramSocket socket, 647 DatagramPacket response) throws IOException { 648 if (!socket.isClosed()) { 649 socket.send(response); 650 return true; 651 } else { 652 return false; 653 } 654 } 655 656 /** 657 * The main receive loop. 658 */ 659 @Override 660 public final void run() { 661 final DatagramSocket sSocket = serverSocket(); 662 try { 663 final int size = Math.max(1024, sSocket.getReceiveBufferSize()); 664 if (size > sSocket.getReceiveBufferSize()) { 665 sSocket.setReceiveBufferSize(size); 666 } 667 while (isStarted() && !Thread.interrupted() && !sSocket.isClosed()) { 668 final byte[] buf = new byte[size]; 669 final DatagramPacket packet = 670 new DatagramPacket(buf, buf.length); 671 lingerIfRequired(); 672 sSocket.receive(packet); 673 //System.out.println("Received packet from: " 674 // + packet.getAddress()+":"+packet.getPort()); 675 handle(sSocket, packet); 676 } 677 } catch (Exception x) { 678 error = x; 679 } finally { 680 synchronized (this) { 681 if (!sSocket.isClosed()) { 682 sSocket.close(); 683 } 684 if (started && this.serverSocket == sSocket) { 685 started = false; 686 this.serverSocket = null; 687 this.acceptThread = null; 688 } 689 } 690 } 691 } 692 693 /** 694 * Represents an UDP request received by the server. 695 */ 696 protected abstract class UdpRequestThread extends Thread { 697 698 protected final DatagramPacket request; 699 protected final DatagramSocket socket; 700 701 protected UdpRequestThread(DatagramSocket socket, DatagramPacket request) { 702 this.socket = socket; 703 this.request = request; 704 this.setDaemon(true); 705 } 706 } 707 708 /** 709 * Creates a new UdpRequestThread to handle a DatagramPacket received 710 * through a DatagramSocket. 711 * 712 * @param socket the socket through which the request was received. 713 * @param request the datagram packet received through the socket. 714 * @return a new UdpRequestThread to handle the request received through 715 * a DatagramSocket. 716 */ 717 protected abstract UdpRequestThread createConnection(DatagramSocket socket, 718 DatagramPacket request); 719 720 /** 721 * Creates and starts a new UdpRequestThread to handle the received 722 * datagram packet. 723 * 724 * @param socket the socket through which the request was received. 725 * @param request the datagram packet received through the socket. 726 */ 727 private synchronized void handle(DatagramSocket socket, 728 DatagramPacket request) { 729 UdpRequestThread c = createConnection(socket, request); 730 // c can be null if the request requires no response. 731 if (c != null) { 732 c.start(); 733 } 734 } 735 736 /** 737 * Close the server socket. 738 * 739 * @throws IOException 740 */ 741 @Override 742 public synchronized void close() throws IOException { 743 if (serverSocket != null && !serverSocket.isClosed()) { 744 serverSocket.close(); 745 } 746 if (acceptThread != null) { 747 acceptThread.interrupt(); 748 } 749 } 750 } 751 752 /** 753 * A small UDP Server that emulates the discard service for tests purposes. 754 * See http://en.wikipedia.org/wiki/Discard_Protocol This server uses an 755 * anonymous port - NOT the standard port 9. We don't guarantee that its 756 * behavior exactly matches the RFC - the only purpose of this server is to 757 * have something that responds to nio tests... 758 */ 759 static final class UdpDiscardServer extends AbstractUdpServer { 760 761 public UdpDiscardServer() { 762 this(0L); 763 } 764 765 public UdpDiscardServer(long linger) { 766 super(linger); 767 } 768 769 @Override 770 protected UdpRequestThread createConnection(DatagramSocket socket, 771 DatagramPacket request) { 772 // no response required 773 return null; 774 } 775 776 public static UdpDiscardServer startNewServer() throws IOException { 777 return startNewServer(0); 778 } 779 780 public static UdpDiscardServer startNewServer(long linger) throws IOException { 781 final UdpDiscardServer discardServer = new UdpDiscardServer(linger); 782 discardServer.start(); 783 return discardServer; 784 } 785 } 786 787 /** 788 * A small UDP Server that emulates the echo service for tests purposes. See 789 * http://en.wikipedia.org/wiki/Echo_Protocol This server uses an anonymous 790 * port - NOT the standard port 7. We don't guarantee that its behavior 791 * exactly matches the RFC - the only purpose of this server is to have 792 * something that responds to nio tests... 793 */ 794 static final class UdpEchoServer extends AbstractUdpServer { 795 796 public UdpEchoServer() { 797 this(0L); 798 } 799 800 public UdpEchoServer(long linger) { 801 super(linger); 802 } 803 804 @Override 805 protected UdpEchoRequest createConnection(DatagramSocket socket, 806 DatagramPacket request) { 807 return new UdpEchoRequest(socket, request); 808 } 809 810 private final class UdpEchoRequest extends UdpRequestThread { 811 812 public UdpEchoRequest(DatagramSocket socket, DatagramPacket request) { 813 super(socket, request); 814 } 815 816 @Override 817 public void run() { 818 try { 819 lingerIfRequired(); 820 final DatagramPacket response = 821 new DatagramPacket(request.getData(), 822 request.getOffset(), request.getLength(), 823 request.getAddress(), request.getPort()); 824 send(socket, response); 825 } catch (IOException io) { 826 System.err.println("Failed to send response: " + io); 827 io.printStackTrace(System.err); 828 } 829 } 830 } 831 832 public static UdpEchoServer startNewServer() throws IOException { 833 return startNewServer(0); 834 } 835 836 public static UdpEchoServer startNewServer(long linger) throws IOException { 837 final UdpEchoServer echoServer = new UdpEchoServer(linger); 838 echoServer.start(); 839 return echoServer; 840 } 841 } 842 843 /** 844 * A small UDP server that emulates the Day & Time service for tests 845 * purposes. See http://en.wikipedia.org/wiki/Daytime_Protocol This server 846 * uses an anonymous port - NOT the standard port 13. We don't guarantee 847 * that its behavior exactly matches the RFC - the only purpose of this 848 * server is to have something that responds to nio tests... 849 */ 850 static final class UdpDayTimeServer extends AbstractUdpServer { 851 852 public UdpDayTimeServer() { 853 this(0L); 854 } 855 856 public UdpDayTimeServer(long linger) { 857 super(linger); 858 } 859 860 @Override 861 protected UdpDayTimeRequestThread createConnection(DatagramSocket socket, 862 DatagramPacket request) { 863 return new UdpDayTimeRequestThread(socket, request); 864 } 865 866 private final class UdpDayTimeRequestThread extends UdpRequestThread { 867 868 public UdpDayTimeRequestThread(DatagramSocket socket, 869 DatagramPacket request) { 870 super(socket, request); 871 } 872 873 @Override 874 public void run() { 875 try { 876 lingerIfRequired(); 877 final byte[] data = new Date(System.currentTimeMillis()) 878 .toString().getBytes("US-ASCII"); 879 final DatagramPacket response = 880 new DatagramPacket(data, 0, data.length, 881 request.getAddress(), request.getPort()); 882 send(socket, response); 883 } catch (IOException io) { 884 System.err.println("Failed to send response: " + io); 885 io.printStackTrace(System.err); 886 } 887 } 888 } 889 890 public static UdpDayTimeServer startNewServer() throws IOException { 891 return startNewServer(0); 892 } 893 894 public static UdpDayTimeServer startNewServer(long linger) 895 throws IOException { 896 final UdpDayTimeServer echoServer = new UdpDayTimeServer(linger); 897 echoServer.start(); 898 return echoServer; 899 } 900 } 901 } |