예제 #1
0
파일: clnt.go 프로젝트: John-Appleseed/govt
func (clnt *Clnt) recv() {
	var err *vt.Error
	var req *Req
	var csz int

	err = nil
	buf := make([]byte, vt.Maxblock*8)
	pos := 0
	for {
		if len(buf) < int(vt.Maxblock) {
			b := make([]byte, vt.Maxblock*8)
			copy(b, buf[0:pos])
			buf = b
			b = nil
		}

		n, oserr := clnt.conn.Read(buf[pos:len(buf)])
		if oserr != nil || n == 0 {
			err = &vt.Error{oserr.Error()}
			goto closed
		}

		pos += n
		for pos > 4 {
			sz, _ := vt.Gint16(buf)
			sz += 2
			if sz > vt.Maxblock {
				err = &vt.Error{fmt.Sprintf("bad client connection: %s", clnt.Id)}
				clnt.conn.Close()
				goto closed
			}

			if pos < int(sz) {
				if len(buf) < int(sz) {
					b := make([]byte, vt.Maxblock*8)
					copy(b, buf[0:pos])
					buf = b
					b = nil
				}

				break
			}

			tag, _ := vt.Gint8(buf[3:])
			clnt.Lock()
			for req = clnt.reqfirst; req != nil; req = req.next {
				if req.tag == tag {
					if req.prev != nil {
						req.prev.next = req.next
					} else {
						clnt.reqfirst = req.next
					}

					if req.next != nil {
						req.next.prev = req.prev
					} else {
						clnt.reqlast = req.prev
					}

					break
				}
			}
			clnt.Unlock()

			if req == nil {
				err = &vt.Error{"unexpected response"}
				clnt.conn.Close()
				goto closed
			}

			csz, err = vt.Unpack(buf, &req.Rc)
			if err != nil {
				clnt.conn.Close()
				goto closed
			}

			if clnt.Debuglevel > 0 {
				clnt.logFcall(&req.Rc)
				if clnt.Debuglevel&DbgPrintPackets != 0 {
					log.Println("}-}", clnt.Id, fmt.Sprint(req.Rc.Pkt))
				}

				if clnt.Debuglevel&DbgPrintCalls != 0 {
					log.Println("}}}", clnt.Id, req.Rc.String())
				}
			}

			if req.Tc.Id != req.Rc.Id-1 {
				if req.Rc.Id != vt.Rerror {
					req.Err = &vt.Error{"invalid response"}
				} else {
					if req.Err != nil {
						req.Err = &vt.Error{req.Rc.Ename}
					}
				}
			}

			if req.Done != nil {
				req.Done <- req
			} else {
				clnt.ReqFree(req)
			}

			pos -= csz
			buf = buf[csz:]
		}
	}

closed:
	clnt.done <- true

	/* send error to all pending requests */
	clnt.Lock()
	if clnt.err != nil {
		clnt.err = err
	}

	r := clnt.reqfirst
	clnt.reqfirst = nil
	clnt.reqlast = nil
	clnt.Unlock()

	for ; r != nil; r = r.next {
		r.Err = err
		if r.Done != nil {
			r.Done <- r
		}
	}

	clnts.Lock()
	if clnt == clnts.list {
		clnts.list = clnt.next
	} else {
		var c *Clnt

		for c = clnts.list; c.next != clnt; c = c.next {
		}

		c.next = clnt.next
	}
	clnts.Unlock()
	if sop, ok := (interface{}(clnt)).(StatsOps); ok {
		sop.statsUnregister()
	}
}
예제 #2
0
파일: srv.go 프로젝트: John-Appleseed/govt
func (conn *Conn) recv() {
	var err error
	var n int

	bufsz := 8 * vt.Maxblock
	buf := make([]byte, bufsz*8)
	srv := conn.Srv
	pos := 0
	for {
		if len(buf) < vt.Maxblock {
			b := make([]byte, bufsz)
			copy(b, buf[0:pos])
			buf = b
			b = nil
		}

		n, err = conn.conn.Read(buf[pos:])
		if err != nil || n == 0 {
			goto closed
		}

		nreads := 1
		pos += n
		for pos > 2 {
			sz, _ := vt.Gint16(buf)
			sz += 2
			if sz > vt.Maxblock {
				log.Println("bad client connection: ", conn.conn.RemoteAddr())
				conn.conn.Close()
				goto closed
			}
			if pos < int(sz) {
				if len(buf) < int(sz) {
					b := make([]byte, bufsz)
					copy(b, buf[0:pos])
					buf = b
					b = nil
				}

				break
			}

			req := srv.ReqAlloc()
			req.Conn = conn
			csize, err := vt.Unpack(buf, req.Tc)
			if err != nil {
				log.Println(fmt.Sprintf("invalid packet: %v %v", err, buf))
				conn.conn.Close()
				srv.ReqFree(req)
				goto closed
			}

			if conn.Debuglevel > 0 {
				conn.logFcall(req.Tc)
				if conn.Debuglevel&DbgPrintPackets != 0 {
					log.Println(">->", conn.Id, fmt.Sprintf("%x", req.Tc.Pkt))
				}

				if conn.Debuglevel&DbgPrintCalls != 0 {
					log.Println(">>>", conn.Id, req.Tc.String())
				}
			}

			conn.Lock()
			conn.nreqs++
			conn.tsz += uint64(sz)
			conn.npend++
			conn.nreads += nreads
			nreads = 0
			if conn.npend > conn.maxpend {
				conn.maxpend = conn.npend
			}
			conn.Unlock()

			go req.process()
			buf = buf[csize:]
			pos -= csize
		}
	}

closed:
	conn.done <- true
	conn.Srv.Lock()
	srv.nreqs += conn.nreqs
	srv.tsz += conn.tsz
	srv.rsz += conn.rsz
	srv.maxpend += conn.maxpend
	srv.nwrites += conn.nwrites
	srv.nreads += conn.nreads
	if conn.prev != nil {
		conn.prev.next = conn.next
	} else {
		conn.Srv.connlist = conn.next
	}

	if conn.next != nil {
		conn.next.prev = conn.prev
	}
	conn.Srv.Unlock()
	if sop, ok := (interface{}(conn)).(StatsOps); ok {
		sop.statsUnregister()
	}

	if op, ok := (conn.Srv.ops).(ConnOps); ok {
		op.ConnClosed(conn)
	}
}