net.pms.network.HTTPServer.java Source code

Java tutorial

Introduction

Here is the source code for net.pms.network.HTTPServer.java

Source

/*
 * PS3 Media Server, for streaming any medias to your PS3.
 * Copyright (C) 2008  A.Brochard
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License only.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package net.pms.network;

import net.pms.PMS;
import net.pms.configuration.PmsConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.*;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.Executors;

public class HTTPServer implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(HTTPServer.class);
    private static final PmsConfiguration configuration = PMS.getConfiguration();
    private final int port;
    private String hostname;
    private ServerSocketChannel serverSocketChannel;
    private ServerSocket serverSocket;
    private boolean stop;
    private Thread runnable;
    private InetAddress iafinal;
    private ChannelFactory factory;
    private Channel channel;
    private NetworkInterface networkInterface;
    private ChannelGroup group;

    // XXX not used
    @Deprecated
    public InetAddress getIafinal() {
        return iafinal;
    }

    public NetworkInterface getNetworkInterface() {
        return networkInterface;
    }

    // use getNetworkInterface()
    @Deprecated
    public NetworkInterface getNi() {
        return getNetworkInterface();
    }

    public HTTPServer(int port) {
        this.port = port;
    }

    public String getURL() {
        return "http://" + hostname + ":" + port;
    }

    public String getHost() {
        return hostname;
    }

    public int getPort() {
        return port;
    }

    public boolean start() throws IOException {
        hostname = configuration.getServerHostname();
        InetSocketAddress address;

        if (StringUtils.isNotBlank(hostname)) {
            logger.info("Using forced address " + hostname);
            InetAddress tempIA = InetAddress.getByName(hostname);

            if (tempIA != null && networkInterface != null
                    && networkInterface.equals(NetworkInterface.getByInetAddress(tempIA))) {
                address = new InetSocketAddress(tempIA, port);
            } else {
                address = new InetSocketAddress(hostname, port);
            }
        } else if (isAddressFromInterfaceFound(configuration.getNetworkInterface())) { // XXX sets iafinal and networkInterface
            logger.info("Using address {} found on network interface: {}", iafinal,
                    networkInterface.toString().trim().replace('\n', ' '));
            address = new InetSocketAddress(iafinal, port);
        } else {
            logger.info("Using localhost address");
            address = new InetSocketAddress(port);
        }

        logger.info("Created socket: " + address);

        if (configuration.isHTTPEngineV2()) { // HTTP Engine V2
            group = new DefaultChannelGroup("myServer");
            factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),
                    Executors.newCachedThreadPool());

            ServerBootstrap bootstrap = new ServerBootstrap(factory);
            HttpServerPipelineFactory pipeline = new HttpServerPipelineFactory(group);
            bootstrap.setPipelineFactory(pipeline);
            bootstrap.setOption("child.tcpNoDelay", true);
            bootstrap.setOption("child.keepAlive", true);
            bootstrap.setOption("reuseAddress", true);
            bootstrap.setOption("child.reuseAddress", true);
            bootstrap.setOption("child.sendBufferSize", 65536);
            bootstrap.setOption("child.receiveBufferSize", 65536);
            channel = bootstrap.bind(address);
            group.add(channel);

            if (hostname == null && iafinal != null) {
                hostname = iafinal.getHostAddress();
            } else if (hostname == null) {
                hostname = InetAddress.getLocalHost().getHostAddress();
            }
        } else { // HTTP Engine V1
            serverSocketChannel = ServerSocketChannel.open();

            serverSocket = serverSocketChannel.socket();
            serverSocket.setReuseAddress(true);
            serverSocket.bind(address);

            if (hostname == null && iafinal != null) {
                hostname = iafinal.getHostAddress();
            } else if (hostname == null) {
                hostname = InetAddress.getLocalHost().getHostAddress();
            }

            runnable = new Thread(this, "HTTP Server");
            runnable.setDaemon(false);
            runnable.start();
        }

        return true;
    }

    // XXX this sets iafinal and networkInterface
    private boolean isAddressFromInterfaceFound(String networkInterfaceName) {
        NetworkConfiguration.InterfaceAssociation ia = StringUtils.isNotEmpty(networkInterfaceName)
                ? NetworkConfiguration.getInstance().getAddressForNetworkInterfaceName(networkInterfaceName)
                : null;

        if (ia == null) {
            ia = NetworkConfiguration.getInstance().getDefaultNetworkInterfaceAddress();
        }

        if (ia != null) {
            iafinal = ia.getAddr();
            networkInterface = ia.getIface();
        }

        return ia != null;
    }

    // http://www.ps3mediaserver.org/forum/viewtopic.php?f=6&t=10689&p=48811#p48811
    //
    // avoid a NPE when a) switching HTTP Engine versions and b) restarting the HTTP server
    // by cleaning up based on what's in use (not null) rather than the config state, which
    // might be inconsistent.
    //
    // NOTE: there's little in the way of cleanup to do here as PMS.reset() discards the old
    // server and creates a new one
    public void stop() {
        logger.info("Stopping server on host {} and port {}...", hostname, port);

        if (runnable != null) { // HTTP Engine V1
            runnable.interrupt();
        }

        if (serverSocket != null) { // HTTP Engine V1
            try {
                serverSocket.close();
                serverSocketChannel.close();
            } catch (IOException e) {
                logger.debug("Caught exception", e);
            }
        }

        if (channel != null) { // HTTP Engine V2
            if (group != null) {
                group.close().awaitUninterruptibly();
            }

            if (factory != null) {
                factory.releaseExternalResources();
            }
        }

        NetworkConfiguration.forgetConfiguration();
    }

    // XXX only used by HTTP Engine V1
    @Override
    public void run() {
        logger.info("Starting DLNA Server on host {} and port {}...", hostname, port);

        while (!stop) {
            try {
                Socket socket = serverSocket.accept();
                InetAddress inetAddress = socket.getInetAddress();
                String ip = inetAddress.getHostAddress();
                // basic IP filter: solntcev at gmail dot com
                boolean ignore = false;

                if (configuration.getIpFiltering().allowed(inetAddress)) {
                    logger.trace("Receiving a request from: " + ip);
                } else {
                    ignore = true;
                    socket.close();
                    logger.trace("Ignoring request from: " + ip);
                }

                if (!ignore) {
                    RequestHandler request = new RequestHandler(socket);
                    Thread thread = new Thread(request, "Request Handler");
                    thread.start();
                }
            } catch (ClosedByInterruptException e) {
                stop = true;
            } catch (IOException e) {
                logger.debug("Caught exception", e);
            } finally {
                try {
                    if (stop && serverSocket != null) {
                        serverSocket.close();
                    }

                    if (stop && serverSocketChannel != null) {
                        serverSocketChannel.close();
                    }
                } catch (IOException e) {
                    logger.debug("Caught exception", e);
                }
            }
        }
    }
}