github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/gonet/trans_server.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  // Package gonet contains server and client implementation for go net.
    18  package gonet
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"net"
    24  	"os"
    25  	"runtime/debug"
    26  	"sync"
    27  	"time"
    28  
    29  	"github.com/cloudwego/netpoll"
    30  
    31  	"github.com/cloudwego/kitex/pkg/remote/trans"
    32  
    33  	"github.com/cloudwego/kitex/pkg/klog"
    34  	"github.com/cloudwego/kitex/pkg/remote"
    35  	"github.com/cloudwego/kitex/pkg/rpcinfo"
    36  	"github.com/cloudwego/kitex/pkg/utils"
    37  )
    38  
    39  // NewTransServerFactory creates a default go net transport server factory.
    40  func NewTransServerFactory() remote.TransServerFactory {
    41  	return &gonetTransServerFactory{}
    42  }
    43  
    44  type gonetTransServerFactory struct{}
    45  
    46  // NewTransServer implements the remote.TransServerFactory interface.
    47  func (f *gonetTransServerFactory) NewTransServer(opt *remote.ServerOption, transHdlr remote.ServerTransHandler) remote.TransServer {
    48  	return &transServer{
    49  		opt:       opt,
    50  		transHdlr: transHdlr,
    51  		lncfg:     trans.NewListenConfig(opt),
    52  	}
    53  }
    54  
    55  type transServer struct {
    56  	opt       *remote.ServerOption
    57  	transHdlr remote.ServerTransHandler
    58  	ln        net.Listener
    59  	lncfg     net.ListenConfig
    60  	connCount utils.AtomicInt
    61  	sync.Mutex
    62  }
    63  
    64  var _ remote.TransServer = &transServer{}
    65  
    66  // CreateListener implements the remote.TransServer interface.
    67  // The network must be "tcp", "tcp4", "tcp6" or "unix".
    68  func (ts *transServer) CreateListener(addr net.Addr) (ln net.Listener, err error) {
    69  	ln, err = ts.lncfg.Listen(context.Background(), addr.Network(), addr.String())
    70  	return ln, err
    71  }
    72  
    73  // BootstrapServer implements the remote.TransServer interface.
    74  func (ts *transServer) BootstrapServer(ln net.Listener) (err error) {
    75  	if ln == nil {
    76  		return errors.New("listener is nil in gonet transport server")
    77  	}
    78  	ts.ln = ln
    79  	for {
    80  		conn, err := ts.ln.Accept()
    81  		if err != nil {
    82  			klog.Errorf("KITEX: BootstrapServer accept failed, err=%s", err.Error())
    83  			os.Exit(1)
    84  		}
    85  		go func() {
    86  			var (
    87  				ctx = context.Background()
    88  				err error
    89  			)
    90  			defer func() {
    91  				transRecover(ctx, conn, "OnRead")
    92  			}()
    93  			bc := newBufioConn(conn)
    94  			ctx, err = ts.transHdlr.OnActive(ctx, bc)
    95  			if err != nil {
    96  				klog.CtxErrorf(ctx, "KITEX: OnActive error=%s", err)
    97  				return
    98  			}
    99  			for {
   100  				ts.refreshDeadline(rpcinfo.GetRPCInfo(ctx), bc)
   101  				err := ts.transHdlr.OnRead(ctx, bc)
   102  				if err != nil {
   103  					ts.onError(ctx, err, bc)
   104  					_ = bc.Close()
   105  					return
   106  				}
   107  			}
   108  		}()
   109  	}
   110  }
   111  
   112  // Shutdown implements the remote.TransServer interface.
   113  func (ts *transServer) Shutdown() (err error) {
   114  	ts.Lock()
   115  	defer ts.Unlock()
   116  
   117  	ctx, cancel := context.WithTimeout(context.Background(), ts.opt.ExitWaitTime)
   118  	defer cancel()
   119  	if g, ok := ts.transHdlr.(remote.GracefulShutdown); ok {
   120  		if ts.ln != nil {
   121  			// 1. stop listener
   122  			_ = ts.ln.Close()
   123  
   124  			// 2. signal all active connections to close gracefully
   125  			_ = g.GracefulShutdown(ctx)
   126  		}
   127  	}
   128  	return
   129  }
   130  
   131  // ConnCount implements the remote.TransServer interface.
   132  func (ts *transServer) ConnCount() utils.AtomicInt {
   133  	return ts.connCount
   134  }
   135  
   136  func (ts *transServer) onError(ctx context.Context, err error, conn net.Conn) {
   137  	ts.transHdlr.OnError(ctx, err, conn)
   138  }
   139  
   140  func (ts *transServer) refreshDeadline(ri rpcinfo.RPCInfo, conn net.Conn) {
   141  	readTimeout := ri.Config().ReadWriteTimeout()
   142  	_ = conn.SetReadDeadline(time.Now().Add(readTimeout))
   143  }
   144  
   145  // bufioConn implements the net.Conn interface.
   146  type bufioConn struct {
   147  	conn net.Conn
   148  	r    netpoll.Reader
   149  }
   150  
   151  func newBufioConn(c net.Conn) *bufioConn {
   152  	return &bufioConn{
   153  		conn: c,
   154  		r:    netpoll.NewReader(c),
   155  	}
   156  }
   157  
   158  func (bc *bufioConn) RawConn() net.Conn {
   159  	return bc.conn
   160  }
   161  
   162  func (bc *bufioConn) Read(b []byte) (int, error) {
   163  	buf, err := bc.r.Next(len(b))
   164  	if err != nil {
   165  		return 0, err
   166  	}
   167  	copy(b, buf)
   168  	return len(b), nil
   169  }
   170  
   171  func (bc *bufioConn) Write(b []byte) (int, error) {
   172  	return bc.conn.Write(b)
   173  }
   174  
   175  func (bc *bufioConn) Close() error {
   176  	bc.r.Release()
   177  	return bc.conn.Close()
   178  }
   179  
   180  func (bc *bufioConn) LocalAddr() net.Addr {
   181  	return bc.conn.LocalAddr()
   182  }
   183  
   184  func (bc *bufioConn) RemoteAddr() net.Addr {
   185  	return bc.conn.RemoteAddr()
   186  }
   187  
   188  func (bc *bufioConn) SetDeadline(t time.Time) error {
   189  	return bc.conn.SetDeadline(t)
   190  }
   191  
   192  func (bc *bufioConn) SetReadDeadline(t time.Time) error {
   193  	return bc.conn.SetReadDeadline(t)
   194  }
   195  
   196  func (bc *bufioConn) SetWriteDeadline(t time.Time) error {
   197  	return bc.conn.SetWriteDeadline(t)
   198  }
   199  
   200  func (bc *bufioConn) Reader() netpoll.Reader {
   201  	return bc.r
   202  }
   203  
   204  func transRecover(ctx context.Context, conn net.Conn, funcName string) {
   205  	panicErr := recover()
   206  	if panicErr != nil {
   207  		if conn != nil {
   208  			klog.CtxErrorf(ctx, "KITEX: panic happened in %s, remoteAddress=%s, error=%v\nstack=%s", funcName, conn.RemoteAddr(), panicErr, string(debug.Stack()))
   209  		} else {
   210  			klog.CtxErrorf(ctx, "KITEX: panic happened in %s, error=%v\nstack=%s", funcName, panicErr, string(debug.Stack()))
   211  		}
   212  	}
   213  }