}
@Override
protected boolean handleResponse(ChannelHandlerContext ctx, Object response) throws Exception {
if (response instanceof Socks5InitResponse) {
Socks5InitResponse res = (Socks5InitResponse) response;
Socks5AuthScheme authScheme = socksAuthScheme();
if (res.authScheme() != Socks5AuthScheme.NO_AUTH && authScheme != res.authScheme()) {
// Server did not allow unauthenticated access nor accept the requested authentication scheme.
throw new ProxyConnectException(exceptionMessage("unexpected authScheme: " + res.authScheme()));
}
switch (authScheme) {
case NO_AUTH:
sendConnectCommand(ctx);
break;
case AUTH_PASSWORD:
// In case of password authentication, send an authentication request.
ctx.pipeline().addBefore(encoderName, decoderName, new Socks5AuthResponseDecoder());
sendToProxyServer(
new Socks5AuthRequest(username != null? username : "", password != null? password : ""));
break;
default:
// Should never reach here.
throw new Error();
}
return false;
}
if (response instanceof Socks5AuthResponse) {
// Received an authentication response from the server.
Socks5AuthResponse res = (Socks5AuthResponse) response;
if (res.authStatus() != Socks5AuthStatus.SUCCESS) {
throw new ProxyConnectException(exceptionMessage("authStatus: " + res.authStatus()));
}
sendConnectCommand(ctx);
return false;
}
// This should be the last message from the server.
Socks5CmdResponse res = (Socks5CmdResponse) response;
if (res.cmdStatus() != Socks5CmdStatus.SUCCESS) {
throw new ProxyConnectException(exceptionMessage("cmdStatus: " + res.cmdStatus()));
}
return true;
}