github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/libs/kcp-go/readloop_linux.go (about)

     1  // +build linux
     2  
     3  package kcp
     4  
     5  import (
     6  	"net"
     7  	"os"
     8  	"sync/atomic"
     9  
    10  	"github.com/pkg/errors"
    11  	"golang.org/x/net/ipv4"
    12  	"golang.org/x/net/ipv6"
    13  )
    14  
    15  // the read loop for a client session
    16  func (s *UDPSession) readLoop() {
    17  	// default version
    18  	if s.xconn == nil {
    19  		s.defaultReadLoop()
    20  		return
    21  	}
    22  
    23  	// x/net version
    24  	var src string
    25  	msgs := make([]ipv4.Message, batchSize)
    26  	for k := range msgs {
    27  		msgs[k].Buffers = [][]byte{make([]byte, mtuLimit)}
    28  	}
    29  
    30  	for {
    31  		if count, err := s.xconn.ReadBatch(msgs, 0); err == nil {
    32  			for i := 0; i < count; i++ {
    33  				msg := &msgs[i]
    34  				// make sure the packet is from the same source
    35  				if src == "" { // set source address if nil
    36  					src = msg.Addr.String()
    37  				} else if msg.Addr.String() != src {
    38  					atomic.AddUint64(&DefaultSnmp.InErrs, 1)
    39  					continue
    40  				}
    41  
    42  				if msg.N < s.headerSize()+IKCP_OVERHEAD {
    43  					atomic.AddUint64(&DefaultSnmp.InErrs, 1)
    44  					continue
    45  				}
    46  
    47  				// source and size has validated
    48  				s.packetInput(msg.Buffers[0][:msg.N])
    49  			}
    50  		} else {
    51  			// compatibility issue:
    52  			// for linux kernel<=2.6.32, support for sendmmsg is not available
    53  			// an error of type os.SyscallError will be returned
    54  			if operr, ok := err.(*net.OpError); ok {
    55  				if se, ok := operr.Err.(*os.SyscallError); ok {
    56  					if se.Syscall == "recvmmsg" {
    57  						s.defaultReadLoop()
    58  						return
    59  					}
    60  				}
    61  			}
    62  			s.notifyReadError(errors.WithStack(err))
    63  			return
    64  		}
    65  	}
    66  }
    67  
    68  // monitor incoming data for all connections of server
    69  func (l *Listener) monitor() {
    70  	var xconn batchConn
    71  	if _, ok := l.conn.(*net.UDPConn); ok {
    72  		addr, err := net.ResolveUDPAddr("udp", l.conn.LocalAddr().String())
    73  		if err == nil {
    74  			if addr.IP.To4() != nil {
    75  				xconn = ipv4.NewPacketConn(l.conn)
    76  			} else {
    77  				xconn = ipv6.NewPacketConn(l.conn)
    78  			}
    79  		}
    80  	}
    81  
    82  	// default version
    83  	if xconn == nil {
    84  		l.defaultMonitor()
    85  		return
    86  	}
    87  
    88  	// x/net version
    89  	msgs := make([]ipv4.Message, batchSize)
    90  	for k := range msgs {
    91  		msgs[k].Buffers = [][]byte{make([]byte, mtuLimit)}
    92  	}
    93  
    94  	for {
    95  		if count, err := xconn.ReadBatch(msgs, 0); err == nil {
    96  			for i := 0; i < count; i++ {
    97  				msg := &msgs[i]
    98  				if msg.N >= l.headerSize+IKCP_OVERHEAD {
    99  					l.packetInput(msg.Buffers[0][:msg.N], msg.Addr)
   100  				} else {
   101  					atomic.AddUint64(&DefaultSnmp.InErrs, 1)
   102  				}
   103  			}
   104  		} else {
   105  			// compatibility issue:
   106  			// for linux kernel<=2.6.32, support for sendmmsg is not available
   107  			// an error of type os.SyscallError will be returned
   108  			if operr, ok := err.(*net.OpError); ok {
   109  				if se, ok := operr.Err.(*os.SyscallError); ok {
   110  					if se.Syscall == "recvmmsg" {
   111  						l.defaultMonitor()
   112  						return
   113  					}
   114  				}
   115  			}
   116  			l.notifyReadError(errors.WithStack(err))
   117  			return
   118  		}
   119  	}
   120  }