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     */
020    package org.apache.directory.server.ntp;
021    
022    
023    import java.io.IOException;
024    
025    import org.apache.directory.server.ntp.protocol.NtpProtocolCodecFactory;
026    import org.apache.directory.server.ntp.protocol.NtpProtocolHandler;
027    import org.apache.directory.server.protocol.shared.AbstractProtocolService;
028    import org.apache.directory.server.protocol.shared.transport.Transport;
029    import org.apache.directory.server.protocol.shared.transport.UdpTransport;
030    import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
031    import org.apache.mina.core.service.IoAcceptor;
032    import org.apache.mina.core.service.IoHandler;
033    import org.apache.mina.filter.codec.ProtocolCodecFilter;
034    import org.apache.mina.transport.socket.DatagramAcceptor;
035    import org.apache.mina.transport.socket.DatagramSessionConfig;
036    import org.apache.mina.transport.socket.SocketAcceptor;
037    import org.slf4j.Logger;
038    import 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     * @version $Rev: 896599 $, $Date: 2010-01-06 19:26:43 +0100 (Wed, 06 Jan 2010) $
046     * @org.apache.xbean.XBean
047     */
048    public class NtpServer extends AbstractProtocolService
049    {
050        /** logger for this class */
051        private static final Logger LOG = LoggerFactory.getLogger( NtpServer.class.getName() );
052        
053        /**
054         * The default IP port.
055         */
056        private static final int IP_PORT_DEFAULT = 123;
057    
058        /** The default service pid. */
059        private static final String SERVICE_PID_DEFAULT = "org.apache.directory.server.ntp";
060    
061        /** The default service name. */
062        private static final String SERVICE_NAME_DEFAULT = "ApacheDS NTP Service";
063    
064    
065        /**
066         * Creates a new instance of NtpConfiguration.
067         */
068        public NtpServer()
069        {
070            super.setServiceId( SERVICE_PID_DEFAULT );
071            super.setServiceName( SERVICE_NAME_DEFAULT );
072        }
073    
074        
075        /**
076         * Start the NTPServer. We initialize the Datagram and Socket, if necessary.
077         * 
078         * Note that we don't have any filter in the chain, everything is done
079         * in the handler.
080         * @throws IOException if there are issues binding
081         */
082        public void start() throws IOException
083        {
084            IoHandler ntpProtocolHandler = new NtpProtocolHandler();
085            
086            // Create the chain for the NTP server
087            DefaultIoFilterChainBuilder ntpChain = new DefaultIoFilterChainBuilder();
088            ntpChain.addLast( "codec", new ProtocolCodecFilter( NtpProtocolCodecFactory.getInstance() ) );
089            
090            if ( ( transports == null ) || ( transports.size() == 0 ) )
091            {
092                // Default to UDP with port 123
093                // We have to create a DatagramAcceptor
094                UdpTransport transport = new UdpTransport( IP_PORT_DEFAULT );
095                setTransports( transport );
096                
097                DatagramAcceptor acceptor = (DatagramAcceptor)transport.getAcceptor();
098    
099                // Set the handler
100                acceptor.setHandler( ntpProtocolHandler );
101        
102                // Allow the port to be reused even if the socket is in TIME_WAIT state
103                ((DatagramSessionConfig)acceptor.getSessionConfig()).setReuseAddress( true );
104        
105                // Inject the chain
106                acceptor.setFilterChainBuilder( ntpChain );
107                
108                // Start the listener
109                acceptor.bind();
110            }
111            else
112            {
113                for ( Transport transport:transports )
114                {
115                    IoAcceptor acceptor = transport.getAcceptor();
116    
117                    // Set the handler
118                    acceptor.setHandler( ntpProtocolHandler );
119                    
120                    if ( transport instanceof UdpTransport )
121                    {
122                        // Allow the port to be reused even if the socket is in TIME_WAIT state
123                        ((DatagramSessionConfig)acceptor.getSessionConfig()).setReuseAddress( true );
124                    }
125                    else
126                    {
127                        // Disable the disconnection of the clients on unbind
128                        acceptor.setCloseOnDeactivation( false );
129                        
130                        // Allow the port to be reused even if the socket is in TIME_WAIT state
131                        ((SocketAcceptor)acceptor).setReuseAddress( true );
132                        
133                        // No Nagle's algorithm
134                        ((SocketAcceptor)acceptor).getSessionConfig().setTcpNoDelay( true );
135                    }
136                    
137                    // Inject the chain
138                    acceptor.setFilterChainBuilder( ntpChain );
139        
140                    // Start the listener
141                    acceptor.bind();
142                }
143            }
144            
145            LOG.info( "NTP server started." );
146            System.out.println( "NTP server started." );
147        }
148    
149        
150        /**
151         * {@inheritDoc}
152         */
153        public void stop()
154        {
155            for ( Transport transport :getTransports() )
156            {
157                IoAcceptor acceptor = transport.getAcceptor();
158                
159                if ( acceptor != null )
160                {
161                    acceptor.dispose();
162                }
163            }
164    
165            LOG.info( "NTP Server stopped." );
166            System.out.println( "NTP Server stopped." );
167        }
168        
169        
170        /**
171         * @see Object#toString()
172         */
173        public String toString()
174        {
175            StringBuilder sb = new StringBuilder();
176            
177            sb.append( "NTPServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' );
178            
179            if ( getTransports() != null )
180            {
181                for ( Transport transport:getTransports() )
182                {
183                    sb.append( "    " ).append( transport ).append( '\n' );
184                }
185            }
186            
187            return sb.toString();
188        }
189    }