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
021package org.apache.directory.server.dns.protocol;
022
023
024import java.util.ArrayList;
025
026import org.apache.directory.server.dns.DnsServer;
027import org.apache.directory.server.dns.DnsException;
028import org.apache.directory.server.dns.messages.DnsMessage;
029import org.apache.directory.server.dns.messages.DnsMessageModifier;
030import org.apache.directory.server.dns.messages.MessageType;
031import org.apache.directory.server.dns.messages.OpCode;
032import org.apache.directory.server.dns.messages.ResourceRecord;
033import org.apache.directory.server.dns.messages.ResponseCode;
034import org.apache.directory.server.dns.service.DnsContext;
035import org.apache.directory.server.dns.service.DomainNameService;
036import org.apache.directory.server.dns.store.RecordStore;
037import org.apache.mina.core.service.IoHandlerAdapter;
038import org.apache.mina.core.session.IdleStatus;
039import org.apache.mina.core.session.IoSession;
040import org.apache.mina.filter.codec.ProtocolCodecFilter;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044
045/**
046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047 */
048public class DnsProtocolHandler extends IoHandlerAdapter
049{
050    private static final Logger LOG = LoggerFactory.getLogger( DnsProtocolHandler.class );
051
052    private DnsServer config;
053    private RecordStore store;
054    private String contextKey = "context";
055
056
057    /**
058     * Creates a new instance of DnsProtocolHandler.
059     *
060     * @param config
061     * @param store
062     */
063    public DnsProtocolHandler( DnsServer config, RecordStore store )
064    {
065        this.config = config;
066        this.store = store;
067    }
068
069
070    @Override
071    public void sessionCreated( IoSession session ) throws Exception
072    {
073        if ( LOG.isDebugEnabled() )
074        {
075            LOG.debug( "{} CREATED:  {}", session.getRemoteAddress(), session.getTransportMetadata() );
076        }
077
078        if ( session.getTransportMetadata().isConnectionless() )
079        {
080            session.getFilterChain().addFirst( "codec",
081                new ProtocolCodecFilter( DnsProtocolUdpCodecFactory.getInstance() ) );
082        }
083        else
084        {
085            session.getFilterChain().addFirst( "codec",
086                new ProtocolCodecFilter( DnsProtocolTcpCodecFactory.getInstance() ) );
087        }
088    }
089
090
091    @Override
092    public void sessionOpened( IoSession session )
093    {
094        LOG.debug( "{} OPENED", session.getRemoteAddress() );
095    }
096
097
098    @Override
099    public void sessionClosed( IoSession session )
100    {
101        LOG.debug( "{} CLOSED", session.getRemoteAddress() );
102    }
103
104
105    @Override
106    public void sessionIdle( IoSession session, IdleStatus status )
107    {
108        LOG.debug( "{} IDLE ({})", session.getRemoteAddress(), status );
109    }
110
111
112    @Override
113    public void exceptionCaught( IoSession session, Throwable cause )
114    {
115        LOG.error( session.getRemoteAddress() + " EXCEPTION", cause );
116        session.closeNow();
117    }
118
119
120    @Override
121    public void messageReceived( IoSession session, Object message )
122    {
123        LOG.debug( "{} RCVD:  {}", session.getRemoteAddress(), message );
124
125        try
126        {
127            DnsContext dnsContext = new DnsContext();
128            dnsContext.setConfig( config );
129            dnsContext.setStore( store );
130            session.setAttribute( getContextKey(), dnsContext );
131
132            DomainNameService.execute( dnsContext, ( DnsMessage ) message );
133
134            DnsMessage response = dnsContext.getReply();
135
136            session.write( response );
137        }
138        catch ( Exception e )
139        {
140            LOG.error( e.getLocalizedMessage(), e );
141
142            DnsMessage request = ( DnsMessage ) message;
143            DnsException de = ( DnsException ) e;
144
145            DnsMessageModifier modifier = new DnsMessageModifier();
146
147            modifier.setTransactionId( request.getTransactionId() );
148            modifier.setMessageType( MessageType.RESPONSE );
149            modifier.setOpCode( OpCode.QUERY );
150            modifier.setAuthoritativeAnswer( false );
151            modifier.setTruncated( false );
152            modifier.setRecursionDesired( request.isRecursionDesired() );
153            modifier.setRecursionAvailable( false );
154            modifier.setReserved( false );
155            modifier.setAcceptNonAuthenticatedData( false );
156            modifier.setResponseCode( ResponseCode.convert( ( byte ) de.getResponseCode() ) );
157            modifier.setQuestionRecords( request.getQuestionRecords() );
158            modifier.setAnswerRecords( new ArrayList<ResourceRecord>() );
159            modifier.setAuthorityRecords( new ArrayList<ResourceRecord>() );
160            modifier.setAdditionalRecords( new ArrayList<ResourceRecord>() );
161
162            session.write( modifier.getDnsMessage() );
163        }
164    }
165
166
167    @Override
168    public void messageSent( IoSession session, Object message )
169    {
170        LOG.debug( "{} SENT:  {}", session.getRemoteAddress(), message );
171    }
172
173
174    protected String getContextKey()
175    {
176        return ( this.contextKey );
177    }
178
179    
180    @Override
181    public void inputClosed( IoSession session )
182    {
183    }
184}