blob: 211babf67575ef31ff5ac51d16fc9a40ecd88bea [file] [log] [blame]
// 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
}