func WebsocketHandler(w http.ResponseWriter, r *http.Request) { log.Info("WebsocketHandler:%s %s %s", r.RemoteAddr, r.Method, r.URL.Path) if !authOK(r) { log.Warn("auth fail....") noAuthResponse(w) return } var conn *websocket.Conn conn, err := websocket.Upgrade(w, r, http.Header{}) if err != nil { log.Error(err.Error()) return } conn.SetReadDeadline(time.Time{}) conn.SetWriteDeadline(time.Time{}) var client = newWebsocketClient(conn, r) if pConfig.client_conf_forward_host == "" { log.Info("pConfig.client_conf_forward_host is empty. tell Client Need the Config.") client.tellClientNeedConfig() } log.Info("Put[%s] into the global Connect pool.", client) client.waitForFrameLoop() websocketClose(r) log.Debug("WebsocketHandler:%s closed.", r.RemoteAddr) }
func main() { flag.Parse() log.Info("start app, Read From[%s], forward data To[%s], auth[%s] log-level[%s].", _LocalNetworkHost, _ForwardServer, _AuthUserPassword, _LogLevel) log.SetLevelByName(_LogLevel) if _ForwardTHread < MIN_THREAD { _ForwardTHread = MIN_THREAD } conf := &cli.Config{ LocalHostServ: _LocalNetworkHost, WebsocketAuth: _AuthUserPassword, MaxThread: _ForwardTHread, } const ( default_sleep_time = 10 * time.Second ) for { cli.Connect2Serv(_ForwardServer, conf) if stop { break } else { log.Info("Connect2Serv fail, wait[%s]Second.", default_sleep_time) time.Sleep(default_sleep_time) } } log.Info("------------------- main end ------------------------") }
func bindConnection(conn net.Conn) error { // 与一个websocket 绑定一个连接 client, err := getFreeClient() if err != nil { return err } client.writerForward = conn.(io.WriteCloser) client.tellClientNewConnection() reader := conn.(io.Reader) p := make([]byte, 4096) for { n, err := reader.Read(p) if err != nil { if err != io.EOF { log.Error("Reading data from[%s] err=%s", conn.RemoteAddr(), err.Error()) } client.closeWriter() break } client.websocket.Write(p[:n], true) } log.Info("BindConnection Request finish.") return nil }
func (c *wsClient) handlerControlMessage(bFrame []byte) error { msg := ctrl.WebSocketControlFrame{} if err := json.Unmarshal(bFrame, &msg); err != nil { log.Warn("Recve a Text-Frame not JSON format. err=%v, frame=%v", err.Error(), string(bFrame)) return err } log.Debug("TCP[%v] Get Frame T[%v], Content=%v, index=%v, ", c, msg.TypeStr(), msg.Content, msg.Index) switch msg.Type { case ctrl.Msg_Request_Finish: c.closeWriter() case ctrl.Msg_Client_Busy: c.writerForward.Write([]byte("current client was busy, pls try anthor.")) c.closeWriter() case ctrl.Msg_Sys_Err: c.writerForward.Write([]byte(msg.Content)) c.closeWriter() case ctrl.Msg_Get_Config: log.Info("Get the Client- side local network server config[%s]", msg.Content) pConfig.client_conf_forward_host = msg.Content default: log.Warn("no handler Msg T[%s]", msg.TypeStr()) } return nil }
// URI: /api/ func httpApiHandler(w http.ResponseWriter, r *http.Request) { log.Info("api Handler: %s %s %s", r.Method, r.URL.RequestURI(), r.RemoteAddr, r.FormValue("svr")) if !authOK(r) { noAuthResponse(w) return } var status = 200 var resp string svr := r.FormValue("svr") if svr != "" && svr != pConfig.client_conf_forward_host { cli, err := getFreeClient() if cli == nil { resp = err.Error() } else { err := cli.tellClientSetConfig(svr) if err != nil { resp = err.Error() } else { resp = fmt.Sprintf("Set [%s] OK", svr) } } } setSTDheader(w) w.WriteHeader(status) io.WriteString(w, resp) }
func ListenIPForwardAndWebsocketServ(forwardHostAndPort, websocketHostAndPort string, conf *Config) { if conf == nil { panic("config is nil.") } pConfig = conf if pConfig.Auth != "" { pConfig.Auth = fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(pConfig.Auth))) } go listenWebsocketServ(websocketHostAndPort, ctrl.WEBSOCKET_CONNECT_URI, WEBSOCKET_CONTORL_URI) l, err := net.Listen("tcp", forwardHostAndPort) if err != nil { log.Error(err.Error()) } defer l.Close() log.Debug("IP Forward Listening TCP[%s]", forwardHostAndPort) for { conn, err := l.Accept() if err != nil { log.Error("IP-Forward Accept err=%s", err.Error()) continue } // handle socket data recv and send go ipforward(conn) } log.Info("ListenAndIPForwardServ exit.") }
func (c *Client) newConnect2LoalNetwork() error { if pConfig.currThread < pConfig.MaxThread { go Connect2Serv(pConfig.orwardServ, pConfig) } // 与本地局域网服务器g_localForwardHostAndPort 建立socket连接 c.rw.Lock() defer c.rw.Unlock() if c.localConn != nil { log.Warn("[%s], thread is busy. can not create new connect.", c) c.tellServBusy() return fmt.Errorf("[%s] thread is busy. can not create new connect.", c) } conn, err := net.Dial("tcp", g_localForwardHostAndPort) if err != nil { log.Error("[%s] Connect to[%s] err=%s", c, g_localForwardHostAndPort, err.Error()) c.tellServError(err) return err } go c.readForward(conn) c.localConn = &conn c.forwardData = make(chan []byte, Default_Channel_Size*4) go c.writerForward(conn) log.Info("new connection was create [%s]", conn.RemoteAddr()) return nil }
// 从客户端读取信息 func (this *Connect) PullFromClient() { for { defer func() { if err := recover(); err != nil { log.Critical("Panic occur. %v", err) this.Send(lineNum(), fmt.Sprintf("%v", err)) this.PullFromClient() } }() var content []byte err := websocket.Message.Receive(this.Conn, &content) if err != nil { log.Info("Websocket Error: %v", err) playerMap.Delete(this.Uid, this) return } beginTime := time.Now() log.Info(" Begin ") // parse proto message this.Request, err = ParseContent(content) if err != nil { log.Error("Parse client request error. %v", err) this.Send(lineNum(), err) continue } if this.Request.GetCmdId() != LOGIN { if !this.verify(this.Request.GetTokenStr()) { continue } } this.Function(this.Request.GetCmdId())() execTime := time.Now().Sub(beginTime) if execTime.Seconds() > 0.1 { // slow log log.Warn("Slow Exec , time is %v second", execTime.Seconds()) } else { log.Info("time is %v second", execTime.Seconds()) } } }
func (client *wsClient) waitForFrameLoop() { for { frameType, bFrame, err := client.websocket.Read() log.Debug("TCP[%s] recv WebSocket Frame typ=[%v] size=[%d], crc32=[%d]", client, frameTypStr(frameType), len(bFrame), crc32.ChecksumIEEE(bFrame)) if err != nil { if err != io.ErrUnexpectedEOF { log.Error("TCP[%s] close Unexpected err=%v", client, err.Error()) } else { log.Debug("TCP[%s] close the socket. EOF.", client) } client.closeWriter() return } switch frameType { case websocket.TextMessage: client.handlerControlMessage(bFrame) case websocket.CloseMessage: log.Info("TCP[%s] close Frame revced. end wait Frame loop", client) client.closeWriter() return case websocket.BinaryMessage: log.Info("TCP[%s] resv-binary: %v", client, len(bFrame)) if client.writerForward == nil { log.Warn("client.writerForward is nil.") continue } _, err := client.writerForward.Write(bFrame) if err != nil { if err != io.EOF { log.Error(err.Error()) } client.tellClientRequestFinish() client.closeWriter() } case websocket.PingMessage, websocket.PongMessage: // IE-11 会无端端发一个pong上来 client.websocket.Pong(bFrame) default: log.Warn("TODO: revce frame-type=%v. can not handler. content=%v", frameTypStr(frameType), string(bFrame)) } } }
func init() { rand.Seed(time.Now().UnixNano()) gameToken = token.NewToken(token.NewAdapter()) playerMap = new(PlayerMap) playerMap.Lock = new(sync.RWMutex) playerMap.Map = make(map[int64]*Connect) request_log_map = make(map[int32]string) CountOnline() log.Info("Program Run !") }
func (client *Client) waitForCommand() { for { frameType, bFrame, err := client.webSocket.Read() log.Debug("TCP[%s] recv WebSocket Frame typ=[%v] size=[%d], crc32=[%d]", client, frameTypStr(frameType), len(bFrame), crc32.ChecksumIEEE(bFrame)) if err != nil { if err != io.ErrUnexpectedEOF { log.Error("TCP[%s] close Unexpected err=%v", client, err.Error()) } else { log.Debug("TCP[%s] close the socket. EOF.", client) } client.closeLocalConnect() return } switch frameType { case websocket.CloseMessage: log.Info("TCP[%s] close Frame revced. end wait Frame loop", client) client.closeLocalConnect() return case websocket.TextMessage: err := client.handlerControlFrame(bFrame) if err != nil { log.Error("handlerControlFrame ret[%s]", err.Error()) } case websocket.BinaryMessage: log.Info("put Binary-Data to chan-len[%d]", len(client.forwardData)) select { case client.forwardData <- bFrame: log.Info("put frame to client.forwardData len[%d] end", len(client.forwardData)) default: log.Warn("[%s] is busy", client) client.tellServBusy() } case websocket.PingMessage, websocket.PongMessage: // IE-11 会无端端发一个pong上来 client.webSocket.Pong(bFrame) default: log.Warn("TODO: revce frame-type=%v. can not handler. content=%v", frameTypStr(frameType), string(bFrame)) } } }
func (this *Connect) pushToClient() { go func() { for s := range this.Chan { if _, err := this.Conn.Write(s); err != nil { log.Warn("Can't send msg. %v", err) } else { log.Info("Send Success") } } }() }
func authOK(req *http.Request) bool { if pConfig == nil && pConfig.Auth == "" { log.Info("did not need auth.") return true } var auth = req.Header.Get("Authorization") log.Debug("reuquest Auth->[%s]", auth) return auth == pConfig.Auth }
func Connect2Serv(forwardServ string, conf *Config) { if conf == nil { panic("config is nil.") } // global pConfig pConfig = conf pConfig.orwardServ = forwardServ var localServ, auth = conf.LocalHostServ, conf.WebsocketAuth setLocalForardHostAndPort(localServ) websockURI := ctrl.WEBSOCKET_CONNECT_URI log.Info("start TCP connect to[%s]", forwardServ) conn, err := net.Dial("tcp", forwardServ) if err != nil { log.Error("connect[%s] fail err=[%s]", forwardServ, err.Error()) return } var headers http.Header if auth != "" { headers = http.Header{} headers.Add("Authorization", fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(auth)))) } log.Info("start websocket NewClient to[%s][%s]", forwardServ, websockURI) ws, _, err := websocket.NewClient(conn, &url.URL{Host: forwardServ, Path: websockURI}, headers) if err != nil { log.Error("Connect to[%s] err=%s", forwardServ, err.Error()) return } client := NewClient(ws) log.Info("Connect[%s] success at[%s], wait for server command.", forwardServ, client) pConfig.currThread++ client.waitForCommand() pConfig.currThread-- log.Info("client thread exist.") }
func main() { flag.Parse() log.Info("app start forward[%s] websocket[%s] auth[%s] log-level[%s], ", _ForwardListtion, _Websocketlisten, _AuthUserPassword, _LogLevel) log.SetLevelByName(_LogLevel) var conf = &svr.Config{Auth: _AuthUserPassword} svr.ListenIPForwardAndWebsocketServ(_ForwardListtion, _Websocketlisten, conf) }
// URI: /admin/ func httpAdminHandler(w http.ResponseWriter, r *http.Request) { log.Info("admin Handler: %s %s %s", r.Method, r.URL.RequestURI(), r.RemoteAddr) if !authOK(r) { noAuthResponse(w) return } setSTDheader(w) resp := fmt.Sprintf(control_html, pConfig.client_conf_forward_host) io.WriteString(w, resp) }
func listenWebsocketServ(hostAndPort string, websocketURI, contorlURI string) { // TODO:连接认证 http.HandleFunc(websocketURI, WebsocketHandler) http.HandleFunc(contorlURI, httpAdminHandler) http.HandleFunc("/api/", httpApiHandler) log.Info("Websocket Listen in TCP[%s]", hostAndPort) svr := &http.Server{ Addr: hostAndPort, Handler: nil, ReadTimeout: 0 * time.Second, WriteTimeout: 0 * time.Second, MaxHeaderBytes: 1 << 20, // 1M } err := svr.ListenAndServe() if err != nil { log.Error("ListenAndServe[%v], err=[%v]", hostAndPort, err.Error()) } log.Info("ListenWebsocketServ exit.") }
func (c *Client) closeLoalNetworkConnection(isReader bool) { c.rw.Lock() defer c.rw.Unlock() if c.localConn == nil { return } if isReader { // 如果readForward函数先结束,writerForward 中的buff = <- c.forwardData会一直阻塞 // 此处发一个字节作信号,使 writerForward 退出 c.forwardData <- []byte("") } (*c.localConn).Close() c.tellServRequestFinish() log.Info("connection was close[%s]", (*c.localConn).RemoteAddr()) c.localConn = nil close(c.forwardData) }
func (c *Client) writerForward(writer io.Writer) { buff := make([]byte, Default_Buffer_Size) var err error for { buff = <-c.forwardData _, err = writer.Write(buff) if err != nil { break } } if err != nil && err != io.EOF { log.Error("Write to Local-network err=%s", err.Error()) } c.closeLoalNetworkConnection(false) log.Info("end writer forward.") }
func (c *Client) readForward(reader io.Reader) { // 从本地局域网连接中读取到数据,通过websocket的Binary帧方式发给服务器 p := make([]byte, Default_Buffer_Size) var err error for { n, err := reader.Read(p) if err != nil { break } c.Write(p[:n]) } if err != nil && err != io.EOF { log.Error("Write to Local-network err=%s", err.Error()) } c.closeLoalNetworkConnection(true) log.Info("end reader forward.") }
func (this *Connect) verify(token string) bool { if token == "" { this.Send(2, nil) return false } uid, _ := gameToken.GetUid(token) if uid == 0 { this.Send(2, nil) return false } if this.Role == nil { this.Uid = uid Role, err := models.Role.Role(uid) if err == sql.ErrNoRows { if Role, err = models.Role.NewRole(uid); err != nil { // 插入失败 return false } } else if err != nil { this.Send(lineNum(), err) return false } this.Role = Role playerMap.Set(uid, this) } else if this.Role.Uid != uid { this.Send(2, nil) return false } else { this.Role.UpdateDate() } log.Info("Exec -> %d (uid:%d)", this.Request.GetCmdId(), this.Uid) models.InsertRequestLog(this.Uid, this.Request.GetCmdId()) return true }
func (c *Client) handlerControlFrame(bFrame []byte) (err error) { msg := ctrl.WebSocketControlFrame{} if err = json.Unmarshal(bFrame, &msg); err != nil { log.Error("Recve a Text-Frame not JSON format. err=%v, frame=%v", err.Error(), string(bFrame)) return err } log.Info("TCP[%v] Get Frame T[%v], Content=%v, index=%v, ", c, msg.TypeStr(), msg.Content, msg.Index) switch msg.Type { case ctrl.Msg_New_Connection: c.newConnect2LoalNetwork() case ctrl.Msg_Request_Finish: c.closeLocalConnect() case ctrl.Msg_Get_Config: err = c.telServConfig() case ctrl.Msg_Set_Config: pConfig.LocalHostServ = msg.Content err = c.telServConfig() default: log.Warn("no handler Msg T[%s]", msg.TypeStr()) } return err }
func (this *Connect) Login() error { request := &protodata.LoginRequest{} if err := Unmarshal(this.Request.GetSerializedString(), request); err != nil { return this.Send(lineNum(), err) } platId := int(request.GetPlatId()) username := request.GetUsername() password := request.GetPassword() otherId := request.GetOtherId() otherData := request.GetOtherData() session := request.GetOtherSession() sign := request.GetOtherSign() var user *models.UserData if platId == 2 { // PP助手 otherId = ppLogin(session) if otherId == "" { return this.Send(lineNum(), fmt.Errorf("PP助手验证错误")) } } else { //else if platId == 4 { // 91助手 // if err := login91(otherId, session); err != nil { // return this.Send(lineNum(), err) // } //} else { var b bool otherId, b = otherLogin(platId, otherId, session, sign, otherData) if !b { return this.Send(lineNum(), fmt.Errorf("第三方验证错误")) } } user = models.User.GetUserByOtherId(otherId, platId) if user == nil { if platId == 0 { m := md5.New() m.Write([]byte(password)) password = hex.EncodeToString(m.Sum(nil)) } user = new(models.UserData) user.UserName = username user.Password = password user.OtherId = otherId user.Ip = request.GetIp() user.Imei = request.GetImei() user.PlatId = platId if err := user.Insert(); err != nil { return this.Send(lineNum(), err) } } else if platId == 0 { m := md5.New() m.Write([]byte(password)) password = hex.EncodeToString(m.Sum(nil)) if user.Password != password { return this.Send(lineNum(), fmt.Errorf("密码错误")) } } token, err := gameToken.AddToken(user.Uid) if err != nil { return this.Send(lineNum(), err) } log.Info("Exec -> login (uid:%d)", user.Uid) this.Uid = user.Uid if Role, err := models.Role.Role(user.Uid); err == nil { this.Role = Role } playerMap.Set(user.Uid, this) response := &protodata.LoginResponse{TokenStr: proto.String(token)} return this.Send(StatusOK, response) }