/* * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the * Jitsi community (http://jitsi.org). * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed 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.jitsi.turnserver.stack; import java.io.*; import java.net.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.ice4j.*; import org.ice4j.socket.*; import org.jitsi.turnserver.*; import org.jitsi.turnserver.listeners.*; /** * The class to run a Turn server. * * @author Aakash Garg */ public class TurnServer { private static final Logger Log = LoggerFactory.getLogger(TurnServer.class); private TransportAddress localAddress = null; // requested maximum length of the queue of incoming connections private int backlog = 50; private boolean started = false; private TurnStack turnStack = null; private IceUdpSocketWrapper turnUdpSocket; private final ServerPeerUdpEventHandler peerUdpHandler; private final ServerChannelDataEventHandler channelDataHandler; private IceSocketWrapper turnTcpServerSocket; public TurnServer(TransportAddress localUDPAddress) { this.localAddress = localUDPAddress; this.peerUdpHandler = new ServerPeerUdpEventHandler(); this.channelDataHandler = new ServerChannelDataEventHandler(); turnStack = new TurnStack(this.peerUdpHandler, this.channelDataHandler); Log.debug("Setting turnstack."); this.peerUdpHandler.setTurnStack(turnStack); this.channelDataHandler.setTurnStack(turnStack); Log.info("Server initialized Waiting to be started"); } /** * @param args */ public static void main(String[] args) throws Exception { TransportAddress localAddress = null; if (args.length == 2) { localAddress = new TransportAddress(args[0], Integer.valueOf(args[1]), Transport.UDP); } else { localAddress = new TransportAddress(InetAddress.getLocalHost(), 3478, Transport.UDP); } TurnServer server = new TurnServer(localAddress); server.start(); Thread.sleep(600 * 1000); if (server.isStarted()) { server.shutDown(); } } /** * Function to start the server * * @throws IOException * @throws TurnException */ public void start() throws IOException, TurnException { if (localAddress == null) { throw new RuntimeException("Local address not initialized"); } AllocationRequestListener allocationRequestListner = new AllocationRequestListener(turnStack); ChannelBindRequestListener channelBindRequestListener = new ChannelBindRequestListener(turnStack); ConnectionBindRequestListener connectionBindRequestListener = new ConnectionBindRequestListener(turnStack); ConnectRequestListener connectRequestListener = new ConnectRequestListener(turnStack); CreatePermissionRequestListener createPermissionRequestListener = new CreatePermissionRequestListener(turnStack); RefreshRequestListener refreshRequestListener = new RefreshRequestListener(turnStack); BindingRequestListener bindingRequestListener = new BindingRequestListener(turnStack); SendIndicationListener sendIndListener = new SendIndicationListener(turnStack); sendIndListener.setLocalAddress(localAddress); allocationRequestListner.start(); channelBindRequestListener.start(); connectionBindRequestListener.start(); connectRequestListener.start(); createPermissionRequestListener.start(); refreshRequestListener.start(); bindingRequestListener.start(); sendIndListener.start(); Log.debug("Local address - " + localAddress.getHostAddress() + ":" + localAddress.getPort()); // instance a server socket for TCP ServerSocket tcpServerSocket = new ServerSocket(localAddress.getPort(), backlog, localAddress.getAddress()); // set reuse to allow binding the socket to the same address tcpServerSocket.setReuseAddress(true); Log.debug("Adding a TCP server socket - " + tcpServerSocket.getLocalSocketAddress()); // create ICE socket wrapper for TCP turnTcpServerSocket = new IceTcpServerSocketWrapper(tcpServerSocket, turnStack.getComponent()); // instance a datagram socket for UDP SafeCloseDatagramSocket udpServerSocket = new SafeCloseDatagramSocket(localAddress.getPort(), localAddress.getAddress()); // set reuse to allow binding the datagram socket to the same address udpServerSocket.setReuseAddress(true); Log.debug("Adding a UDP server socket - " + udpServerSocket.getLocalSocketAddress()); // create ICE socket wrapper for UDP turnUdpSocket = new IceUdpSocketWrapper(udpServerSocket); // add the TCP socket to the stack turnStack.addSocket(turnTcpServerSocket); // add the UDP socket to the stack turnStack.addSocket(turnUdpSocket); started = true; Log.info("Server started, listening on " + localAddress.getAddress() + ":" + localAddress.getPort()); } /** * function to stop the server and free resources allocated by it. */ public void shutDown() { Log.info("Stopping server at " + localAddress.getAddress() + ":" + localAddress.getPort()); turnStack.removeSocket(localAddress); turnStack = null; turnUdpSocket.close(); turnUdpSocket = null; this.turnTcpServerSocket.close(); this.turnTcpServerSocket = null; localAddress = null; this.started = false; Log.info("Server stopped"); } public boolean isStarted() { return started; } /** * Sets the incoming connection backlog. * * @param backlog */ public void setBacklog(int backlog) { this.backlog = backlog; } @Override public void finalize() throws Throwable { // to free resources by default if shutdown is not invoked before the // object is destroyed shutDown(); } }