001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *  
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *  
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License. 
018 *  
019 */
020package org.apache.directory.server.ntp;
021
022
023import java.io.IOException;
024
025import org.apache.directory.server.ntp.protocol.NtpProtocolCodecFactory;
026import org.apache.directory.server.ntp.protocol.NtpProtocolHandler;
027import org.apache.directory.server.protocol.shared.AbstractProtocolService;
028import org.apache.directory.server.protocol.shared.transport.Transport;
029import org.apache.directory.server.protocol.shared.transport.UdpTransport;
030import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
031import org.apache.mina.core.service.IoAcceptor;
032import org.apache.mina.core.service.IoHandler;
033import org.apache.mina.filter.codec.ProtocolCodecFilter;
034import org.apache.mina.transport.socket.DatagramAcceptor;
035import org.apache.mina.transport.socket.DatagramSessionConfig;
036import org.apache.mina.transport.socket.SocketAcceptor;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * Contains the configuration parameters for the NTP protocol provider.
043 *
044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045 */
046public class NtpServer extends AbstractProtocolService
047{
048    /** logger for this class */
049    private static final Logger LOG = LoggerFactory.getLogger( NtpServer.class );
050
051    /**
052     * The default IP port.
053     */
054    private static final int IP_PORT_DEFAULT = 123;
055
056    /** The default service pid. */
057    private static final String SERVICE_PID_DEFAULT = "org.apache.directory.server.ntp";
058
059    /** The default service name. */
060    private static final String SERVICE_NAME_DEFAULT = "ApacheDS NTP Service";
061
062
063    /**
064     * Creates a new instance of NtpConfiguration.
065     */
066    public NtpServer()
067    {
068        super.setServiceId( SERVICE_PID_DEFAULT );
069        super.setServiceName( SERVICE_NAME_DEFAULT );
070    }
071
072
073    /**
074     * Start the NTPServer. We initialize the Datagram and Socket, if necessary.
075     * 
076     * Note that we don't have any filter in the chain, everything is done
077     * in the handler.
078     * @throws IOException if there are issues binding
079     */
080    public void start() throws IOException
081    {
082        IoHandler ntpProtocolHandler = new NtpProtocolHandler();
083
084        // Create the chain for the NTP server
085        DefaultIoFilterChainBuilder ntpChain = new DefaultIoFilterChainBuilder();
086        ntpChain.addLast( "codec", new ProtocolCodecFilter( NtpProtocolCodecFactory.getInstance() ) );
087
088        if ( ( transports == null ) || transports.isEmpty() )
089        {
090            // Default to UDP with port 123
091            // We have to create a DatagramAcceptor
092            UdpTransport transport = new UdpTransport( IP_PORT_DEFAULT );
093            setTransports( transport );
094
095            DatagramAcceptor acceptor = transport.getAcceptor();
096
097            // Set the handler
098            acceptor.setHandler( ntpProtocolHandler );
099
100            // Allow the port to be reused even if the socket is in TIME_WAIT state
101            acceptor.getSessionConfig().setReuseAddress( true );
102
103            // Inject the chain
104            acceptor.setFilterChainBuilder( ntpChain );
105
106            // Start the listener
107            acceptor.bind();
108        }
109        else
110        {
111            for ( Transport transport : transports )
112            {
113                IoAcceptor acceptor = transport.getAcceptor();
114
115                // Set the handler
116                acceptor.setHandler( ntpProtocolHandler );
117
118                if ( transport instanceof UdpTransport )
119                {
120                    // Allow the port to be reused even if the socket is in TIME_WAIT state
121                    ( ( DatagramSessionConfig ) acceptor.getSessionConfig() ).setReuseAddress( true );
122                }
123                else
124                {
125                    // Disable the disconnection of the clients on unbind
126                    acceptor.setCloseOnDeactivation( false );
127
128                    // Allow the port to be reused even if the socket is in TIME_WAIT state
129                    ( ( SocketAcceptor ) acceptor ).setReuseAddress( true );
130
131                    // No Nagle's algorithm
132                    ( ( SocketAcceptor ) acceptor ).getSessionConfig().setTcpNoDelay( true );
133                }
134
135                // Inject the chain
136                acceptor.setFilterChainBuilder( ntpChain );
137
138                // Start the listener
139                acceptor.bind();
140            }
141        }
142
143        LOG.info( "NTP server started." );
144    }
145
146
147    /**
148     * {@inheritDoc}
149     */
150    public void stop()
151    {
152        for ( Transport transport : getTransports() )
153        {
154            IoAcceptor acceptor = transport.getAcceptor();
155
156            if ( acceptor != null )
157            {
158                acceptor.dispose();
159            }
160        }
161
162        LOG.info( "NTP Server stopped." );
163    }
164
165
166    /**
167     * @see Object#toString()
168     */
169    public String toString()
170    {
171        StringBuilder sb = new StringBuilder();
172
173        sb.append( "NTPServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' );
174
175        if ( getTransports() != null )
176        {
177            for ( Transport transport : getTransports() )
178            {
179                sb.append( "    " ).append( transport ).append( '\n' );
180            }
181        }
182
183        return sb.toString();
184    }
185}