1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.proxy.event;
21
22 import java.util.LinkedList;
23 import java.util.Queue;
24
25 import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
26 import org.apache.mina.proxy.session.ProxyIoSession;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31 * IoSessionEventQueue.java - Queue that contains filtered session events
32 * while handshake isn't done.
33 *
34 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
35 * @since MINA 2.0.0-M3
36 */
37 public class IoSessionEventQueue {
38 private final static Logger logger = LoggerFactory.getLogger(IoSessionEventQueue.class);
39
40 /**
41 * The proxy session object.
42 */
43 private ProxyIoSession proxyIoSession;
44
45 /**
46 * Queue of session events which occurred before the proxy handshake had completed.
47 */
48 private Queue<IoSessionEvent> sessionEventsQueue = new LinkedList<IoSessionEvent>();
49
50 public IoSessionEventQueue(ProxyIoSession proxyIoSession) {
51 this.proxyIoSession = proxyIoSession;
52 }
53
54 /**
55 * Discard all events from the queue.
56 */
57 private void discardSessionQueueEvents() {
58 synchronized (sessionEventsQueue) {
59 // Free queue
60 sessionEventsQueue.clear();
61 logger.debug("Event queue CLEARED");
62 }
63 }
64
65 /**
66 * Event is enqueued only if necessary :
67 * - socks proxies do not need the reconnection feature so events are always
68 * forwarded for these.
69 * - http proxies events will be enqueued while handshake has not been completed
70 * or until connection was closed.
71 * If connection was prematurely closed previous events are discarded and only the
72 * session closed is delivered.
73 *
74 * @param evt the event to enqueue
75 */
76 public void enqueueEventIfNecessary(final IoSessionEvent evt) {
77 logger.debug("??? >> Enqueue {}", evt);
78
79 if (proxyIoSession.getRequest() instanceof SocksProxyRequest) {
80 // No reconnection used
81 evt.deliverEvent();
82 return;
83 }
84
85 if (proxyIoSession.getHandler().isHandshakeComplete()) {
86 evt.deliverEvent();
87 } else {
88 if (evt.getType() == IoSessionEventType.CLOSED) {
89 if (proxyIoSession.isAuthenticationFailed()) {
90 proxyIoSession.getConnector().cancelConnectFuture();
91 discardSessionQueueEvents();
92 evt.deliverEvent();
93 } else {
94 discardSessionQueueEvents();
95 }
96 } else if (evt.getType() == IoSessionEventType.OPENED) {
97 // Enqueue event cause it will not reach IoHandler but deliver it to enable
98 // session creation.
99 enqueueSessionEvent(evt);
100 evt.deliverEvent();
101 } else {
102 enqueueSessionEvent(evt);
103 }
104 }
105 }
106
107 /**
108 * Send any session event which were queued while waiting for handshaking to complete.
109 *
110 * Please note this is an internal method. DO NOT USE it in your code.
111 */
112 public void flushPendingSessionEvents() throws Exception {
113 synchronized (sessionEventsQueue) {
114 IoSessionEvent evt;
115
116 while ((evt = sessionEventsQueue.poll()) != null) {
117 logger.debug(" Flushing buffered event: {}", evt);
118 evt.deliverEvent();
119 }
120 }
121 }
122
123 /**
124 * Enqueue an event to be delivered once handshaking is complete.
125 *
126 * @param evt the session event to enqueue
127 */
128 private void enqueueSessionEvent(final IoSessionEvent evt) {
129 synchronized (sessionEventsQueue) {
130 logger.debug("Enqueuing event: {}", evt);
131 sessionEventsQueue.offer(evt);
132 }
133 }
134 }