/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.jni;
import java.io.OutputStream;
import java.util.concurrent.CountDownLatch;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Tests for server-side sockets.
*/
public class TestSocketServer extends AbstractJniTest {
private static final String HOST = "localhost";
private int port = 0;
private long serverSocket = 0;
private long clientSocket = 0;
@Before
public void init() throws Exception {
long serverPool = Pool.create(0);
long inetAddress = Address.info(HOST, Socket.APR_INET,
0, 0, serverPool);
serverSocket = Socket.create(Socket.APR_INET, Socket.SOCK_STREAM,
Socket.APR_PROTO_TCP, serverPool);
if (OS.IS_UNIX) {
Socket.optSet(serverSocket, Socket.APR_SO_REUSEADDR, 1);
}
int rc = Socket.bind(serverSocket, inetAddress);
Assert.assertEquals("Can't bind: " + Error.strerror(rc), 0, rc);
Socket.listen(serverSocket, 5);
if (!OS.IS_UNIX) {
Socket.optSet(serverSocket, Socket.APR_SO_REUSEADDR, 1);
}
long localAddress = Address.get(Socket.APR_LOCAL, serverSocket);
port = Address.getInfo(localAddress).port;
}
@After
public void destroy() {
if (clientSocket != 0) {
Socket.close(clientSocket);
Socket.destroy(clientSocket);
}
if (serverSocket != 0) {
Socket.close(serverSocket);
Socket.destroy(serverSocket);
}
}
@Test
public void testPort() {
Assert.assertTrue(port > 0);
}
@Test
public void testBlockingReadFromClientWithTimeout() throws Exception {
/* Start the client that connects to the server */
Client client = new Client(port);
client.start();
/* Accept the client connection */
clientSocket = Socket.accept(serverSocket);
/* Configure a 1s timeout for reading from client */
Socket.timeoutSet(clientSocket, 1000000);
long timeout = Socket.timeoutGet(clientSocket);
Assert.assertEquals("Socket.timeoutGet clientSocket failed", 1000000, timeout);
byte [] buf = new byte[1];
long start = System.nanoTime();
while (Socket.recv(clientSocket, buf, 0, 1) == 1) {
}
long wait = System.nanoTime() - start;
Assert.assertFalse("Socket.timeoutSet failed (<1s) [" + wait + "]", wait < 1000000000);
Assert.assertFalse("Socket.timeoutSet failed (>2s) [" + wait + "]", wait > 2000000000);
client.countDown();
client.join();
}
@Test
public void testNonBlockingReadFromClient() throws Exception {
/* Start the client that connects to the server */
Client client = new Client(port);
client.start();
/* Accept the client connection */
clientSocket = Socket.accept(serverSocket);
/* Configure the connection for non-blocking */
Socket.optSet(clientSocket, Socket.APR_SO_NONBLOCK, 1);
int val = Socket.optGet(clientSocket, Socket.APR_SO_NONBLOCK);
Assert.assertEquals("Socket.optGet clientSocket failed", 1, val);
byte [] buf = new byte[1];
long start = System.nanoTime();
while (Socket.recv(clientSocket, buf, 0, 1) == 1) {
}
long wait = System.nanoTime() - start;
Assert.assertFalse("non_blocking client Socket.APR_SO_NONBLOCK failed (>1ms)",
wait > 1000000);
client.countDown();
client.join();
}
@Test
public void testNonBlockingReadThenBlockingReadFromClient() throws Exception {
/* Start the client that connects to the server */
Client client = new Client(port);
client.start();
/* Accept the client connection */
clientSocket = Socket.accept(serverSocket);
/* Configure the connection for non-blocking */
Socket.optSet(clientSocket, Socket.APR_SO_NONBLOCK, 1);
byte [] buf = new byte[1];
long start = System.nanoTime();
while (Socket.recv(clientSocket, buf, 0, 1) == 1) {
}
long wait = System.nanoTime() - start;
Assert.assertFalse("non_blocking client Socket.APR_SO_NONBLOCK failed (>1ms)",
wait > 1000000);
/* Configure for blocking */
Socket.optSet(clientSocket, Socket.APR_SO_NONBLOCK, 0);
Socket.timeoutSet(clientSocket, 2000);
start = System.nanoTime();
while (Socket.recv(clientSocket, buf, 0, 1) == 1) {
}
wait = System.nanoTime() - start;
Assert.assertFalse("non_blocking client Socket.APR_SO_NONBLOCK false failed",
wait < 1000000);
client.countDown();
client.join();
}
@Test
public void testNonBlockingAcceptWithNoClient() throws Exception {
Socket.optSet(serverSocket, Socket.APR_SO_NONBLOCK, 1);
int val = Socket.optGet(serverSocket, Socket.APR_SO_NONBLOCK);
Assert.assertEquals("Socket.optGet serverSocket failed", 1, val);
long start = System.nanoTime();
boolean ok = false;
try {
Socket.accept(serverSocket);
} catch (Exception ex) {
ok = true;
}
long wait = System.nanoTime() - start;
Assert.assertTrue("Timeout failed", ok);
Assert.assertFalse("non_blocking accept Socket.APR_SO_NONBLOCK failed ([" + wait + "]>1ms)",
wait > 1000000);
}
/**
* Simple client that connects, sends a single byte then closes the
* connection.
*/
private static class Client extends java.lang.Thread {
private final int port;
private final CountDownLatch complete = new CountDownLatch(1);
public Client(int port) throws Exception {
this.port = port;
}
public void countDown() {
complete.countDown();
}
@Override
public void run() {
try (java.net.Socket sock = new java.net.Socket(TestSocketServer.HOST, port)) {
OutputStream os = sock.getOutputStream();
os.write('A');
os.flush();
complete.await();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}