github.com/DFWallet/tendermint-cosmos@v0.0.2/abci/server/socket_server.go (about)

     1  package server
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  	"os"
     9  	"runtime"
    10  
    11  	"github.com/DFWallet/tendermint-cosmos/abci/types"
    12  	tmlog "github.com/DFWallet/tendermint-cosmos/libs/log"
    13  	tmnet "github.com/DFWallet/tendermint-cosmos/libs/net"
    14  	"github.com/DFWallet/tendermint-cosmos/libs/service"
    15  	tmsync "github.com/DFWallet/tendermint-cosmos/libs/sync"
    16  )
    17  
    18  // var maxNumberConnections = 2
    19  
    20  type SocketServer struct {
    21  	service.BaseService
    22  	isLoggerSet bool
    23  
    24  	proto    string
    25  	addr     string
    26  	listener net.Listener
    27  
    28  	connsMtx   tmsync.Mutex
    29  	conns      map[int]net.Conn
    30  	nextConnID int
    31  
    32  	appMtx tmsync.Mutex
    33  	app    types.Application
    34  }
    35  
    36  func NewSocketServer(protoAddr string, app types.Application) service.Service {
    37  	proto, addr := tmnet.ProtocolAndAddress(protoAddr)
    38  	s := &SocketServer{
    39  		proto:    proto,
    40  		addr:     addr,
    41  		listener: nil,
    42  		app:      app,
    43  		conns:    make(map[int]net.Conn),
    44  	}
    45  	s.BaseService = *service.NewBaseService(nil, "ABCIServer", s)
    46  	return s
    47  }
    48  
    49  func (s *SocketServer) SetLogger(l tmlog.Logger) {
    50  	s.BaseService.SetLogger(l)
    51  	s.isLoggerSet = true
    52  }
    53  
    54  func (s *SocketServer) OnStart() error {
    55  	ln, err := net.Listen(s.proto, s.addr)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	s.listener = ln
    61  	go s.acceptConnectionsRoutine()
    62  
    63  	return nil
    64  }
    65  
    66  func (s *SocketServer) OnStop() {
    67  	if err := s.listener.Close(); err != nil {
    68  		s.Logger.Error("Error closing listener", "err", err)
    69  	}
    70  
    71  	s.connsMtx.Lock()
    72  	defer s.connsMtx.Unlock()
    73  	for id, conn := range s.conns {
    74  		delete(s.conns, id)
    75  		if err := conn.Close(); err != nil {
    76  			s.Logger.Error("Error closing connection", "id", id, "conn", conn, "err", err)
    77  		}
    78  	}
    79  }
    80  
    81  func (s *SocketServer) addConn(conn net.Conn) int {
    82  	s.connsMtx.Lock()
    83  	defer s.connsMtx.Unlock()
    84  
    85  	connID := s.nextConnID
    86  	s.nextConnID++
    87  	s.conns[connID] = conn
    88  
    89  	return connID
    90  }
    91  
    92  // deletes conn even if close errs
    93  func (s *SocketServer) rmConn(connID int) error {
    94  	s.connsMtx.Lock()
    95  	defer s.connsMtx.Unlock()
    96  
    97  	conn, ok := s.conns[connID]
    98  	if !ok {
    99  		return fmt.Errorf("connection %d does not exist", connID)
   100  	}
   101  
   102  	delete(s.conns, connID)
   103  	return conn.Close()
   104  }
   105  
   106  func (s *SocketServer) acceptConnectionsRoutine() {
   107  	for {
   108  		// Accept a connection
   109  		s.Logger.Info("Waiting for new connection...")
   110  		conn, err := s.listener.Accept()
   111  		if err != nil {
   112  			if !s.IsRunning() {
   113  				return // Ignore error from listener closing.
   114  			}
   115  			s.Logger.Error("Failed to accept connection", "err", err)
   116  			continue
   117  		}
   118  
   119  		s.Logger.Info("Accepted a new connection")
   120  
   121  		connID := s.addConn(conn)
   122  
   123  		closeConn := make(chan error, 2)              // Push to signal connection closed
   124  		responses := make(chan *types.Response, 1000) // A channel to buffer responses
   125  
   126  		// Read requests from conn and deal with them
   127  		go s.handleRequests(closeConn, conn, responses)
   128  		// Pull responses from 'responses' and write them to conn.
   129  		go s.handleResponses(closeConn, conn, responses)
   130  
   131  		// Wait until signal to close connection
   132  		go s.waitForClose(closeConn, connID)
   133  	}
   134  }
   135  
   136  func (s *SocketServer) waitForClose(closeConn chan error, connID int) {
   137  	err := <-closeConn
   138  	switch {
   139  	case err == io.EOF:
   140  		s.Logger.Error("Connection was closed by client")
   141  	case err != nil:
   142  		s.Logger.Error("Connection error", "err", err)
   143  	default:
   144  		// never happens
   145  		s.Logger.Error("Connection was closed")
   146  	}
   147  
   148  	// Close the connection
   149  	if err := s.rmConn(connID); err != nil {
   150  		s.Logger.Error("Error closing connection", "err", err)
   151  	}
   152  }
   153  
   154  // Read requests from conn and deal with them
   155  func (s *SocketServer) handleRequests(closeConn chan error, conn io.Reader, responses chan<- *types.Response) {
   156  	var count int
   157  	var bufReader = bufio.NewReader(conn)
   158  
   159  	defer func() {
   160  		// make sure to recover from any app-related panics to allow proper socket cleanup
   161  		r := recover()
   162  		if r != nil {
   163  			const size = 64 << 10
   164  			buf := make([]byte, size)
   165  			buf = buf[:runtime.Stack(buf, false)]
   166  			err := fmt.Errorf("recovered from panic: %v\n%s", r, buf)
   167  			if !s.isLoggerSet {
   168  				fmt.Fprintln(os.Stderr, err)
   169  			}
   170  			closeConn <- err
   171  			s.appMtx.Unlock()
   172  		}
   173  	}()
   174  
   175  	for {
   176  
   177  		var req = &types.Request{}
   178  		err := types.ReadMessage(bufReader, req)
   179  		if err != nil {
   180  			if err == io.EOF {
   181  				closeConn <- err
   182  			} else {
   183  				closeConn <- fmt.Errorf("error reading message: %w", err)
   184  			}
   185  			return
   186  		}
   187  		s.appMtx.Lock()
   188  		count++
   189  		s.handleRequest(req, responses)
   190  		s.appMtx.Unlock()
   191  	}
   192  }
   193  
   194  func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types.Response) {
   195  	switch r := req.Value.(type) {
   196  	case *types.Request_Echo:
   197  		responses <- types.ToResponseEcho(r.Echo.Message)
   198  	case *types.Request_Flush:
   199  		responses <- types.ToResponseFlush()
   200  	case *types.Request_Info:
   201  		res := s.app.Info(*r.Info)
   202  		responses <- types.ToResponseInfo(res)
   203  	case *types.Request_SetOption:
   204  		res := s.app.SetOption(*r.SetOption)
   205  		responses <- types.ToResponseSetOption(res)
   206  	case *types.Request_DeliverTx:
   207  		res := s.app.DeliverTx(*r.DeliverTx)
   208  		responses <- types.ToResponseDeliverTx(res)
   209  	case *types.Request_CheckTx:
   210  		res := s.app.CheckTx(*r.CheckTx)
   211  		responses <- types.ToResponseCheckTx(res)
   212  	case *types.Request_Commit:
   213  		res := s.app.Commit()
   214  		responses <- types.ToResponseCommit(res)
   215  	case *types.Request_Query:
   216  		res := s.app.Query(*r.Query)
   217  		responses <- types.ToResponseQuery(res)
   218  	case *types.Request_InitChain:
   219  		res := s.app.InitChain(*r.InitChain)
   220  		responses <- types.ToResponseInitChain(res)
   221  	case *types.Request_BeginBlock:
   222  		res := s.app.BeginBlock(*r.BeginBlock)
   223  		responses <- types.ToResponseBeginBlock(res)
   224  	case *types.Request_EndBlock:
   225  		res := s.app.EndBlock(*r.EndBlock)
   226  		responses <- types.ToResponseEndBlock(res)
   227  	case *types.Request_ListSnapshots:
   228  		res := s.app.ListSnapshots(*r.ListSnapshots)
   229  		responses <- types.ToResponseListSnapshots(res)
   230  	case *types.Request_OfferSnapshot:
   231  		res := s.app.OfferSnapshot(*r.OfferSnapshot)
   232  		responses <- types.ToResponseOfferSnapshot(res)
   233  	case *types.Request_LoadSnapshotChunk:
   234  		res := s.app.LoadSnapshotChunk(*r.LoadSnapshotChunk)
   235  		responses <- types.ToResponseLoadSnapshotChunk(res)
   236  	case *types.Request_ApplySnapshotChunk:
   237  		res := s.app.ApplySnapshotChunk(*r.ApplySnapshotChunk)
   238  		responses <- types.ToResponseApplySnapshotChunk(res)
   239  	default:
   240  		responses <- types.ToResponseException("Unknown request")
   241  	}
   242  }
   243  
   244  // Pull responses from 'responses' and write them to conn.
   245  func (s *SocketServer) handleResponses(closeConn chan error, conn io.Writer, responses <-chan *types.Response) {
   246  	var count int
   247  	var bufWriter = bufio.NewWriter(conn)
   248  	for {
   249  		var res = <-responses
   250  		err := types.WriteMessage(res, bufWriter)
   251  		if err != nil {
   252  			closeConn <- fmt.Errorf("error writing message: %w", err)
   253  			return
   254  		}
   255  		if _, ok := res.Value.(*types.Response_Flush); ok {
   256  			err = bufWriter.Flush()
   257  			if err != nil {
   258  				closeConn <- fmt.Errorf("error flushing write buffer: %w", err)
   259  				return
   260  			}
   261  		}
   262  		count++
   263  	}
   264  }