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  }