blob: 9e1e8ff5bcee34e9725708594af10214429e50a9 [file] [log] [blame]
/*
* 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.InputStream;
import java.util.Properties;
/** Echo server example
*
* @author Mladen Turk
* @version $Revision$, $Date$
*/
public class Echo {
public static String echoEcho = null;
public static String echoAddr = null;
public static int echoPort = 0;
public static int echoNmax = 0;
public static int echoNrun = 0;
public static long echoPool = 0;
private static Poller echoPoller = null;
private static Acceptor echoAcceptor = null;
private static Object threadLock = new Object();
static {
try {
InputStream is = Echo.class.getResourceAsStream
("/org/apache/tomcat/jni/Echo.properties");
Properties props = new Properties();
props.load(is);
is.close();
echoAddr = props.getProperty("echo.ip", "127.0.0.1");
echoPort = Integer.decode(props.getProperty("echo.port", "23")).intValue();
echoNmax = Integer.decode(props.getProperty("echo.max", "1")).intValue();
}
catch (Throwable t) {
; // Nothing
}
}
/* Acceptor thread. Listens for new connections */
private class Acceptor extends java.lang.Thread {
private long serverSock = 0;
private long inetAddress = 0;
private long pool = 0;
public Acceptor() throws Exception {
try {
pool = Pool.create(Echo.echoPool);
System.out.println("Accepting: " + Echo.echoAddr + ":" +
Echo.echoPort);
inetAddress = Address.info(Echo.echoAddr, Socket.APR_INET,
Echo.echoPort, 0,
pool);
serverSock = Socket.create(Socket.APR_INET, Socket.SOCK_STREAM,
Socket.APR_PROTO_TCP, pool);
long sa = Address.get(Socket.APR_LOCAL, serverSock);
Sockaddr addr = new Sockaddr();
if (Address.fill(addr, sa)) {
System.out.println("Host: " + addr.hostname);
System.out.println("Server: " + addr.servname);
System.out.println("IP: " + Address.getip(sa) +
":" + addr.port);
}
int rc = Socket.bind(serverSock, inetAddress);
if (rc != 0) {
throw(new Exception("Can't create Acceptor: bind: " + Error.strerror(rc)));
}
Socket.listen(serverSock, 5);
}
catch( Exception ex ) {
ex.printStackTrace();
throw(new Exception("Can't create Acceptor"));
}
}
public void run() {
int i = 0;
try {
while (true) {
long clientSock = Socket.accept(serverSock);
System.out.println("Accepted id: " + i);
try {
long sa = Address.get(Socket.APR_REMOTE, clientSock);
Sockaddr raddr = new Sockaddr();
if (Address.fill(raddr, sa)) {
System.out.println("Remote Host: " + Address.getnameinfo(sa, 0));
System.out.println("Remote IP: " + Address.getip(sa) +
":" + raddr.port);
}
sa = Address.get(Socket.APR_LOCAL, clientSock);
Sockaddr laddr = new Sockaddr();
if (Address.fill(laddr, sa)) {
System.out.println("Local Host: " + laddr.hostname);
System.out.println("Local Server: " + Address.getnameinfo(sa, 0));
System.out.println("Local IP: " + Address.getip(sa) +
":" + laddr.port);
}
} catch (Exception e) {
// Ignore
e.printStackTrace();
}
Socket.timeoutSet(clientSock, 10000000);
Worker worker = new Worker(clientSock, i++,
this.getClass().getName());
Echo.incThreads();
worker.start();
}
}
catch( Exception ex ) {
ex.printStackTrace();
}
}
}
/* Poller thread. Listens for new recycled connections */
private class Poller extends java.lang.Thread {
private long serverPollset = 0;
private long pool = 0;
private int nsocks = 0;
public Poller() {
try {
pool = Pool.create(Echo.echoPool);
serverPollset = Poll.create(16, pool, 0, 10000000);
}
catch( Exception ex ) {
ex.printStackTrace();
}
}
public void add(long socket) {
int rv = Poll.add(serverPollset, socket,
Poll.APR_POLLIN);
if (rv == Status.APR_SUCCESS) {
System.out.println("Added worker to pollset");
nsocks++;
}
}
public void remove(long socket) {
int rv = Poll.remove(serverPollset, socket);
if (rv == Status.APR_SUCCESS) {
nsocks--;
System.out.println("Removed worker from pollset");
}
else {
System.out.println("Failed removing worker from pollset");
}
}
public void run() {
while (true) {
try {
if (nsocks < 1) {
java.lang.Thread.sleep(1);
continue;
}
/* Two times size then created pollset */
long [] desc = new long[64];
/* USe 1 second poll timeout */
int rv = Poll.poll(serverPollset, 1000000, desc, false);
if (rv > 0) {
for (int n = 0; n < rv; n++) {
long clientSock = desc[n*2+1];
System.out.println("Poll flags " + desc[n*2]);
remove(clientSock);
Worker worker = new Worker(clientSock, n,
this.getClass().getName());
Echo.incThreads();
worker.start();
}
}
else {
if (Status.APR_STATUS_IS_TIMEUP(-rv))
System.out.println("Timeup");
else {
System.out.println("Error " + (-rv));
}
}
}
/* XXX: JFC quick hack
catch(Error err ) {
if (Status.APR_STATUS_IS_TIMEUP(err.getError())) {
/0 TODO: deal with timeout 0/
}
else {
err.printStackTrace();
break;
}
}
*/
catch( Exception ex ) {
ex.printStackTrace();
break;
}
}
}
}
private class Worker extends java.lang.Thread {
private int workerId = 0;
private long clientSock = 0;
private byte [] wellcomeMsg = null;
public Worker(long clientSocket, int workerId, String from) {
this.clientSock = clientSocket;
this.workerId = workerId;
wellcomeMsg = ("Echo server id: " + this.workerId + " from " +
from + "\r\n").getBytes();
}
public void run() {
boolean doClose = false;
try {
Socket.send(clientSock, wellcomeMsg, 0, wellcomeMsg.length);
/* Do a blocking read byte at a time */
byte [] buf = new byte[1];
while (Socket.recv(clientSock, buf, 0, 1) == 1) {
if (buf[0] == '\n')
break;
else if (buf[0] == '!') {
doClose = true;
break;
}
}
if (doClose) {
try {
byte [] msg = ("Bye from worker: " + workerId + "\r\n").getBytes();
Socket.send(clientSock, msg, 0, msg.length);
} catch(Exception e) { }
Socket.close(clientSock);
}
else {
try {
byte [] msg = ("Recycling worker: " + workerId + "\r\n").getBytes();
Socket.send(clientSock, msg, 0, msg.length);
} catch(Exception e) { }
/* Put the socket to the keep-alive poll */
Echo.echoPoller.add(clientSock);
}
} catch (Exception e) {
Socket.close(clientSock);
e.printStackTrace();
}
Echo.decThreads();
System.out.println("Worker: " + workerId + " finished");
}
}
public Echo()
{
echoPool = Pool.create(0);
try {
echoAcceptor = new Acceptor();
echoAcceptor.start();
echoPoller = new Poller();
echoPoller.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void incThreads() {
synchronized(threadLock) {
echoNrun++;
}
}
public static void decThreads() {
synchronized(threadLock) {
echoNrun--;
}
}
public static void main(String [] args) {
try {
Library.initialize(null);
long [] inf = new long[16];
System.out.println("Info ...");
System.out.println(" Native " + Library.versionString());
System.out.println(" APR " + Library.aprVersionString());
OS.info(inf);
System.out.println("OS Info ...");
System.out.println(" Physical " + inf[0]);
System.out.println(" Avail " + inf[1]);
System.out.println(" Swap " + inf[2]);
System.out.println(" Swap free " + inf[3]);
System.out.println(" Shared " + inf[4]);
System.out.println(" Buffers size " + inf[5]);
System.out.println(" Load " + inf[6]);
System.out.println(" Idle " + inf[7]);
System.out.println(" Kernel " + inf[8]);
System.out.println(" User " + inf[9]);
System.out.println(" Proc creation " + inf[10]);
System.out.println(" Proc kernel " + inf[11]);
System.out.println(" Proc user " + inf[12]);
System.out.println(" Curr working " + inf[13]);
System.out.println(" Peak working " + inf[14]);
System.out.println(" Page faults " + inf[15]);
SSL.initialize(null);
System.out.println("OpenSSL ...");
System.out.println(" version " + SSL.versionString());
System.out.println(" number " + SSL.version());
System.out.println("Starting Native Echo server example on port " +
echoAddr + ":" + echoPort);
Echo echo = new Echo();
} catch (Exception e) {
e.printStackTrace();
}
}
}