//socks5Client 代理客户端

import wsock.tcp.client;
namespace wsock.tcp;

class socks5Client{
	ctor(ip,port,user,pwd){
		
		this = ..wsock.tcp.client();
		this.realConnect = this.connect;
		
		if( this.realConnect(ip,port) ) {
			var req = {
				BYTE ver = 5;
				BYTE nmethods = 1;
				BYTE methods[] = {user ? 2 : 0};
			}
			this.write(req) 
				
			var rep = this.read({
				BYTE ver;
				BYTE method;
			}); 
			
			if(rep[["ver"]]!=5){
				return null,"服务器不支持SOCKS5协议";
			}
	
			if( rep[["method"]] == 2 ){
				if(! (user && pwd) ){
					return null,"代码服务器需要用户名与密码";
				}
				var req = {
					BYTE ver = 5;
					BYTE userLen = #user;
					BYTE user[] = user;
					BYTE pwdLen = #pwd;
					BYTE pwd[] = pwd;
				}
				this.write(req) 
					
					var rep = this.read({
					BYTE ver;
					BYTE status;
				}); 
				
				if(rep.status!=0) return null,"认证失败"
			}
			elseif(rep[["method"]]){
				return null,"连接代理服务器时遇到错误";
			}
			
			this.connect = function(ip,port){
				if( (port===null) && (ip===null) ) error("请指定域名或端口地址",2);
				if(!#ip){
					error("域名或IP不能为空",2);
				}
				
				var atyp = ..string.match(ip,"^\d+\.\d+\.\d+\.\d+$") ? 1 : 3;
		
				if(atyp==1){
					var service = ..wsock.sockaddr_in( ip,port );
					if(!service) return;
					service.sin_family = 0x2/*_AF_INET*/
					
					//必须一次写过去
					this.write({ 
						BYTE ver = 5;
							BYTE cmd = 1;
							BYTE rsv = 0;
							BYTE atyp = atyp;
							struct dstAddr = service.sin_addr; 
							WORD dstPort = service.sin_port;
							_struct_aligned = 1;
					} );  	
					}
				else {
					//必须一次写过去
					this.write({ 
						BYTE ver = 5;
							BYTE cmd = 1;
							BYTE rsv = 0;
							BYTE atyp = atyp; 
							BYTE len = #ip;
							BYTE domain[] = ip;
							WORD dstPort = ..wsock.htons((tonumber(port)));
							_struct_aligned = 1;
					} ); 
				}
					
				var rep = this.read({
					BYTE ver;BYTE status;BYTE rsv;BYTE atyp;   
				} )
				
				if(!rep) return false,"协议错误";
				if(rep.status){
					return false,({"普通SOCKS服务器连接失败";"现有规则不允许连接";"网络不可达";"主机不可达";
						"连接被拒";"TTL超时";"不支持的命令";"不支持的地址类型";"0xFF未定义"})[rep.status];
				} 
				
				if( rep.atyp =  1 ){
					if(!this.read({INT bndAddr;})) return false; 
					if(!this.read({WORD bndPort;})) return false;  
				}  
				else if( rep.atyp =  3 ){
					var rep = this.read({
						BYTE len;   
					});
					this.read(rep.len);
					this.read({WORD bndPort;}); 
				}
				else {
					return false;
				} 
				
				this.readyState = 1;
				return true; 
			};
		}
		else {
			return null,"连接服务器失败";
		}
	};
}

/**intellisense()
wsock.tcp.socks5Client(.(IP或域名,端口号,用户名,密码) = 创建SOCKS5代理TCP客户端，用户名和密码为可选参数\n连接失败返回null,错误信息
wsock.tcp.socks5Client() = !stdtcpclient.
end intellisense**/
