Skip to content

Commit

Permalink
wip wake with write
Browse files Browse the repository at this point in the history
  • Loading branch information
tidwall committed Oct 28, 2017
1 parent 17aa5a0 commit 8897e0d
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 235 deletions.
4 changes: 2 additions & 2 deletions doppio.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Events struct {
// Serving fires when the server can accept connections.
// The wake parameter is a goroutine-safe function that triggers
// a Data event (with a nil `in` parameter) for the specified id.
Serving func(wake func(id int) bool) (action Action)
Serving func(wake func(id int, out []byte) bool) (action Action)
// Opened fires when a new connection has opened.
// Use the out return value to write data to the connection.
Opened func(id int, addr string) (out []byte, opts Options, action Action)
Expand Down Expand Up @@ -180,7 +180,7 @@ func servestdlib(events Events, lns []*listener) error {
var id int
var connconn = make(map[net.Conn]*cconn)
var idconn = make(map[int]*cconn)
wake := func(id int) bool {
wake := func(id int, out []byte) bool {
var ok = true
var err error
lock()
Expand Down
24 changes: 20 additions & 4 deletions doppio_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,32 @@ func serve(events Events, lns []*listener) error {
unlock := func() { mu.Unlock() }
fdconn := make(map[int]*conn)
idconn := make(map[int]*conn)
wake := func(id int) bool {
wake := func(id int, out []byte) bool {
var ok = true
var err error
lock()
c := idconn[id]
if c == nil {
ok = false
} else if !c.wake {
c.wake = true
err = c.addwrite()
} else {
// attempt to write to the socket
if out != nil {
c.outbuf = append(c.outbuf, out...)
var n int
n, err = syscall.Write(c.fd, c.outbuf)
if n > 0 && err == nil {
c.outpos += n
}
if len(c.outbuf)-c.outpos > 0 {
err = c.addwrite()
// } else {
// c.outbuf = nil //c.outbuf[:0]
// c.outpos = 0
}
} else if !c.wake {
c.wake = true
err = c.addwrite()
}
}
unlock()
if err != nil {
Expand Down
66 changes: 36 additions & 30 deletions examples/http-server-mt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type request struct {
type conn struct {
id int
addr string
wake func(id int) bool
wake func(id int, out []byte) bool

cond *sync.Cond
in []byte
Expand Down Expand Up @@ -56,7 +56,13 @@ func (c *conn) run() {
}
if c.outi > c.outw || c.action != doppio.None {
c.outw = c.outi
c.wake(c.id)
if c.action == doppio.None {
c.wake(c.id, c.out)
c.out = nil
} else {
c.wake(c.id, nil)
}

}
c.cond.Wait()
}
Expand All @@ -78,30 +84,32 @@ func main() {
}
go func(conn net.Conn) {
defer conn.Close()
addr := conn.RemoteAddr().String()
var in []byte
//addr := conn.RemoteAddr().String()
//var in []byte
var packet [0xFFFF]byte
for {
n, err := conn.Read(packet[:])
_, err := conn.(*net.TCPConn).Read(packet[:])
if err != nil {
return
}
in = append(in, packet[:n]...)
data := in
for {
out, leftover, action := execdata(data, addr)
if len(out) > 0 {
conn.Write(out)
}
if action != doppio.None {
return
}
if len(leftover) == len(data) {
break
}
data = leftover
}
in = append(in[:0], data...)
conn.Write(appendresp(nil, nil, "200 OK", "", "Hello World!"))

// in = append(in, packet[:n]...)
// data := in
// for {
// out, leftover, action := execdata(data, addr)
// if len(out) > 0 {
// conn.Write(out)
// }
// if action != doppio.None {
// return
// }
// if len(leftover) == len(data) {
// break
// }
// data = leftover
// }
// in = append(in[:0], data...)
}
}(conn)
}
Expand All @@ -110,9 +118,9 @@ func main() {

var events doppio.Events
var conns = make(map[int]*conn)
var wake func(id int) bool
var wake func(id int, out []byte) bool

events.Serving = func(wakefn func(id int) bool) (action doppio.Action) {
events.Serving = func(wakefn func(id int, out []byte) bool) (action doppio.Action) {
log.Print("http server started on port 8080")
wake = wakefn
return
Expand Down Expand Up @@ -141,19 +149,19 @@ func main() {

// Deal with incoming data
events.Data = func(id int, in []byte) (out []byte, action doppio.Action) {
//out = appendresp(out, nil, "200 OK", "", "Hello World!") //[]byte("HTTP/1.1 200 OK\r\n\r\n")
// return
c := conns[id]
if in == nil {
// from wakeup
c.cond.L.Lock()
out, action = c.out, c.action
c.out = nil
//println(456)
c.cond.L.Unlock()
} else {
// new data
c.cond.L.Lock()
c.in = append(c.in, in...)
//println(123)
c.cond.Broadcast()
c.cond.L.Unlock()
}
Expand All @@ -176,11 +184,9 @@ func appendresp(b []byte, req *request, status, head, body string) []byte {
b = append(b, "Date: "...)
b = time.Now().AppendFormat(b, "Mon, 02 Jan 2006 15:04:05 GMT")
b = append(b, '\r', '\n')
if len(body) > 0 {
b = append(b, "Content-Length: "...)
b = strconv.AppendInt(b, int64(len(body)), 10)
b = append(b, '\r', '\n')
}
b = append(b, "Content-Length: "...)
b = strconv.AppendInt(b, int64(len(body)), 10)
b = append(b, '\r', '\n')
b = append(b, head...)
b = append(b, '\r', '\n')
if len(body) > 0 {
Expand Down
199 changes: 0 additions & 199 deletions examples/http-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,202 +148,3 @@ func parsereq(data []byte, req *request) (leftover []byte, err error) {
// not enough data
return data, nil
}

// type conn struct {
// id int
// addr string
// in []byte
// out []byte
// closed bool
// action doppio.Action
// cond *sync.Cond
// wake func(id int) bool
// }

// func (c *conn) run() {
// c.cond.L.Lock()
// for !c.closed {
// if len(c.in) > 0 {
// in := c.in
// c.in = nil
// c.cond.L.Unlock()
// out, leftover, action := execdata(in, c.addr)
// c.cond.L.Lock()
// c.in = append(c.in, leftover...)
// c.out = out
// c.action = action
// }
// if len(c.out) > 0 || c.action != doppio.None {
// c.wake(c.id)
// }
// c.cond.Wait()
// }
// c.cond.L.Unlock()
// }

// func main() {
// var events doppio.Events
// var conns = make(map[int]*conn)
// var wake func(id int) bool

// events.Serving = func(wakefn func(id int) bool) (action doppio.Action) {
// log.Print("http server started on port 8080")
// wake = wakefn
// return
// }

// // Accept a new client connection for the specified ID.
// events.Opened = func(id int, addr string) (out []byte, opts doppio.Options, action doppio.Action) {
// c := &conn{id: id, addr: addr, cond: sync.NewCond(&sync.Mutex{}), wake: wake}
// conns[id] = c
// log.Printf("%s: opened", addr)
// go c.run()
// return
// }

// // Free resources after a connection closes
// events.Closed = func(id int) (action doppio.Action) {
// c := conns[id]
// log.Printf("%s: closed", c.addr)
// delete(conns, id)
// c.cond.L.Lock()
// c.closed = true
// c.cond.Signal()
// c.cond.L.Unlock()
// return
// }

// // Deal with incoming data
// events.Data = func(id int, in []byte) (out []byte, action doppio.Action) {
// // return []byte(
// // `HTTP/1.1 200 OK
// // Date: Fri, 27 Oct 2017 21:51:10 GMT
// // Content-Length: 13
// // Content-Type: text/plain; charset=utf-8

// // Hello World!
// // `), doppio.None
// c := conns[id]
// if false {
// c.cond.L.Lock()
// if in == nil {
// // from wakeup
// out, action = c.out, c.action
// c.out = c.out[:0]
// } else {
// c.in = append(c.in, in...)
// c.cond.Signal()
// }
// c.cond.L.Unlock()
// return
// }

// data := append(c.in, in...)
// var outb bytes.Buffer
// for len(data) > 0 && action == doppio.None {
// var req *http.Request
// var resp *http.Response
// var err error
// if req, data, err = readreq(data); err != nil {
// // bad thing happened
// resp = makeresp(nil, 500, nil, []byte(err.Error()+"\n"))
// resp.Close = true
// action = doppio.Close
// } else if req == nil {
// // request not ready, yet
// break
// } else {
// // do something neat with the request
// req.RemoteAddr = c.addr
// resp = handle(req)
// }
// if resp != nil {
// resp.Write(&outb)
// }
// }
// if len(data) > 0 {
// c.in = append(c.in[:0], data...)
// } else if len(c.in) > 0 {
// c.in = c.in[:0]
// }
// out = outb.Bytes()
// return
// }

// // Connect to port 8080
// log.Fatal(doppio.Serve(events, "tcp://0.0.0.0:8080"))
// }

// func execdata(in []byte, addr string) (out []byte, leftover []byte, action doppio.Action) {
// var outb bytes.Buffer
// for len(in) > 0 && action == doppio.None {
// var req *http.Request
// var resp *http.Response
// var err error
// if req, in, err = readreq(in); err != nil {
// // bad thing happened
// resp = makeresp(nil, 500, nil, []byte(err.Error()+"\n"))
// resp.Close = true
// action = doppio.Close
// } else if req == nil {
// // request not ready, yet
// break
// } else {
// // do something neat with the request
// req.RemoteAddr = addr
// resp = handle(req)
// }
// if resp != nil {
// resp.Write(&outb)
// }
// }
// return outb.Bytes(), in, action
// }

// func readreq(data []byte) (req *http.Request, leftover []byte, err error) {
// if !bytes.Contains(data, []byte("\r\n\r\n")) {
// // request not ready, just return the original data back
// return nil, data, nil
// }
// buf := bytes.NewBuffer(data)
// rd := bufio.NewReader(buf)
// req, err = http.ReadRequest(rd)
// leftover = data[len(data)-buf.Len()-rd.Buffered():]
// if err != nil {
// return
// }
// if req.ContentLength > 0 {
// // read the body content
// if int64(len(leftover)) < req.ContentLength {
// // not ready, just return the original data back
// return nil, data, nil
// }
// req.Body = ioutil.NopCloser(bytes.NewBuffer(leftover[:int(req.ContentLength)]))
// leftover = leftover[int(req.ContentLength):]
// }
// return
// }

// func makeresp(req *http.Request, code int, header http.Header, body []byte) *http.Response {
// return &http.Response{
// Request: req, StatusCode: code,
// ProtoMajor: 1, ProtoMinor: 1,
// Header: header,
// ContentLength: int64(len(body)),
// Body: ioutil.NopCloser(bytes.NewBuffer(body)),
// }
// }

// func handle(req *http.Request) *http.Response {
// //log.Printf("%s: %s: %s", req.RemoteAddr, req.Method, req.URL.Path)
// var body []byte
// switch req.URL.Path {
// default:
// body = []byte("Hi from " + req.URL.Path + "\n")
// case "/time":
// body = []byte(time.Now().String() + "\n")
// case "/":
// body = []byte(string("Hello World!\n"))
// }
// return makeresp(req, 200, nil, body)
// }

0 comments on commit 8897e0d

Please sign in to comment.