View Javadoc

1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.example.securechat;
17  
18  import java.net.InetAddress;
19  import java.util.logging.Level;
20  import java.util.logging.Logger;
21  
22  import org.jboss.netty.channel.Channel;
23  import org.jboss.netty.channel.ChannelEvent;
24  import org.jboss.netty.channel.ChannelFuture;
25  import org.jboss.netty.channel.ChannelFutureListener;
26  import org.jboss.netty.channel.ChannelHandlerContext;
27  import org.jboss.netty.channel.ChannelStateEvent;
28  import org.jboss.netty.channel.ExceptionEvent;
29  import org.jboss.netty.channel.MessageEvent;
30  import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
31  import org.jboss.netty.channel.group.ChannelGroup;
32  import org.jboss.netty.channel.group.DefaultChannelGroup;
33  import org.jboss.netty.handler.ssl.SslHandler;
34  
35  /**
36   * Handles a server-side channel.
37   */
38  public class SecureChatServerHandler extends SimpleChannelUpstreamHandler {
39  
40      private static final Logger logger = Logger.getLogger(
41              SecureChatServerHandler.class.getName());
42  
43      static final ChannelGroup channels = new DefaultChannelGroup();
44  
45      @Override
46      public void handleUpstream(
47              ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
48          if (e instanceof ChannelStateEvent) {
49              logger.info(e.toString());
50          }
51          super.handleUpstream(ctx, e);
52      }
53  
54      @Override
55      public void channelConnected(
56              ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
57  
58          // Get the SslHandler in the current pipeline.
59          // We added it in SecureChatPipelineFactory.
60          final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
61  
62          // Get notified when SSL handshake is done.
63          ChannelFuture handshakeFuture = sslHandler.handshake();
64          handshakeFuture.addListener(new Greeter(sslHandler));
65      }
66  
67      @Override
68      public void channelDisconnected(
69              ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
70          // Unregister the channel from the global channel list
71          // so the channel does not receive messages anymore.
72          channels.remove(e.getChannel());
73      }
74  
75      @Override
76      public void messageReceived(
77              ChannelHandlerContext ctx, MessageEvent e) {
78  
79          // Convert to a String first.
80          String request = (String) e.getMessage();
81  
82          // Send the received message to all channels but the current one.
83          for (Channel c: channels) {
84              if (c != e.getChannel()) {
85                  c.write("[" + e.getChannel().getRemoteAddress() + "] " +
86                          request + '\n');
87              } else {
88                  c.write("[you] " + request + '\n');
89              }
90          }
91  
92          // Close the connection if the client has sent 'bye'.
93          if (request.toLowerCase().equals("bye")) {
94              e.getChannel().close();
95          }
96      }
97  
98      @Override
99      public void exceptionCaught(
100             ChannelHandlerContext ctx, ExceptionEvent e) {
101         logger.log(
102                 Level.WARNING,
103                 "Unexpected exception from downstream.",
104                 e.getCause());
105         e.getChannel().close();
106     }
107 
108     private static final class Greeter implements ChannelFutureListener {
109 
110         private final SslHandler sslHandler;
111 
112         Greeter(SslHandler sslHandler) {
113             this.sslHandler = sslHandler;
114         }
115 
116         public void operationComplete(ChannelFuture future) throws Exception {
117             if (future.isSuccess()) {
118                 // Once session is secured, send a greeting.
119                 future.getChannel().write(
120                         "Welcome to " + InetAddress.getLocalHost().getHostName() +
121                         " secure chat service!\n");
122                 future.getChannel().write(
123                         "Your session is protected by " +
124                         sslHandler.getEngine().getSession().getCipherSuite() +
125                         " cipher suite.\n");
126 
127                 // Register the channel to the global channel list
128                 // so the channel received the messages from others.
129                 channels.add(future.getChannel());
130             } else {
131                 future.getChannel().close();
132             }
133         }
134     }
135 }