| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- // Copyright 2013 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.
- // Native Client SRPC message passing.
- // This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
- package unix
- import (
- "errors"
- "sync"
- "unsafe"
- )
- // An srpcClient represents the client side of an SRPC connection.
- type srpcClient struct {
- fd int // to server
- r msgReceiver
- s msgSender
- service map[string]srpcService // services by name
- outMu sync.Mutex // protects writing to connection
- mu sync.Mutex // protects following fields
- muxer bool // is someone reading and muxing responses
- pending map[uint32]*srpc
- idGen uint32 // generator for request IDs
- }
- // An srpcService is a single method that the server offers.
- type srpcService struct {
- num uint32 // method number
- fmt string // argument format; see "parsing of RPC messages" below
- }
- // An srpc represents a single srpc issued by a client.
- type srpc struct {
- Ret []interface{}
- Done chan *srpc
- Err error
- c *srpcClient
- id uint32
- }
- // newClient allocates a new SRPC client using the file descriptor fd.
- func newClient(fd int) (*srpcClient, error) {
- c := new(srpcClient)
- c.fd = fd
- c.r.fd = fd
- c.s.fd = fd
- c.service = make(map[string]srpcService)
- c.pending = make(map[uint32]*srpc)
- // service discovery request
- m := &msg{
- isRequest: 1,
- template: []interface{}{[]byte(nil)},
- size: []int{4000}, // max size to accept for returned byte slice
- }
- if err := m.pack(); err != nil {
- return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
- }
- c.s.send(m)
- m, err := c.r.recv()
- if err != nil {
- return nil, err
- }
- m.unpack()
- if m.status != uint32(srpcOK) {
- return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
- }
- list := m.value[0].([]byte)
- var n uint32
- for len(list) > 0 {
- var line []byte
- i := byteIndex(list, '\n')
- if i < 0 {
- line, list = list, nil
- } else {
- line, list = list[:i], list[i+1:]
- }
- i = byteIndex(line, ':')
- if i >= 0 {
- c.service[string(line)] = srpcService{n, string(line[i+1:])}
- }
- n++
- }
- return c, nil
- }
- func byteIndex(b []byte, c byte) int {
- for i, bi := range b {
- if bi == c {
- return i
- }
- }
- return -1
- }
- var yourTurn srpc
- func (c *srpcClient) wait(r *srpc) {
- var rx *srpc
- for rx = range r.Done {
- if rx != &yourTurn {
- break
- }
- c.input()
- }
- return
- }
- func (c *srpcClient) input() {
- // read message
- m, err := c.r.recv()
- if err != nil {
- println("Native Client SRPC receive error:", err.Error())
- return
- }
- if m.unpack(); m.status != uint32(srpcOK) {
- println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
- return
- }
- // deliver to intended recipient
- c.mu.Lock()
- rpc, ok := c.pending[m.id]
- if ok {
- delete(c.pending, m.id)
- }
- // wake a new muxer if there are more RPCs to read
- c.muxer = false
- for _, rpc := range c.pending {
- c.muxer = true
- rpc.Done <- &yourTurn
- break
- }
- c.mu.Unlock()
- if !ok {
- println("Native Client: unexpected response for ID", m.id)
- return
- }
- rpc.Ret = m.value
- rpc.Done <- rpc
- }
- // Wait blocks until the RPC has finished.
- func (r *srpc) Wait() {
- r.c.wait(r)
- }
- // Start issues an RPC request for method name with the given arguments.
- // The RPC r must not be in use for another pending request.
- // To wait for the RPC to finish, receive from r.Done and then
- // inspect r.Ret and r.Errno.
- func (r *srpc) Start(name string, arg []interface{}) {
- r.Err = nil
- r.c.mu.Lock()
- srv, ok := r.c.service[name]
- if !ok {
- r.c.mu.Unlock()
- r.Err = srpcErrBadRPCNumber
- r.Done <- r
- return
- }
- r.c.pending[r.id] = r
- if !r.c.muxer {
- r.c.muxer = true
- r.Done <- &yourTurn
- }
- r.c.mu.Unlock()
- var m msg
- m.id = r.id
- m.isRequest = 1
- m.rpc = srv.num
- m.value = arg
- // Fill in the return values and sizes to generate
- // the right type chars. We'll take most any size.
- // Skip over input arguments.
- // We could check them against arg, but the server
- // will do that anyway.
- i := 0
- for srv.fmt[i] != ':' {
- i++
- }
- format := srv.fmt[i+1:]
- // Now the return prototypes.
- m.template = make([]interface{}, len(format))
- m.size = make([]int, len(format))
- for i := 0; i < len(format); i++ {
- switch format[i] {
- default:
- println("Native Client SRPC: unexpected service type " + string(format[i]))
- r.Err = srpcErrBadRPCNumber
- r.Done <- r
- return
- case 'b':
- m.template[i] = false
- case 'C':
- m.template[i] = []byte(nil)
- m.size[i] = 1 << 30
- case 'd':
- m.template[i] = float64(0)
- case 'D':
- m.template[i] = []float64(nil)
- m.size[i] = 1 << 30
- case 'h':
- m.template[i] = int(-1)
- case 'i':
- m.template[i] = int32(0)
- case 'I':
- m.template[i] = []int32(nil)
- m.size[i] = 1 << 30
- case 's':
- m.template[i] = ""
- m.size[i] = 1 << 30
- }
- }
- if err := m.pack(); err != nil {
- r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
- r.Done <- r
- return
- }
- r.c.outMu.Lock()
- r.c.s.send(&m)
- r.c.outMu.Unlock()
- }
- // Call is a convenience wrapper that starts the RPC request,
- // waits for it to finish, and then returns the results.
- // Its implementation is:
- //
- // r.Start(name, arg)
- // r.Wait()
- // return r.Ret, r.Errno
- //
- func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
- r := c.NewRPC(nil)
- r.Start(name, arg)
- r.Wait()
- return r.Ret, r.Err
- }
- // NewRPC creates a new RPC on the client connection.
- func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
- if done == nil {
- done = make(chan *srpc, 1)
- }
- c.mu.Lock()
- id := c.idGen
- c.idGen++
- c.mu.Unlock()
- return &srpc{Done: done, c: c, id: id}
- }
- // The current protocol number.
- // Kind of useless, since there have been backwards-incompatible changes
- // to the wire protocol that did not update the protocol number.
- // At this point it's really just a sanity check.
- const protocol = 0xc0da0002
- // An srpcErrno is an SRPC status code.
- type srpcErrno uint32
- const (
- srpcOK srpcErrno = 256 + iota
- srpcErrBreak
- srpcErrMessageTruncated
- srpcErrNoMemory
- srpcErrProtocolMismatch
- srpcErrBadRPCNumber
- srpcErrBadArgType
- srpcErrTooFewArgs
- srpcErrTooManyArgs
- srpcErrInArgTypeMismatch
- srpcErrOutArgTypeMismatch
- srpcErrInternalError
- srpcErrAppError
- )
- var srpcErrstr = [...]string{
- srpcOK - srpcOK: "ok",
- srpcErrBreak - srpcOK: "break",
- srpcErrMessageTruncated - srpcOK: "message truncated",
- srpcErrNoMemory - srpcOK: "out of memory",
- srpcErrProtocolMismatch - srpcOK: "protocol mismatch",
- srpcErrBadRPCNumber - srpcOK: "invalid RPC method number",
- srpcErrBadArgType - srpcOK: "unexpected argument type",
- srpcErrTooFewArgs - srpcOK: "too few arguments",
- srpcErrTooManyArgs - srpcOK: "too many arguments",
- srpcErrInArgTypeMismatch - srpcOK: "input argument type mismatch",
- srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
- srpcErrInternalError - srpcOK: "internal error",
- srpcErrAppError - srpcOK: "application error",
- }
- func (e srpcErrno) Error() string {
- if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
- return "srpcErrno(" + itoa(int(e)) + ")"
- }
- return srpcErrstr[e-srpcOK]
- }
- // A msgHdr is the data argument to the imc_recvmsg
- // and imc_sendmsg system calls.
- type msgHdr struct {
- iov *iov
- niov int32
- desc *int32
- ndesc int32
- flags uint32
- }
- // A single region for I/O.
- type iov struct {
- base *byte
- len int32
- }
- const maxMsgSize = 1<<16 - 4*4
- // A msgReceiver receives messages from a file descriptor.
- type msgReceiver struct {
- fd int
- data [maxMsgSize]byte
- desc [8]int32
- hdr msgHdr
- iov iov
- }
- func (r *msgReceiver) recv() (*msg, error) {
- // Init pointers to buffers where syscall recvmsg can write.
- r.iov.base = &r.data[0]
- r.iov.len = int32(len(r.data))
- r.hdr.iov = &r.iov
- r.hdr.niov = 1
- r.hdr.desc = &r.desc[0]
- r.hdr.ndesc = int32(len(r.desc))
- n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
- if e != 0 {
- println("Native Client imc_recvmsg: ", e.Error())
- return nil, e
- }
- // Make a copy of the data so that the next recvmsg doesn't
- // smash it. The system call did not update r.iov.len. Instead it
- // returned the total byte count as n.
- m := new(msg)
- m.data = make([]byte, n)
- copy(m.data, r.data[0:])
- // Make a copy of the desc too.
- // The system call *did* update r.hdr.ndesc.
- if r.hdr.ndesc > 0 {
- m.desc = make([]int32, r.hdr.ndesc)
- copy(m.desc, r.desc[:])
- }
- return m, nil
- }
- // A msgSender sends messages on a file descriptor.
- type msgSender struct {
- fd int
- hdr msgHdr
- iov iov
- }
- func (s *msgSender) send(m *msg) error {
- if len(m.data) > 0 {
- s.iov.base = &m.data[0]
- }
- s.iov.len = int32(len(m.data))
- s.hdr.iov = &s.iov
- s.hdr.niov = 1
- s.hdr.desc = nil
- s.hdr.ndesc = 0
- _, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
- if e != 0 {
- println("Native Client imc_sendmsg: ", e.Error())
- return e
- }
- return nil
- }
- // A msg is the Go representation of an SRPC message.
- type msg struct {
- data []byte // message data
- desc []int32 // message file descriptors
- // parsed version of message
- id uint32
- isRequest uint32
- rpc uint32
- status uint32
- value []interface{}
- template []interface{}
- size []int
- format string
- broken bool
- }
- // reading from a msg
- func (m *msg) uint32() uint32 {
- if m.broken {
- return 0
- }
- if len(m.data) < 4 {
- m.broken = true
- return 0
- }
- b := m.data[:4]
- x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
- m.data = m.data[4:]
- return x
- }
- func (m *msg) uint64() uint64 {
- x := uint64(m.uint32()) | uint64(m.uint32())<<32
- if m.broken {
- return 0
- }
- return x
- }
- func (m *msg) bytes(n int) []byte {
- if m.broken {
- return nil
- }
- if len(m.data) < n {
- m.broken = true
- return nil
- }
- x := m.data[0:n]
- m.data = m.data[n:]
- return x
- }
- // writing to a msg
- func (m *msg) wuint32(x uint32) {
- m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
- }
- func (m *msg) wuint64(x uint64) {
- lo := uint32(x)
- hi := uint32(x >> 32)
- m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
- }
- func (m *msg) wbytes(p []byte) {
- m.data = append(m.data, p...)
- }
- func (m *msg) wstring(s string) {
- m.data = append(m.data, s...)
- }
- // Parsing of RPC messages.
- //
- // Each message begins with
- // total_size uint32
- // total_descs uint32
- // fragment_size uint32
- // fragment_descs uint32
- //
- // If fragment_size < total_size or fragment_descs < total_descs, the actual
- // message is broken up in multiple messages; follow-up messages omit
- // the "total" fields and begin with the "fragment" fields.
- // We do not support putting fragmented messages back together.
- // To do this we would need to change the message receiver.
- //
- // After that size information, the message header follows:
- // protocol uint32
- // requestID uint32
- // isRequest uint32
- // rpcNumber uint32
- // status uint32
- // numValue uint32
- // numTemplate uint32
- //
- // After the header come numTemplate fixed-size arguments,
- // numValue fixed-size arguments, and then the variable-sized
- // part of the values. The templates describe the expected results
- // and have no associated variable sized data in the request.
- //
- // Each fixed-size argument has the form:
- // tag uint32 // really a char, like 'b' or 'C'
- // pad uint32 // unused
- // val1 uint32
- // val2 uint32
- //
- // The tags are:
- // 'b': bool; val1 == 0 or 1
- // 'C': []byte; val1 == len, data in variable-sized section
- // 'd': float64; (val1, val2) is data
- // 'D': []float64; val1 == len, data in variable-sized section
- // 'h': int; val1 == file descriptor
- // 'i': int32; descriptor in next entry in m.desc
- // 'I': []int; val1 == len, data in variable-sized section
- // 's': string; val1 == len, data in variable-sized section
- //
- func (m *msg) pack() error {
- m.data = m.data[:0]
- m.desc = m.desc[:0]
- // sizes, to fill in later
- m.wuint32(0)
- m.wuint32(0)
- m.wuint32(0)
- m.wuint32(0)
- // message header
- m.wuint32(protocol)
- m.wuint32(m.id)
- m.wuint32(m.isRequest)
- m.wuint32(m.rpc)
- m.wuint32(m.status)
- m.wuint32(uint32(len(m.value)))
- m.wuint32(uint32(len(m.template)))
- // fixed-size templates
- for i, x := range m.template {
- var tag, val1, val2 uint32
- switch x.(type) {
- default:
- return errors.New("unexpected template type")
- case bool:
- tag = 'b'
- case []byte:
- tag = 'C'
- val1 = uint32(m.size[i])
- case float64:
- tag = 'd'
- case []float64:
- tag = 'D'
- val1 = uint32(m.size[i])
- case int:
- tag = 'h'
- case int32:
- tag = 'i'
- case []int32:
- tag = 'I'
- val1 = uint32(m.size[i])
- case string:
- tag = 's'
- val1 = uint32(m.size[i])
- }
- m.wuint32(tag)
- m.wuint32(0)
- m.wuint32(val1)
- m.wuint32(val2)
- }
- // fixed-size values
- for _, x := range m.value {
- var tag, val1, val2 uint32
- switch x := x.(type) {
- default:
- return errors.New("unexpected value type")
- case bool:
- tag = 'b'
- if x {
- val1 = 1
- }
- case []byte:
- tag = 'C'
- val1 = uint32(len(x))
- case float64:
- tag = 'd'
- v := float64bits(x)
- val1 = uint32(v)
- val2 = uint32(v >> 32)
- case []float64:
- tag = 'D'
- val1 = uint32(len(x))
- case int32:
- tag = 'i'
- m.desc = append(m.desc, x)
- case []int32:
- tag = 'I'
- val1 = uint32(len(x))
- case string:
- tag = 's'
- val1 = uint32(len(x) + 1)
- }
- m.wuint32(tag)
- m.wuint32(0)
- m.wuint32(val1)
- m.wuint32(val2)
- }
- // variable-length data for values
- for _, x := range m.value {
- switch x := x.(type) {
- case []byte:
- m.wbytes(x)
- case []float64:
- for _, f := range x {
- m.wuint64(float64bits(f))
- }
- case []int32:
- for _, j := range x {
- m.wuint32(uint32(j))
- }
- case string:
- m.wstring(x)
- m.wstring("\x00")
- }
- }
- // fill in sizes
- data := m.data
- m.data = m.data[:0]
- m.wuint32(uint32(len(data)))
- m.wuint32(uint32(len(m.desc)))
- m.wuint32(uint32(len(data)))
- m.wuint32(uint32(len(m.desc)))
- m.data = data
- return nil
- }
- func (m *msg) unpack() error {
- totalSize := m.uint32()
- totalDesc := m.uint32()
- fragSize := m.uint32()
- fragDesc := m.uint32()
- if totalSize != fragSize || totalDesc != fragDesc {
- return errors.New("Native Client: fragmented RPC messages not supported")
- }
- if m.uint32() != protocol {
- return errors.New("Native Client: RPC protocol mismatch")
- }
- // message header
- m.id = m.uint32()
- m.isRequest = m.uint32()
- m.rpc = m.uint32()
- m.status = m.uint32()
- m.value = make([]interface{}, m.uint32())
- m.template = make([]interface{}, m.uint32())
- m.size = make([]int, len(m.template))
- if m.broken {
- return errors.New("Native Client: malformed message")
- }
- // fixed-size templates
- for i := range m.template {
- tag := m.uint32()
- m.uint32() // padding
- val1 := m.uint32()
- m.uint32() // val2
- switch tag {
- default:
- return errors.New("Native Client: unexpected template type " + string(rune(tag)))
- case 'b':
- m.template[i] = false
- case 'C':
- m.template[i] = []byte(nil)
- m.size[i] = int(val1)
- case 'd':
- m.template[i] = float64(0)
- case 'D':
- m.template[i] = []float64(nil)
- m.size[i] = int(val1)
- case 'i':
- m.template[i] = int32(0)
- case 'I':
- m.template[i] = []int32(nil)
- m.size[i] = int(val1)
- case 'h':
- m.template[i] = int(0)
- case 's':
- m.template[i] = ""
- m.size[i] = int(val1)
- }
- }
- // fixed-size values
- var (
- strsize []uint32
- d int
- )
- for i := range m.value {
- tag := m.uint32()
- m.uint32() // padding
- val1 := m.uint32()
- val2 := m.uint32()
- switch tag {
- default:
- return errors.New("Native Client: unexpected value type " + string(rune(tag)))
- case 'b':
- m.value[i] = val1 > 0
- case 'C':
- m.value[i] = []byte(nil)
- strsize = append(strsize, val1)
- case 'd':
- m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
- case 'D':
- m.value[i] = make([]float64, val1)
- case 'i':
- m.value[i] = int32(val1)
- case 'I':
- m.value[i] = make([]int32, val1)
- case 'h':
- m.value[i] = int(m.desc[d])
- d++
- case 's':
- m.value[i] = ""
- strsize = append(strsize, val1)
- }
- }
- // variable-sized parts of values
- for i, x := range m.value {
- switch x := x.(type) {
- case []byte:
- m.value[i] = m.bytes(int(strsize[0]))
- strsize = strsize[1:]
- case []float64:
- for i := range x {
- x[i] = float64frombits(m.uint64())
- }
- case []int32:
- for i := range x {
- x[i] = int32(m.uint32())
- }
- case string:
- m.value[i] = string(m.bytes(int(strsize[0])))
- strsize = strsize[1:]
- }
- }
- if len(m.data) > 0 {
- return errors.New("Native Client: junk at end of message")
- }
- return nil
- }
- func float64bits(x float64) uint64 {
- return *(*uint64)(unsafe.Pointer(&x))
- }
- func float64frombits(x uint64) float64 {
- return *(*float64)(unsafe.Pointer(&x))
- }
- // At startup, connect to the name service.
- var nsClient = nsConnect()
- func nsConnect() *srpcClient {
- var ns int32 = -1
- _, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
- if errno != 0 {
- println("Native Client nameservice:", errno.Error())
- return nil
- }
- sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
- if errno != 0 {
- println("Native Client nameservice connect:", errno.Error())
- return nil
- }
- c, err := newClient(int(sock))
- if err != nil {
- println("Native Client nameservice init:", err.Error())
- return nil
- }
- return c
- }
- const (
- nsSuccess = 0
- nsNameNotFound = 1
- nsDuplicateName = 2
- nsInsufficientResources = 3
- nsPermissionDenied = 4
- nsInvalidArgument = 5
- )
- func openNamedService(name string, mode int32) (fd int, err error) {
- if nsClient == nil {
- return 0, errors.New("no name service")
- }
- ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
- if err != nil {
- return 0, err
- }
- status := ret[0].(int32)
- fd = ret[1].(int)
- switch status {
- case nsSuccess:
- // ok
- case nsNameNotFound:
- return -1, ENOENT
- case nsDuplicateName:
- return -1, EEXIST
- case nsInsufficientResources:
- return -1, EWOULDBLOCK
- case nsPermissionDenied:
- return -1, EPERM
- case nsInvalidArgument:
- return -1, EINVAL
- default:
- return -1, EINVAL
- }
- return fd, nil
- }
|