func _adminKickSession(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { server := r.FormValue("server") session := r.FormValue("session") if server == "" || session == "" { result = "please spec server and session" bSuccess = false return } conn, bHave := common.ServerName2Conn[server] if bHave { server, bHave2 := common.Conn2ClientInfo[conn] if bHave2 { session, bHave := server.Id2Session[session] if bHave { if session.ClientA != conn { common.Write(session.ClientA, "0", "showandquit", "admin kick you out") } else if session.ClientB != conn { common.Write(session.ClientB, "0", "showandquit", "admin kick you out") } result = "kick session ok" } else { result = "no need kick" } } else { bSuccess = false result = "donnot have this conn" } } else { bSuccess = false result = "donnot have this serverName" return } bSuccess = true return }
func handleLocalPortResponse(client *Client, id string) { sessionId := id if !client.bUdp { arr := strings.Split(id, "-") sessionId = arr[1] } session := client.getSession(sessionId) if session == nil { return } conn := session.localConn if conn == nil { return } arr := make([]byte, nat.SendBuffSize) reader := bufio.NewReader(conn) for { size, err := reader.Read(arr) if err != nil { break } if common.Write(session.pipe, id, "tunnel_msg_s", string(arr[0:size])) != nil { break } } // log.Println("handlerlocal down") if client.removeSession(sessionId) { common.Write(session.pipe, id, "tunnel_close_s", "") } }
func handleLocalServerResponse(client *Client, sessionId string) { session := client.getSession(sessionId) if session == nil { return } pipe := session.pipe if pipe == nil { return } conn := session.localConn common.Write(pipe, sessionId, "tunnel_open", "") arr := make([]byte, nat.SendBuffSize) reader := bufio.NewReader(conn) for { size, err := reader.Read(arr) if err != nil { break } if common.Write(pipe, sessionId, "tunnel_msg_c", string(arr[0:size])) != nil { break } } common.Write(pipe, sessionId, "tunnel_close", "") client.removeSession(sessionId) }
func _adminBroadcast(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { msgtype := r.FormValue("type") if msgtype == "" { result = "please spec type" bSuccess = false return } msg := r.FormValue("msg") quit := r.FormValue("quit") cmd := "show" if quit != "" { cmd = "showandquit" } n := 0 for conn, info := range common.Conn2ClientInfo { hit := false if msgtype == "s" && info.IsServer { hit = true } else if msgtype == "c" && !info.IsServer { hit = true } else if msgtype == "a" { hit = true } if hit { common.Write(conn, "0", cmd, msg) n++ } } result = fmt.Sprintf("%d", n) bSuccess = true return }
func (session *UDPMakeSession) reportAddrList(buster bool, outip string) { id := session.id var otherAddrList string if !buster { arr := strings.SplitN(outip, ":", 2) outip, otherAddrList = arr[0], arr[1] } else { arr := strings.SplitN(outip, ":", 2) var delayTime string outip, delayTime = arr[0], arr[1] session.delay, _ = strconv.Atoi(delayTime) if session.delay < 0 { session.delay = 0 } } outip += ";" + *addInitAddr _id, _ := strconv.Atoi(id) engine, err := nat.Init(outip, buster, _id, *serverBustAddr) engine.Kcp = getKcpSetting() engine.D = *dataShards engine.P = *parityShards if err != nil { println("init error", err.Error()) disconnect() return } session.engine = engine session.buster = buster if !buster { engine.SetOtherAddrList(otherAddrList) } addrList := engine.GetAddrList() println("addrList", addrList) common.Write(remoteConn, id, "report_addrlist", addrList) }
func handleClient(conn net.Conn) { common.Conn2ClientInfo[conn] = &common.ClientInfo{Conn: conn, ClientMap: make(map[net.Conn]*common.Session), Id2Session: make(map[string]*common.Session), IsServer: false, Quit: make(chan bool), ResponseTime: time.Now().Unix()} log.Println("client linked success", conn.RemoteAddr().String()) common.Conn2ClientInfo[conn].Loop() common.Read(conn, handleResponse) client, bHave := common.Conn2ClientInfo[conn] if bHave { close(client.Quit) if client.IsServer { for conn, session := range client.ClientMap { conn.Close() common.RmId(client.ServerName, session.Id) } delete(common.ServerName2Conn, client.ServerName) log.Println("unregister service Name", client.ServerName) if bUseDB { user, _ := auth.GetUser(client.UserName) if user != nil { user.OnLogout() } } } else { common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { id := server.DelClient(conn) log.Println("send quit") common.Write(server.Conn, id, "clientquit", "") }, func() {}) } delete(common.Conn2ClientInfo, conn) } conn.Close() log.Println("client disconnected", conn.RemoteAddr().String()) }
func (sc *Client) MultiListen() bool { if g_LocalConn == nil { g_LocalConn, err := net.Listen("tcp", *localAddr) if err != nil { log.Println("cannot listen addr:" + err.Error()) if remoteConn != nil { remoteConn.Close() } return false } go func() { quit := false ping := time.NewTicker(time.Second * 5) go func() { out: for { select { case <-ping.C: if quit { break out } for _, pipe := range sc.pipes { common.Write(pipe, "-1", "ping", "") } } } }() ping.Stop() for { conn, err := g_LocalConn.Accept() if err != nil { continue } sessionId := common.GetId("udp") pipe := sc.getOnePipe() if pipe == nil { log.Println("cannot get pipe for client") if remoteConn != nil { remoteConn.Close() } return } sc.sessionLock.Lock() sc.sessions[sessionId] = &clientSession{pipe: pipe, localConn: conn} sc.sessionLock.Unlock() log.Println("client", sc.id, "create session", sessionId) go handleLocalServerResponse(sc, sessionId) } quit = true }() mode := "p2p mode" if !sc.bUdp { mode = "c/s mode" delete(g_ClientMapKey, sc.id) } println("service start success,please connect", *localAddr, mode) } return true }
func connect() { if *pipeNum <= 0 { *pipeNum = 1 } clientInfo := common.ClientSetting{Version: common.Version, Delay: *delayTime, Mode: *clientMode, PipeNum: *pipeNum, AccessKey: *accessKey, ClientKey: *clientKey, AesKey: ""} if *bEncrypt { clientInfo.AesKey = string([]byte(fmt.Sprintf("asd4%d%d", int32(time.Now().Unix()), (rand.Intn(100000) + 100)))[:16]) log.Println("debug aeskey", clientInfo.AesKey) key, _ := aes.NewCipher([]byte(clientInfo.AesKey)) aesKey = &key } if *bLoadSettingFromFile { var setting fileSetting err := loadSettings(&setting) if err == nil { clientInfo.AccessKey = setting.Key } else { log.Println("load setting fail", err.Error()) } } else { if clientInfo.AccessKey != "" { var setting = fileSetting{Key: clientInfo.AccessKey} err := saveSettings(setting) if err != nil { log.Println("save setting error", err.Error()) } else { println("save setting ok, nexttime please use -f to replace -key") } } } if clientType == 0 { markName = *serveName clientInfo.ClientType = "reg" } else if clientType == 1 { markName = *linkName clientInfo.ClientType = "link" } else { println("no clienttype!") } clientInfo.Name = markName clientInfoStr, err := json.Marshal(clientInfo) if err != nil { println("encode args error") } log.Println("init client", string(clientInfoStr)) common.Write(remoteConn, "0", "init", string(clientInfoStr)) }
func shutdown() { for conn, client := range common.Conn2ClientInfo { if !client.IsServer { log.Println("shutdown client", client.ServerName) common.Write(conn, "0", "showandquit", "server shutdown") } else { log.Println("unregister service Name", client.ServerName) if bUseDB { user, _ := auth.GetUser(client.UserName) if user != nil { user.OnLogout() } } //donnot showandquit,because client_server need to reconnect } } }
func _adminKickServer(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { server := r.FormValue("server") if server == "" { result = "please spec server" bSuccess = false return } conn, bHave := common.ServerName2Conn[server] if bHave { common.Write(conn, "0", "showandquit", "admin kick you out") result = "kick server ok" } else { bSuccess = false result = "donnot have this serverName" return } bSuccess = true return }
func handleResponse(conn net.Conn, clientId string, action string, content string) { //log.Println("got", clientId, action) switch action { case "aeskey": fmt.Println("init aeskey for client", clientId, content) block, _ := aes.NewCipher([]byte(content)) g_ClientMapKey[clientId] = &block case "show": fmt.Println(time.Now().Format("2006-01-02 15:04:05"), content) case "showandretry": fmt.Println(time.Now().Format("2006-01-02 15:04:05"), content) remoteConn.Close() case "showandquit": fmt.Println(time.Now().Format("2006-01-02 15:04:05"), content) remoteConn.Close() bForceQuit = true case "clientquit": client := g_ClientMap[clientId] log.Println("clientquit!!!", clientId, client) if client != nil { client.Quit() } case "remove_udpsession": log.Println("server force remove udpsession", clientId) delete(g_Id2UDPSession, clientId) case "query_addrlist_a": outip := content arr := strings.Split(clientId, "-") id := arr[0] sessionId := arr[1] pipeType := arr[2] g_Id2UDPSession[id] = &UDPMakeSession{id: id, sessionId: sessionId, pipeType: pipeType} go g_Id2UDPSession[id].reportAddrList(true, outip) case "query_addrlist_b": arr := strings.Split(clientId, "-") id := arr[0] sessionId := arr[1] pipeType := arr[2] g_Id2UDPSession[id] = &UDPMakeSession{id: id, sessionId: sessionId, pipeType: pipeType} go g_Id2UDPSession[id].reportAddrList(false, content) case "tell_bust_a": session, bHave := g_Id2UDPSession[clientId] if bHave { go session.beginMakeHole(content) } case "tell_bust_b": session, bHave := g_Id2UDPSession[clientId] if bHave { go session.beginMakeHole("") } case "csmode_c_tunnel_close": log.Println("receive close msg from server") arr := strings.Split(clientId, "-") clientId = arr[0] sessionId := arr[1] client, bHave := g_ClientMap[clientId] if bHave { client.removeSession(sessionId) } case "csmode_s_tunnel_close": arr := strings.Split(clientId, "-") clientId = arr[0] sessionId := arr[1] client, bHave := g_ClientMap[clientId] if bHave { client.removeSession(sessionId) } case "csmode_s_tunnel_open": oriId := clientId arr := strings.Split(oriId, "-") clientId = arr[0] sessionId := arr[1] client, bHave := g_ClientMap[clientId] if !bHave { client = &Client{id: clientId, pipes: make(map[int]net.Conn), engine: nil, buster: true, sessions: make(map[string]*clientSession), ready: true, bUdp: false} client.pipes[0] = remoteConn g_ClientMap[clientId] = client } else { client.pipes[0] = remoteConn client.ready = true client.bUdp = false } //log.Println("client init csmode", clientId, sessionId) if *localAddr != "socks5" { s_conn, err := net.DialTimeout("tcp", *localAddr, 10*time.Second) if err != nil { log.Println("connect to local server fail:", err.Error()) msg := "cannot connect to bind addr" + *localAddr common.Write(remoteConn, clientId, "tunnel_error", msg) //remoteConn.Close() return } else { client.sessionLock.Lock() client.sessions[sessionId] = &clientSession{pipe: remoteConn, localConn: s_conn} client.sessionLock.Unlock() go handleLocalPortResponse(client, oriId) } } else { client.sessionLock.Lock() client.sessions[sessionId] = &clientSession{pipe: remoteConn, localConn: nil, status: "init", recvMsg: ""} client.sessionLock.Unlock() } case "csmode_c_begin": client, bHave := g_ClientMap[clientId] if !bHave { client = &Client{id: clientId, pipes: make(map[int]net.Conn), engine: nil, buster: false, sessions: make(map[string]*clientSession), ready: true, bUdp: false} client.pipes[0] = remoteConn g_ClientMap[clientId] = client } else { client.pipes[0] = remoteConn client.ready = true client.bUdp = false } if client.MultiListen() { common.Write(remoteConn, clientId, "makeholeok", "csmode") } case "csmode_msg_c": oriId := clientId arr := strings.Split(clientId, "-") clientId = arr[0] sessionId := arr[1] client, bHave := g_ClientMap[clientId] if bHave { session := client.getSession(sessionId) if session != nil && session.localConn != nil { session.localConn.Write([]byte(content)) } else if session != nil && *localAddr == "socks5" { session.processSockProxy(client, oriId, content, func() { if len(session.recvMsg) > 0 && session.localConn != nil { session.localConn.Write([]byte(session.recvMsg)) } }) } } case "csmode_msg_s": arr := strings.Split(clientId, "-") clientId = arr[0] sessionId := arr[1] client, bHave := g_ClientMap[clientId] if bHave { session := client.getSession(sessionId) if session != nil && session.localConn != nil { session.localConn.Write([]byte(content)) } else { //log.Println("cs:cannot tunnel msg", sessionId) } } } }
func (session *clientSession) processSockProxy(sc *Client, sessionId, content string, callback func()) { pipe := session.pipe session.recvMsg += content bytes := []byte(session.recvMsg) size := len(bytes) //log.Println("recv msg-====", len(session.recvMsg), session.recvMsg, session.status, sessionId) switch session.status { case "init": if session.localConn != nil { session.localConn.Close() session.localConn = nil } if size < 2 { //println("wait init") return } var _, nmethod uint8 = bytes[0], bytes[1] //println("version", version, nmethod) session.status = "version" session.recvMsg = string(bytes[2:]) session.extra = nmethod case "version": if uint8(size) < session.extra { //println("wait version") return } var send = []uint8{5, 0} go common.Write(pipe, sessionId, "tunnel_msg_s", string(send)) session.status = "hello" session.recvMsg = string(bytes[session.extra:]) session.extra = 0 //log.Println("now", len(session.recvMsg)) case "hello": var hello reqMsg bOk, tail := hello.read(bytes) if bOk { go func() { var ansmsg ansMsg url := hello.url var s_conn net.Conn var err error if *dnsCacheNum > 0 && hello.atyp == 3 { host := string(hello.dst_addr[1 : 1+hello.dst_addr[0]]) resChan := make(chan *dnsQueryRes) checkDns <- &dnsQueryReq{c: resChan, host: host, port: int(hello.dst_port2), reqtype: hello.reqtype, url: url} res := <-resChan s_conn = res.conn err = res.err if res.ip != "" { url = net.JoinHostPort(res.ip, fmt.Sprintf("%d", hello.dst_port2)) } } if s_conn == nil && err == nil { s_conn, err = net.DialTimeout(hello.reqtype, url, 30*time.Second) } if err != nil { log.Println("connect to local server fail:", err.Error()) ansmsg.gen(&hello, 4) go common.Write(pipe, sessionId, "tunnel_msg_s", string(ansmsg.buf[:ansmsg.mlen])) return } else { session.localConn = s_conn go handleLocalPortResponse(sc, sessionId) ansmsg.gen(&hello, 0) go common.Write(pipe, sessionId, "tunnel_msg_s", string(ansmsg.buf[:ansmsg.mlen])) session.status = "ok" session.recvMsg = string(tail) callback() return } }() } else { //log.Println("wait hello") } return case "ok": return } session.processSockProxy(sc, sessionId, "", callback) }
func main() { flag.Parse() checkDns = make(chan *dnsQueryReq) checkDnsRes = make(chan *dnsQueryBack) go dnsLoop() if *bShowVersion { fmt.Printf("%.2f\n", common.Version) return } if !*bVerbose { log.SetOutput(ioutil.Discard) } if *dataShards < 0 || *dataShards >= 128 { println("-ds should in [0-127]") return } if *parityShards < 0 || *parityShards >= 128 { println("-ds should in [0-127]") return } if *serveName == "" && *linkName == "" { println("you must assign reg or link") return } if *serveName != "" && *linkName != "" { println("you must assign reg or link, not both of them") return } if *localAddr == "" { println("you must assign the local addr") return } if *serveName != "" { clientType = 0 } else { clientType = 1 } if *bEncrypt { if clientType != 1 { println("only link size need encrypt") return } } go func() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) n := 0 for { <-c log.Println("received signal,shutdown") bForceQuit = true if remoteConn != nil { remoteConn.Close() } n++ if n > 5 { log.Println("force shutdown") os.Exit(-1) } } }() loop := func() bool { if bForceQuit { return true } g_ClientMap = make(map[string]*Client) g_ClientMapKey = make(map[string]*cipher.Block) g_Id2UDPSession = make(map[string]*UDPMakeSession) //var err error if *bUseSSL { _remoteConn, err := tls.Dial("tcp", *serverAddr, &tls.Config{InsecureSkipVerify: true}) if err != nil { println("connect remote err:" + err.Error()) return false } remoteConn = net.Conn(_remoteConn) } else { _remoteConn, err := net.DialTimeout("tcp", *serverAddr, 10*time.Second) if err != nil { println("connect remote err:" + err.Error()) return false } remoteConn = _remoteConn } println("connect to server succeed") go connect() q := make(chan bool) go func() { c := time.NewTicker(time.Second * 10) out: for { select { case <-c.C: if remoteConn != nil { common.Write(remoteConn, "-1", "ping", "") } case <-q: break out } } c.Stop() }() common.Read(remoteConn, handleResponse) q <- true for clientId, client := range g_ClientMap { log.Println("client shutdown", clientId) client.Quit() } for _, session := range g_Id2UDPSession { if session.engine != nil { session.engine.Fail() } } if remoteConn != nil { remoteConn.Close() } if bForceQuit { return true } return false } if clientType == 0 { for { if loop() { break } time.Sleep(10 * time.Second) } } else { loop() } log.Println("service shutdown") }
func (session *UDPMakeSession) beginMakeHole(content string) { engine := session.engine if engine == nil { return } addrList := content if session.buster { engine.SetOtherAddrList(addrList) } log.Println("begin bust", session.id, session.sessionId, session.buster) if clientType == 1 && !session.buster { log.Println("retry bust!") } report := func() { if session.buster { if session.delay > 0 { log.Println("try to delay", session.delay, "seconds") time.Sleep(time.Duration(session.delay) * time.Second) } go common.Write(remoteConn, session.id, "success_bust_a", "") } } oldSession := session var aesBlock *cipher.Block if clientType == 1 { aesBlock = aesKey } else { aesBlock, _ = g_ClientMapKey[session.sessionId] } var conn net.Conn var err error if aesBlock == nil { conn, err = engine.GetConn(report, nil, nil) } else { conn, err = engine.GetConn(report, func(s []byte) []byte { if aesBlock == nil { return s } else { padLen := aes.BlockSize - (len(s) % aes.BlockSize) for i := 0; i < padLen; i++ { s = append(s, byte(padLen)) } srcLen := len(s) encryptText := make([]byte, srcLen+aes.BlockSize) iv := encryptText[srcLen:] for i := 0; i < len(iv); i++ { iv[i] = byte(i) } mode := cipher.NewCBCEncrypter(*aesBlock, iv) mode.CryptBlocks(encryptText[:srcLen], s) return encryptText } }, func(s []byte) []byte { if aesBlock == nil { return s } else { if len(s) < aes.BlockSize*2 || len(s)%aes.BlockSize != 0 { return []byte{} } srcLen := len(s) - aes.BlockSize decryptText := make([]byte, srcLen) iv := s[srcLen:] mode := cipher.NewCBCDecrypter(*aesBlock, iv) mode.CryptBlocks(decryptText, s[:srcLen]) paddingLen := int(decryptText[srcLen-1]) if paddingLen > 16 { return []byte{} } return decryptText[:srcLen-paddingLen] } }) } session, _bHave := g_Id2UDPSession[session.id] if session != oldSession { return } if !_bHave { return } delete(g_Id2UDPSession, session.id) if err == nil { if !session.buster { common.Write(remoteConn, session.id, "makeholeok", "") } client, bHave := g_ClientMap[session.sessionId] if !bHave { client = &Client{id: session.sessionId, engine: session.engine, buster: session.buster, ready: true, bUdp: true, sessions: make(map[string]*clientSession), specPipes: make(map[string]net.Conn), pipes: make(map[int]net.Conn)} g_ClientMap[session.sessionId] = client } if isCommonSessionId(session.pipeType) { size := len(client.pipes) client.pipes[size] = conn go client.Run(size, "") log.Println("add common session", session.buster, session.sessionId, session.id) if clientType == 1 { if len(client.pipes) == *pipeNum { client.MultiListen() } } } else { client.specPipes[session.pipeType] = conn go client.Run(-1, session.pipeType) log.Println("add session for", session.pipeType) } } else { delete(g_ClientMap, session.sessionId) delete(g_ClientMapKey, session.sessionId) log.Println("cannot connect", err.Error()) if !session.buster && err.Error() != "quit" { common.Write(remoteConn, session.id, "makeholefail", "") } } }
func (sc *Client) OnTunnelRecv(pipe net.Conn, sessionId string, action string, content string) { //println("recv p2p tunnel", sessionId, action, content) session := sc.getSession(sessionId) var conn net.Conn if session != nil { conn = session.localConn } switch action { case "tunnel_error": if conn != nil { conn.Write([]byte(content)) log.Println("tunnel error", content, sessionId) } sc.removeSession(sessionId) //case "serve_begin": case "tunnel_msg_s": if conn != nil { //println("tunnel msg", sessionId, len(content)) conn.Write([]byte(content)) } else { //log.Println("cannot tunnel msg", sessionId) } case "tunnel_close_s": sc.removeSession(sessionId) case "ping", "pingback": //log.Println("recv", action) if action == "ping" { common.Write(pipe, sessionId, "pingback", "") } case "tunnel_msg_c": if conn != nil { //log.Println("tunnel", len(content), sessionId) conn.Write([]byte(content)) } else if *localAddr == "socks5" { if session == nil { return } session.processSockProxy(sc, sessionId, content, func() { sc.OnTunnelRecv(pipe, sessionId, action, session.recvMsg) }) } case "tunnel_close": sc.removeSession(sessionId) case "tunnel_open": if clientType == 0 { if *localAddr != "socks5" { s_conn, err := net.DialTimeout("tcp", *localAddr, 10*time.Second) if err != nil { log.Println("connect to local server fail:", err.Error()) msg := "cannot connect to bind addr" + *localAddr common.Write(pipe, sessionId, "tunnel_error", msg) //remoteConn.Close() return } else { sc.sessionLock.Lock() sc.sessions[sessionId] = &clientSession{pipe: pipe, localConn: s_conn} sc.sessionLock.Unlock() go handleLocalPortResponse(sc, sessionId) } } else { sc.sessionLock.Lock() sc.sessions[sessionId] = &clientSession{pipe: pipe, localConn: nil, status: "init", recvMsg: ""} sc.sessionLock.Unlock() } } } }
func handleResponse(conn net.Conn, id string, action string, content string) { //log.Println("got", id, action, content) common.GetClientInfoByConn(conn, func(client *common.ClientInfo) { client.ResponseTime = time.Now().Unix() }, func() { }) switch action { case "init": clientInfoStr := content var clientInfo common.ClientSetting err := json.Unmarshal([]byte(clientInfoStr), &clientInfo) if err != nil { log.Println("error decode clientinfo, kick out", conn.RemoteAddr().String()) common.Write(conn, "0", "showandquit", "server decode clientInfo error") return } if common.Version != clientInfo.Version { s_version := fmt.Sprintf("%.2f", common.Version) c_version := fmt.Sprintf("%.2f", clientInfo.Version) log.Println("version not eq", conn.RemoteAddr().String(), s_version, c_version) common.Write(conn, "0", "showandquit", "client version:"+c_version+" not eq with server:"+s_version) return } ServerName := clientInfo.Name if clientInfo.ClientType == "reg" { var user *auth.User if bUseDB { if clientInfo.AccessKey == "" { user, _ = auth.GetUser("test") } else { user, _ = auth.GetUserByKey(clientInfo.AccessKey) } } else { user = &auth.User{UserType: auth.UserType_Admin} } //fmt.Printf("%+v\n", user) if user == nil { common.Write(conn, "0", "showandquit", "invalid user accessKey:"+clientInfo.AccessKey+"!!!") return } if !user.CheckOnlineServiceNum() { common.Write(conn, "0", "showandquit", "online service num cannot overstep "+strconv.Itoa(user.MaxOnlineServerNum)) return } if !user.CheckIpLimit(conn.RemoteAddr().(*net.TCPAddr).IP.String()) { common.Write(conn, "0", "showandquit", "ip limit service num cannot overstep "+strconv.Itoa(user.MaxSameIPServers)) return } f := func() { common.ServerName2Conn[ServerName] = conn common.GetClientInfoByConn(conn, func(info *common.ClientInfo) { info.ServerName = ServerName info.IsServer = true info.Id2MakeSession = make(map[string]*common.UDPMakeSession) info.UserName = user.UserName info.ClientKey = clientInfo.ClientKey }, func() {}) log.Println("client reg service success", conn.RemoteAddr().String(), user.UserName, ServerName) common.Write(conn, "0", "show", "register service ok, user:"******"force unregister service Name", server.ServerName) if bUseDB { user, _ := auth.GetUser(server.UserName) if user != nil { user.OnLogout() } } delete(common.Conn2ClientInfo, _conn) common.Write(_conn, "0", "showandquit", "some one kick you out") _conn.Close() f() } else { common.Write(conn, "0", "showandretry", "already have the ServerName!") } }, f) } else if clientInfo.ClientType == "link" { if clientInfo.Mode < 0 || clientInfo.Mode > 2 { clientInfo.Mode = 0 } ServerName := clientInfo.Name bAuth := true common.GetClientInfoByName(ServerName, func(info *common.ClientInfo) { var user *auth.User if bUseDB { user, _ = auth.GetUser(info.UserName) } else { user = &auth.User{UserType: auth.UserType_Admin} } //fmt.Printf("%+v\n", user) if user == nil { common.Write(conn, "0", "showandquit", "invalid user:"******"!!!") bAuth = false return } if info.ClientKey != clientInfo.ClientKey { common.Write(conn, "0", "showandquit", "clientkey invalid!!!") bAuth = false return } if !user.CheckSessionNum(len(info.ClientMap)) { common.Write(conn, "0", "showandquit", "session numcannot overstep "+strconv.Itoa(len(info.ClientMap))) bAuth = false return } if !user.CheckPipeNum(clientInfo.PipeNum) { common.Write(conn, "0", "showandquit", "pipenum cannot overstep "+strconv.Itoa(user.MaxPipeNum)) bAuth = false return } }, func() { common.Write(conn, "0", "showandquit", "serverName invalid!!!") bAuth = false }) if !bAuth { return } common.GetClientInfoByConn(conn, func(client *common.ClientInfo) { client.ServerName = ServerName }, func() { }) common.GetClientInfoByName(ServerName, func(server *common.ClientInfo) { log.Println("client link service success", conn.RemoteAddr().String(), ServerName) server.AddClient(conn, clientInfo) }, func() { common.Write(conn, "0", "showandquit", "donnt have this service name") }) } case "tunnel_error": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { log.Println("<<=====tunnel_error", server.ServerName, conn.RemoteAddr().String()) session, bHave := server.Id2Session[id] if bHave { session.Status = "fail" common.Write(session.ClientA, "0", "showandquit", content) server.DelClient(session.ClientA) } }, func() { }) case "makeholefail": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { udpsession, bHave := server.Id2MakeSession[id] if bHave { log.Println("<<=====make hole fail", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.SessionId, id) sessionId := udpsession.SessionId session, _bHave := server.Id2Session[sessionId] if _bHave { session.Status = "fail" session.MakeHoleResponseN++ session.MakeHoleHasFail = true if session.MakeHoleResponseN == session.Setting.PipeNum { if session.Method == "udp" { session.RestartSession(server.ServerName) } else if session.Method == "restart" { if session.Setting.Mode == 0 { tmp := session.ClientA session.ClientA = session.ClientB session.ClientB = tmp session.StartCSMode() } else { server.DelClient(session.ClientB) } } else { server.DelClient(session.ClientA) } } } udpsession.Remove(false) } }, func() { }) case "makeholeok": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { if content == "csmode" { session, _bHave := server.Id2Session[id] if _bHave { log.Println("<<=====make hole ok", conn.RemoteAddr().String(), server.ServerName, session.Id) session.Status = "ok" session.MakeHoleResponseN++ } } udpsession, bHave := server.Id2MakeSession[id] if bHave { log.Println("<<=====make hole ok", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.SessionId, id) sessionId := udpsession.SessionId session, _bHave := server.Id2Session[sessionId] if _bHave { session.MakeHoleResponseN++ if session.MakeHoleResponseN == session.Setting.PipeNum { if !session.MakeHoleHasFail { session.Status = "ok" } } } udpsession.Remove(false) } }, func() { }) case "report_addrlist": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { udpsession, bHave := server.Id2MakeSession[id] //log.Println("test", udpsession, id, server.ServerName) if bHave { log.Println("<<===report addr list ok", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.Id) udpsession.BeginMakeHole(1, content) } }, func() { }) case "success_bust_a": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { udpsession, bHave := server.Id2MakeSession[id] if bHave { log.Println("<<=====success_bust_a", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.SessionId, id) udpsession.BeginMakeHole(2, content) } }, func() { }) // for c/s mode case "tunnel_close": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { session := server.GetSession(conn) if session != nil { common.Write(session.ClientB, session.Id+"-"+id, "csmode_s_tunnel_close", content) } else { println("no session") } }, func() { }) case "tunnel_open": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { session := server.GetSession(conn) if session != nil { common.Write(session.ClientB, session.Id+"-"+id, "csmode_s_tunnel_open", content) } else { println("no session") } }, func() { }) case "tunnel_msg_c": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { var user *auth.User if bUseDB { user, _ = auth.GetUser(server.UserName) } else { user = &auth.User{UserType: auth.UserType_Admin} } if user == nil { common.Write(conn, "0", "showandquit", "cannot get userinfo of this service "+server.UserName) return } if !user.UpdateCSMode(len(content)) { common.Write(conn, "0", "showandquit", "reach today's csmode data limit") return } session := server.GetSession(conn) if session != nil { common.Write(session.ClientB, session.Id+"-"+id, "csmode_msg_c", content) } else { println("no session") } }, func() { }) case "tunnel_msg_s": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { var user *auth.User if bUseDB { user, _ = auth.GetUser(server.UserName) } else { user = &auth.User{UserType: auth.UserType_Admin} } if user == nil { common.Write(conn, "0", "showandquit", "cannot get userinfo of this service"+server.UserName) return } if !user.UpdateCSMode(len(content)) { common.Write(conn, "0", "show", "reach today's csmode data limit") return } arr := strings.Split(id, "-") clientId := arr[0] session, bHave := server.Id2Session[clientId] if bHave { common.Write(session.ClientA, id, "csmode_msg_s", content) } else { println("no session") } }, func() { }) case "tunnel_close_s": common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { arr := strings.Split(id, "-") clientId := arr[0] session, bHave := server.Id2Session[clientId] if bHave { common.Write(session.ClientA, id, "csmode_c_tunnel_close", content) } else { println("no session") } }, func() { }) } }