github.com/polarismesh/polaris@v1.17.8/apiserver/l5pbserver/naming.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package l5pbserver 19 20 import ( 21 "bufio" 22 "context" 23 "encoding/binary" 24 "io" 25 "net" 26 "time" 27 28 "github.com/golang/protobuf/proto" 29 "go.uber.org/zap" 30 31 "github.com/polarismesh/polaris/common/api/l5" 32 "github.com/polarismesh/polaris/common/model" 33 ) 34 35 type l5Code uint32 36 37 const ( 38 l5Success l5Code = iota 39 l5ResponseFailed 40 l5UnmarshalPacketFailed 41 l5SyncByAgentCmdFailed 42 l5RegisterByNameCmdFailed 43 l5MarshalPacketFailed 44 l5PacketCmdFailed 45 ) 46 47 // handleConnection 连接处理的协程函数 48 // 每个客户端会新建一个协程 49 // 使用方法 go handleConnection(conn) 50 func (l *L5pbserver) handleConnection(conn net.Conn) { 51 defer conn.Close() 52 53 req := &cl5Request{ 54 conn: conn, 55 clientAddr: conn.RemoteAddr().String(), 56 } 57 58 // 先读取头部数据,然后再根据packetLength读取body数据 59 header := make([]byte, headSize) 60 bufRead := bufio.NewReader(conn) 61 for { 62 if _, err := io.ReadFull(bufRead, header); err != nil { 63 // end of the reader 64 if err == io.EOF { 65 return 66 } 67 log.Errorf("[Cl5] read header from conn(%s) err: %s", req.clientAddr, err.Error()) 68 return 69 } 70 packetLength := checkRequest(header) 71 if packetLength <= headSize || packetLength > maxSize { // 包大小检查 72 log.Errorf("[Cl5] read header from conn(%s) found body length(%d) invalid", 73 req.clientAddr, packetLength) 74 return 75 } 76 body := make([]byte, packetLength-headSize) 77 if _, err := io.ReadFull(bufRead, body); err != nil { 78 log.Errorf("[Cl5] read body from conn(%s) err: %s", req.clientAddr, err.Error()) 79 return 80 } 81 if code := l.handleRequest(req, body); code != l5Success { 82 log.Error("[CL5] catch error code", zap.Uint32("code", uint32(code)), 83 zap.String("client", req.clientAddr)) 84 return 85 } 86 } 87 } 88 89 // handleRequest cl5请求的handle入口 90 func (l *L5pbserver) handleRequest(req *cl5Request, requestData []byte) l5Code { 91 req.start = time.Now() // 从解包开始计算开始时间 92 cl5Pkg := &l5.Cl5Pkg{} 93 err := proto.Unmarshal(requestData, cl5Pkg) 94 if err != nil { 95 log.Errorf("[Cl5] client(%s) Unmarshal requestData error: %v", 96 req.clientAddr, err) 97 return l5UnmarshalPacketFailed 98 } 99 100 req.cmd = cl5Pkg.GetCmd() 101 l.PreProcess(req) 102 switch cl5Pkg.GetCmd() { 103 case int32(l5.CL5_CMD_CL5_REGISTER_BY_NAME_CMD): 104 req.code = l.handleRegisterByNameCmd(req.conn, cl5Pkg) 105 case int32(l5.CL5_CMD_CL5_SYNC_BY_AGENT_CMD): 106 req.code = l.handleSyncByAgentCmd(req.conn, cl5Pkg) 107 default: 108 log.Errorf("receive invalid cmd[%d] from [%d]", cl5Pkg.GetCmd(), cl5Pkg.GetIp()) 109 req.code = l5PacketCmdFailed 110 } 111 l.PostProcess(req) 112 return req.code 113 } 114 115 // handleSyncByAgentCmd 根据SID列表获取路由信息 116 func (l *L5pbserver) handleSyncByAgentCmd(conn net.Conn, iPkg *l5.Cl5Pkg) l5Code { 117 ctx := context.Background() 118 ctx = context.WithValue(ctx, model.Cl5ServerCluster{}, l.clusterName) 119 ctx = context.WithValue(ctx, model.Cl5ServerProtocol{}, l.GetProtocol()) 120 syncByAgentAck, err := l.namingServer.SyncByAgentCmd(ctx, iPkg.GetSyncByAgentCmd()) 121 if err != nil { 122 log.Errorf("%v", err) 123 return l5SyncByAgentCmdFailed 124 } 125 126 oPkg := &l5.Cl5Pkg{ 127 Seqno: proto.Int32(iPkg.GetSeqno()), 128 Cmd: proto.Int32(int32(l5.CL5_CMD_CL5_SYNC_BY_AGENT_ACK_CMD)), 129 Result: proto.Int32(success), 130 Ip: proto.Int32(iPkg.GetIp()), 131 SyncByAgentAckCmd: syncByAgentAck, 132 } 133 134 log.Infof("handle sync by agent cmd, sid count(%d), callee count(%d), ip count(%d)", 135 len(iPkg.GetSyncByAgentCmd().GetOptList().GetOpt()), 136 len(oPkg.GetSyncByAgentAckCmd().GetServList().GetServ()), 137 len(oPkg.GetSyncByAgentAckCmd().GetIpcList().GetIpc())) 138 return response(conn, oPkg) 139 } 140 141 // handleRegisterByNameCmd 根据服务名列表寻找对应的SID列表 142 func (l *L5pbserver) handleRegisterByNameCmd(conn net.Conn, iPkg *l5.Cl5Pkg) l5Code { 143 registerByNameAck, err := l.namingServer.RegisterByNameCmd(iPkg.GetRegisterByNameCmd()) 144 if err != nil { 145 log.Errorf("%v", err) 146 return l5RegisterByNameCmdFailed 147 } 148 149 oPkg := &l5.Cl5Pkg{ 150 Seqno: proto.Int32(iPkg.GetSeqno()), 151 Cmd: proto.Int32(int32(l5.CL5_CMD_CL5_REGISTER_BY_NAME_ACK_CMD)), 152 Result: proto.Int32(success), 153 Ip: proto.Int32(iPkg.GetIp()), 154 RegisterByNameAckCmd: registerByNameAck, 155 } 156 157 return response(conn, oPkg) 158 } 159 160 // checkRequest 请求包完整性检查 161 func checkRequest(buffer []byte) int { 162 var length uint32 163 isLittle := isLittleEndian() 164 if isLittle { 165 length = binary.LittleEndian.Uint32(buffer[sohSize:headSize]) 166 } else { 167 length = binary.BigEndian.Uint32(buffer[sohSize:headSize]) 168 } 169 170 return int(length) 171 } 172 173 func response(conn net.Conn, pkg *l5.Cl5Pkg) l5Code { 174 responseData, err := proto.Marshal(pkg) 175 if err != nil { 176 log.Errorf("Marshal responseData error: %v", err) 177 return l5MarshalPacketFailed 178 } 179 180 sohData := make([]byte, 2) 181 lengthData := make([]byte, 4) 182 var soh uint16 = 1 183 length := uint32(binary.Size(responseData) + headSize) 184 185 isLittle := isLittleEndian() 186 if isLittle { 187 binary.LittleEndian.PutUint16(sohData, soh) 188 binary.LittleEndian.PutUint32(lengthData, length) 189 } else { 190 binary.BigEndian.PutUint16(sohData, soh) 191 binary.BigEndian.PutUint32(lengthData, length) 192 } 193 194 sohData = append(sohData, lengthData...) 195 sohData = append(sohData, responseData...) 196 197 if _, err = conn.Write(sohData); err != nil { 198 log.Errorf("conn write error: %v", err) 199 return l5ResponseFailed 200 } 201 return l5Success 202 } 203 204 // isLittleEndian 判断系统是大端/小端存储 205 func isLittleEndian() bool { 206 a := int16(0x1234) 207 b := int8(a) 208 209 return 0x34 == b 210 }