// raw packet encapsulation and put it online func (buf *Buffer) raw_send(data []byte) bool { // combine output to reduce syscall.write sz := len(data) binary.BigEndian.PutUint16(buf.cache, uint16(sz)) copy(buf.cache[2:], data) // write data n, err := buf.conn.Write(buf.cache[:sz+2]) if err != nil { log.Warningf("Error send reply data, bytes: %v reason: %v", n, err) return false } return true }
// add a service func (p *service_pool) add_service(key, value string) { p.Lock() defer p.Unlock() service_name := filepath.Dir(key) // name check if p.enable_name_check && !p.service_names[service_name] { log.Warningf("service not in names: %v, ignored", service_name) return } if p.services[service_name] == nil { p.services[service_name] = &service{} log.Tracef("new service type: %v", service_name) } service := p.services[service_name] if conn, err := grpc.Dial(value, grpc.WithTimeout(DEFAULT_DIAL_TIMEOUT), grpc.WithInsecure()); err == nil { service.clients = append(service.clients, client{key, conn}) log.Tracef("service added: %v -- %v", key, value) } else { log.Errorf("did not connect: %v -- %v err: %v", key, value, err) } }
// start a goroutine when a new connection is accepted func handleClient(conn *net.TCPConn) { defer utils.PrintPanicStack() // set per-connection socket buffer conn.SetReadBuffer(SO_RCVBUF) // set initial socket buffer conn.SetWriteBuffer(SO_SNDBUF) // initial network control struct header := make([]byte, 2) in := make(chan []byte) defer func() { close(in) // session will close }() // create a new session object for the connection var sess Session host, port, err := net.SplitHostPort(conn.RemoteAddr().String()) if err != nil { log.Error("cannot get remote address:", err) return } sess.IP = net.ParseIP(host) log.Infof("new connection from:%v port:%v", host, port) // session die signal sess.Die = make(chan struct{}) // create a write buffer out := new_buffer(conn, sess.Die) go out.start() // start one agent for handling packet wg.Add(1) go agent(&sess, in, out) // network loop for { // solve dead link problem conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second)) n, err := io.ReadFull(conn, header) if err != nil { log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } size := binary.BigEndian.Uint16(header) // alloc a byte slice for reading payload := make([]byte, size) // read msg n, err = io.ReadFull(conn, payload) if err != nil { log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } select { case in <- payload: // payload queued case <-sess.Die: log.Warningf("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP) return } } }
// PIPELINE #1: handleClient // the goroutine is used for reading incoming PACKETS // each packet is defined as : // | 2B size | DATA | // func handleClient(conn *net.TCPConn) { defer utils.PrintPanicStack() // set socket read buffer conn.SetReadBuffer(SO_RCVBUF) // set socket write buffer conn.SetWriteBuffer(SO_SNDBUF) // for reading the 2-Byte header header := make([]byte, 2) // the input channel for agent() in := make(chan []byte) defer func() { close(in) // session will close }() // create a new session object for the connection // and record it's IP address var sess Session host, port, err := net.SplitHostPort(conn.RemoteAddr().String()) if err != nil { log.Error("cannot get remote address:", err) return } sess.IP = net.ParseIP(host) log.Infof("new connection from:%v port:%v", host, port) // session die signal, will be triggered by agent() sess.Die = make(chan struct{}) // create a write buffer out := new_buffer(conn, sess.Die) go out.start() // start agent for PACKET processing wg.Add(1) go agent(&sess, in, out) // read loop for { // solve dead link problem: // physical disconnection without any communcation between client and server // will cause the read to block FOREVER, so a timeout is a rescue. conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second)) // read 2B header n, err := io.ReadFull(conn, header) if err != nil { log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } size := binary.BigEndian.Uint16(header) // alloc a byte slice of the size defined in the header for reading data payload := make([]byte, size) n, err = io.ReadFull(conn, payload) if err != nil { log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } // deliver the data to the input queue of agent() select { case in <- payload: // payload queued case <-sess.Die: log.Warningf("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP) return } } }