| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build fuchsia |
| |
| package zxsocket |
| |
| import ( |
| "syscall/zx" |
| ) |
| |
| // ServerHandler is the type of the callback which contains the remoteio "server". It is called from |
| // the server handler function. |
| // - msg.Datalen represents the size of the incoming/outgoing message in msg.Data. |
| // - Return values are placed in msg.Arg. Negative is error. |
| type ServerHandler func(msg *Msg, rh zx.Socket, cookie int64) zx.Status |
| |
| // Handler reads a single RIO message from the handle h. If the message is valid, the callback |
| // cb is invoked. If the callback is successful, a response may be sent back on handle h. |
| func Handler(h zx.Socket, cb interface{}, cookie int64) error { |
| var msg Msg |
| |
| serverCb := cb.(ServerHandler) |
| if h == 0 { |
| // The remote side has been closed. Send our final callback and leave. |
| msg.SetOp(OpClose) |
| msg.Arg = 0 |
| msg.Datalen = 0 |
| msg.Hcount = 0 |
| serverCb(&msg, 0, cookie) |
| return nil |
| } |
| msg.Hcount = MessageMaxHandles |
| numBytesInt, _, err := msg.ReadMsg(h) |
| numBytes := uint32(numBytesInt) |
| if err != nil { |
| if mxerr, hasStatus := err.(zx.Error); hasStatus && mxerr.Status == zx.ErrBadState { |
| return ErrNoWork |
| } |
| return err |
| } |
| if !msg.IsValidIncoming(numBytes) { |
| return zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Handler"} |
| } |
| |
| isClose := (msg.Op() == OpClose) |
| status := serverCb(&msg, h, cookie) |
| msg.Arg = int32(status) |
| if zx.Status(msg.Arg) == ErrIndirect.Status { |
| // The callback is handling the reply itself |
| return nil |
| } else if status < 0 || !msg.IsValid() { |
| // zx.Error case |
| msg.Datalen = 0 |
| if msg.Arg >= 0 { |
| // TODO(smklein): This error code may change. It currently is set to "ERR_FAULT" in |
| // Zircon, but is scheduled to change. |
| msg.Arg = int32(zx.ErrIO) |
| } |
| } |
| |
| _, err = msg.WriteMsg(h) |
| if isClose { |
| // Signals that a close callback is not necessary -- the op has already completed |
| return ErrDisconnectNoCallback |
| } |
| return err |
| } |