|
1 | 1 | package top.meethigher.proxy.tcp.tunnel;
|
2 | 2 |
|
3 |
| -import io.vertx.core.AsyncResult; |
4 | 3 | import io.vertx.core.Handler;
|
5 | 4 | import io.vertx.core.Vertx;
|
6 | 5 | import io.vertx.core.buffer.Buffer;
|
@@ -185,81 +184,106 @@ protected boolean doHandle(Vertx vertx, NetSocket netSocket, TunnelMessageType t
|
185 | 184 | try {
|
186 | 185 | TunnelMessage.OpenDataConn parsed = TunnelMessage.OpenDataConn.parseFrom(bodyBytes);
|
187 | 186 | final int sessionId = parsed.getSessionId();
|
188 |
| - // 保证顺序执行。 |
| 187 | + // 保证顺序,并将建立数据连接的逻辑返回给控制连接。 |
189 | 188 | CountDownLatch latch = new CountDownLatch(1);
|
190 |
| - Handler<AsyncResult<NetSocket>> asyncResultHandler = ar -> { |
191 |
| - if (ar.succeeded()) { |
192 |
| - final NetSocket dataSocket = ar.result(); |
193 |
| - dataSocket.pause(); |
194 |
| - // 连接建立成功后,立马发送消息告诉数据服务,我是数据连接,并与用户连接进行绑定 |
195 |
| - dataSocket.write(Buffer.buffer() |
196 |
| - .appendBytes(DATA_CONN_FLAG) |
197 |
| - .appendInt(sessionId)); |
198 |
| - log.debug("{}: sessionId {}, data connection {} -- {} established. wait for backend connection", |
199 |
| - dataProxyName, |
200 |
| - sessionId, |
201 |
| - dataSocket.remoteAddress(), dataSocket.localAddress()); |
202 |
| - netClient.connect(backendPort, backendHost).onComplete(rst -> { |
203 |
| - if (rst.succeeded()) { |
204 |
| - atomicResult.set(rst.succeeded()); |
205 |
| - final NetSocket backendSocket = rst.result(); |
206 |
| - backendSocket.pause(); |
207 |
| - log.debug("{}: sessionId {}, backend connection {} -- {} established", dataProxyName, sessionId, backendSocket.remoteAddress(), backendSocket.localAddress()); |
208 |
| - // 双向生命周期绑定、双向数据转发 |
209 |
| - // feat: v1.0.5以前的版本,在closeHandler里面,将对端连接也关闭。比如targetSocket关闭时,则将sourceSocket也关闭。 |
210 |
| - // 结果导致在转发短连接时,出现了bug。参考https://github.com/meethigher/tcp-reverse-proxy/issues/6 |
211 |
| - dataSocket.closeHandler(v -> { |
212 |
| - log.debug("{}: sessionId {}, data connection {} -- {} closed", dataProxyName, sessionId, dataSocket.remoteAddress(), dataSocket.localAddress()); |
213 |
| - }).pipeTo(backendSocket).onFailure(e -> { |
214 |
| - log.error("{}: sessionId {}, data connection {} -- {} pipe to backend connection {} -- {} failed", |
215 |
| - dataProxyName, |
216 |
| - sessionId, |
217 |
| - dataSocket.remoteAddress(), dataSocket.localAddress(), |
218 |
| - backendSocket.remoteAddress(), backendSocket.localAddress(), |
219 |
| - e); |
220 |
| - }); |
221 |
| - backendSocket.closeHandler(v -> { |
222 |
| - log.debug("{}: sessionId {}, backend connection {} -- {} closed", dataProxyName, sessionId, backendSocket.remoteAddress(), backendSocket.localAddress()); |
223 |
| - }).pipeTo(dataSocket).onFailure(e -> { |
224 |
| - log.error("{}: sessionId {}, backend connection {} -- {} pipe to data connection {} -- {} failed", |
225 |
| - dataProxyName, |
226 |
| - sessionId, |
227 |
| - backendSocket.remoteAddress(), backendSocket.localAddress(), |
228 |
| - dataSocket.remoteAddress(), dataSocket.localAddress(), |
229 |
| - e); |
230 |
| - }); |
231 |
| - backendSocket.resume(); |
232 |
| - dataSocket.resume(); |
233 |
| - log.debug("{}: sessionId {}, data connection {} -- {} bound to backend connection {} -- {} for session id {}", |
234 |
| - dataProxyName, |
235 |
| - sessionId, |
236 |
| - dataSocket.remoteAddress(), dataSocket.localAddress(), |
237 |
| - backendSocket.remoteAddress(), backendSocket.localAddress(), |
238 |
| - sessionId); |
239 |
| - } else { |
240 |
| - // 建立连接失败,那么数据连接就要关闭 |
241 |
| - dataSocket.close(); |
242 |
| - log.error("{}: sessionId {}, client open backend connection to {}:{} failed", |
243 |
| - dataProxyName, |
244 |
| - sessionId, |
245 |
| - backendHost, backendPort, rst.cause()); |
246 |
| - } |
247 |
| - latch.countDown(); |
248 |
| - }); |
249 |
| - } else { |
250 |
| - log.error("{}: sessionId {}, client open data connection to {}:{} failed", dataProxyName, |
251 |
| - sessionId, |
252 |
| - dataProxyHost, dataProxyPort, ar.cause()); |
253 |
| - latch.countDown(); |
254 |
| - } |
| 189 | + // 建立数据连接 |
| 190 | + Handler<Throwable> dataSocketFailureHandler = e -> { |
| 191 | + log.error("{}: sessionId {}, client failed to open data connection {}:{}", |
| 192 | + dataProxyName, |
| 193 | + sessionId, |
| 194 | + dataProxyHost, |
| 195 | + dataProxyPort); |
| 196 | + latch.countDown(); |
| 197 | + }; |
| 198 | + Handler<NetSocket> dataSocketSuccessHandler = dataSocket -> { |
| 199 | + atomicResult.set(true); |
| 200 | + latch.countDown(); |
| 201 | + dataSocket.pause(); |
| 202 | + log.debug("{}: sessionId {}, data connection {} -- {} established. ", |
| 203 | + dataProxyName, |
| 204 | + sessionId, |
| 205 | + dataSocket.remoteAddress(), dataSocket.localAddress()); |
| 206 | + // 连接建立成功后,立马发送消息告诉数据服务"我是数据连接" |
| 207 | + dataSocket.write(Buffer.buffer() |
| 208 | + .appendBytes(DATA_CONN_FLAG) |
| 209 | + .appendInt(sessionId)); |
| 210 | + final Buffer buf = Buffer.buffer(); |
| 211 | + // 等待数据连接返回与用户连接的绑定结果 |
| 212 | + dataSocket.handler(buffer -> { |
| 213 | + buf.appendBuffer(buffer); |
| 214 | + if (buf.length() < 8) { |
| 215 | + return; |
| 216 | + } |
| 217 | + if (buf.getByte(0) == Tunnel.DATA_CONN_FLAG[0] |
| 218 | + && buf.getByte(1) == Tunnel.DATA_CONN_FLAG[1] |
| 219 | + && buf.getByte(2) == Tunnel.DATA_CONN_FLAG[2] |
| 220 | + && buf.getByte(3) == Tunnel.DATA_CONN_FLAG[3] |
| 221 | + && buf.getInt(4) == sessionId |
| 222 | + ) { |
| 223 | + // 用户连接已成功与数据连接绑定。开始建立后端连接 |
| 224 | + dataSocket.pause(); |
| 225 | + netClient.connect(backendPort, backendHost) |
| 226 | + .onFailure(e -> { |
| 227 | + log.error("{}: sessionId {}, client open backend connection to {}:{} failed", |
| 228 | + dataProxyName, |
| 229 | + sessionId, |
| 230 | + backendHost, backendPort, e); |
| 231 | + dataSocket.close(); |
| 232 | + }) |
| 233 | + .onSuccess(backendSocket -> { |
| 234 | + backendSocket.pause(); |
| 235 | + log.debug("{}: sessionId {}, backend connection {} -- {} established", dataProxyName, sessionId, backendSocket.remoteAddress(), backendSocket.localAddress()); |
| 236 | + // 双向生命周期绑定、双向数据转发 |
| 237 | + // feat: v1.0.5以前的版本,在closeHandler里面,将对端连接也关闭。比如targetSocket关闭时,则将sourceSocket也关闭。 |
| 238 | + // 结果导致在转发短连接时,出现了bug。参考https://github.com/meethigher/tcp-reverse-proxy/issues/6 |
| 239 | + dataSocket.closeHandler(v -> { |
| 240 | + log.debug("{}: sessionId {}, data connection {} -- {} closed", dataProxyName, sessionId, dataSocket.remoteAddress(), dataSocket.localAddress()); |
| 241 | + }).pipeTo(backendSocket).onFailure(e -> { |
| 242 | + log.error("{}: sessionId {}, data connection {} -- {} pipe to backend connection {} -- {} failed", |
| 243 | + dataProxyName, |
| 244 | + sessionId, |
| 245 | + dataSocket.remoteAddress(), dataSocket.localAddress(), |
| 246 | + backendSocket.remoteAddress(), backendSocket.localAddress(), |
| 247 | + e); |
| 248 | + }); |
| 249 | + backendSocket.closeHandler(v -> { |
| 250 | + log.debug("{}: sessionId {}, backend connection {} -- {} closed", dataProxyName, sessionId, backendSocket.remoteAddress(), backendSocket.localAddress()); |
| 251 | + }).pipeTo(dataSocket).onFailure(e -> { |
| 252 | + log.error("{}: sessionId {}, backend connection {} -- {} pipe to data connection {} -- {} failed", |
| 253 | + dataProxyName, |
| 254 | + sessionId, |
| 255 | + backendSocket.remoteAddress(), backendSocket.localAddress(), |
| 256 | + dataSocket.remoteAddress(), dataSocket.localAddress(), |
| 257 | + e); |
| 258 | + }); |
| 259 | + backendSocket.resume(); |
| 260 | + dataSocket.resume(); |
| 261 | + log.debug("{}: sessionId {}, data connection {} -- {} bound to backend connection {} -- {} for session id {}", |
| 262 | + dataProxyName, |
| 263 | + sessionId, |
| 264 | + dataSocket.remoteAddress(), dataSocket.localAddress(), |
| 265 | + backendSocket.remoteAddress(), backendSocket.localAddress(), |
| 266 | + sessionId); |
| 267 | + }); |
255 | 268 |
|
| 269 | + } else { |
| 270 | + dataSocket.close(); |
| 271 | + log.warn("{}: sessionId {}, data connection {} -- {} received invalid message, will be closed. ", |
| 272 | + dataProxyName, |
| 273 | + sessionId, |
| 274 | + dataSocket.remoteAddress(), dataSocket.localAddress()); |
| 275 | + } |
| 276 | + }); |
| 277 | + dataSocket.resume(); |
256 | 278 | };
|
257 |
| - netClient.connect(dataProxyPort, dataProxyHost).onComplete(asyncResultHandler); |
| 279 | + netClient.connect(dataProxyPort, dataProxyHost) |
| 280 | + .onFailure(dataSocketFailureHandler) |
| 281 | + .onSuccess(dataSocketSuccessHandler); |
258 | 282 | latch.await();
|
259 |
| - netSocket.write(encode(TunnelMessageType.OPEN_DATA_CONN_ACK, TunnelMessage.OpenDataConnAck.newBuilder() |
260 |
| - .setSuccess(atomicResult.get()).setMessage("").build().toByteArray())); |
261 | 283 | } catch (Exception ignore) {
|
262 | 284 | }
|
| 285 | + netSocket.write(encode(TunnelMessageType.OPEN_DATA_CONN_ACK, TunnelMessage.OpenDataConnAck.newBuilder() |
| 286 | + .setSuccess(atomicResult.get()).setMessage("").build().toByteArray())); |
263 | 287 | return atomicResult.get();
|
264 | 288 | }
|
265 | 289 | });
|
|
0 commit comments