Home | History | Annotate | Download | only in syscall
      1 // Copyright 2013 The Go Authors.  All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Native Client SRPC message passing.
      6 // This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
      7 
      8 package syscall
      9 
     10 import (
     11 	"errors"
     12 	"sync"
     13 	"unsafe"
     14 )
     15 
     16 // An srpcClient represents the client side of an SRPC connection.
     17 type srpcClient struct {
     18 	fd      int // to server
     19 	r       msgReceiver
     20 	s       msgSender
     21 	service map[string]srpcService // services by name
     22 
     23 	outMu sync.Mutex // protects writing to connection
     24 
     25 	mu      sync.Mutex // protects following fields
     26 	muxer   bool       // is someone reading and muxing responses
     27 	pending map[uint32]*srpc
     28 	idGen   uint32 // generator for request IDs
     29 }
     30 
     31 // An srpcService is a single method that the server offers.
     32 type srpcService struct {
     33 	num uint32 // method number
     34 	fmt string // argument format; see "parsing of RPC messages" below
     35 }
     36 
     37 // An srpc represents a single srpc issued by a client.
     38 type srpc struct {
     39 	Ret  []interface{}
     40 	Done chan *srpc
     41 	Err  error
     42 	c    *srpcClient
     43 	id   uint32
     44 }
     45 
     46 // newClient allocates a new SRPC client using the file descriptor fd.
     47 func newClient(fd int) (*srpcClient, error) {
     48 	c := new(srpcClient)
     49 	c.fd = fd
     50 	c.r.fd = fd
     51 	c.s.fd = fd
     52 	c.service = make(map[string]srpcService)
     53 	c.pending = make(map[uint32]*srpc)
     54 
     55 	// service discovery request
     56 	m := &msg{
     57 		isRequest: 1,
     58 		template:  []interface{}{[]byte(nil)},
     59 		size:      []int{4000}, // max size to accept for returned byte slice
     60 	}
     61 	if err := m.pack(); err != nil {
     62 		return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
     63 	}
     64 	c.s.send(m)
     65 	m, err := c.r.recv()
     66 	if err != nil {
     67 		return nil, err
     68 	}
     69 	m.unpack()
     70 	if m.status != uint32(srpcOK) {
     71 		return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
     72 	}
     73 	list := m.value[0].([]byte)
     74 	var n uint32
     75 	for len(list) > 0 {
     76 		var line []byte
     77 		i := byteIndex(list, '\n')
     78 		if i < 0 {
     79 			line, list = list, nil
     80 		} else {
     81 			line, list = list[:i], list[i+1:]
     82 		}
     83 		i = byteIndex(line, ':')
     84 		if i >= 0 {
     85 			c.service[string(line)] = srpcService{n, string(line[i+1:])}
     86 		}
     87 		n++
     88 	}
     89 
     90 	return c, nil
     91 }
     92 
     93 func byteIndex(b []byte, c byte) int {
     94 	for i, bi := range b {
     95 		if bi == c {
     96 			return i
     97 		}
     98 	}
     99 	return -1
    100 }
    101 
    102 var yourTurn srpc
    103 
    104 func (c *srpcClient) wait(r *srpc) {
    105 	var rx *srpc
    106 	for rx = range r.Done {
    107 		if rx != &yourTurn {
    108 			break
    109 		}
    110 		c.input()
    111 	}
    112 	return
    113 }
    114 
    115 func (c *srpcClient) input() {
    116 	// read message
    117 	m, err := c.r.recv()
    118 	if err != nil {
    119 		println("Native Client SRPC receive error:", err.Error())
    120 		return
    121 	}
    122 	if m.unpack(); m.status != uint32(srpcOK) {
    123 		println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
    124 		return
    125 	}
    126 
    127 	// deliver to intended recipient
    128 	c.mu.Lock()
    129 	rpc, ok := c.pending[m.id]
    130 	if ok {
    131 		delete(c.pending, m.id)
    132 	}
    133 
    134 	// wake a new muxer if there are more RPCs to read
    135 	c.muxer = false
    136 	for _, rpc := range c.pending {
    137 		c.muxer = true
    138 		rpc.Done <- &yourTurn
    139 		break
    140 	}
    141 	c.mu.Unlock()
    142 	if !ok {
    143 		println("Native Client: unexpected response for ID", m.id)
    144 		return
    145 	}
    146 	rpc.Ret = m.value
    147 	rpc.Done <- rpc
    148 }
    149 
    150 // Wait blocks until the RPC has finished.
    151 func (r *srpc) Wait() {
    152 	r.c.wait(r)
    153 }
    154 
    155 // Start issues an RPC request for method name with the given arguments.
    156 // The RPC r must not be in use for another pending request.
    157 // To wait for the RPC to finish, receive from r.Done and then
    158 // inspect r.Ret and r.Errno.
    159 func (r *srpc) Start(name string, arg []interface{}) {
    160 	r.Err = nil
    161 	r.c.mu.Lock()
    162 	srv, ok := r.c.service[name]
    163 	if !ok {
    164 		r.c.mu.Unlock()
    165 		r.Err = srpcErrBadRPCNumber
    166 		r.Done <- r
    167 		return
    168 	}
    169 	r.c.pending[r.id] = r
    170 	if !r.c.muxer {
    171 		r.c.muxer = true
    172 		r.Done <- &yourTurn
    173 	}
    174 	r.c.mu.Unlock()
    175 
    176 	var m msg
    177 	m.id = r.id
    178 	m.isRequest = 1
    179 	m.rpc = srv.num
    180 	m.value = arg
    181 
    182 	// Fill in the return values and sizes to generate
    183 	// the right type chars.  We'll take most any size.
    184 
    185 	// Skip over input arguments.
    186 	// We could check them against arg, but the server
    187 	// will do that anyway.
    188 	i := 0
    189 	for srv.fmt[i] != ':' {
    190 		i++
    191 	}
    192 	format := srv.fmt[i+1:]
    193 
    194 	// Now the return prototypes.
    195 	m.template = make([]interface{}, len(format))
    196 	m.size = make([]int, len(format))
    197 	for i := 0; i < len(format); i++ {
    198 		switch format[i] {
    199 		default:
    200 			println("Native Client SRPC: unexpected service type " + string(format[i]))
    201 			r.Err = srpcErrBadRPCNumber
    202 			r.Done <- r
    203 			return
    204 		case 'b':
    205 			m.template[i] = false
    206 		case 'C':
    207 			m.template[i] = []byte(nil)
    208 			m.size[i] = 1 << 30
    209 		case 'd':
    210 			m.template[i] = float64(0)
    211 		case 'D':
    212 			m.template[i] = []float64(nil)
    213 			m.size[i] = 1 << 30
    214 		case 'h':
    215 			m.template[i] = int(-1)
    216 		case 'i':
    217 			m.template[i] = int32(0)
    218 		case 'I':
    219 			m.template[i] = []int32(nil)
    220 			m.size[i] = 1 << 30
    221 		case 's':
    222 			m.template[i] = ""
    223 			m.size[i] = 1 << 30
    224 		}
    225 	}
    226 
    227 	if err := m.pack(); err != nil {
    228 		r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
    229 		r.Done <- r
    230 		return
    231 	}
    232 
    233 	r.c.outMu.Lock()
    234 	r.c.s.send(&m)
    235 	r.c.outMu.Unlock()
    236 }
    237 
    238 // Call is a convenience wrapper that starts the RPC request,
    239 // waits for it to finish, and then returns the results.
    240 // Its implementation is:
    241 //
    242 //	r.Start(name, arg)
    243 //	r.Wait()
    244 //	return r.Ret, r.Errno
    245 //
    246 func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
    247 	r := c.NewRPC(nil)
    248 	r.Start(name, arg)
    249 	r.Wait()
    250 	return r.Ret, r.Err
    251 }
    252 
    253 // NewRPC creates a new RPC on the client connection.
    254 func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
    255 	if done == nil {
    256 		done = make(chan *srpc, 1)
    257 	}
    258 	c.mu.Lock()
    259 	id := c.idGen
    260 	c.idGen++
    261 	c.mu.Unlock()
    262 	return &srpc{Done: done, c: c, id: id}
    263 }
    264 
    265 // The current protocol number.
    266 // Kind of useless, since there have been backwards-incompatible changes
    267 // to the wire protocol that did not update the protocol number.
    268 // At this point it's really just a sanity check.
    269 const protocol = 0xc0da0002
    270 
    271 // An srpcErrno is an SRPC status code.
    272 type srpcErrno uint32
    273 
    274 const (
    275 	srpcOK srpcErrno = 256 + iota
    276 	srpcErrBreak
    277 	srpcErrMessageTruncated
    278 	srpcErrNoMemory
    279 	srpcErrProtocolMismatch
    280 	srpcErrBadRPCNumber
    281 	srpcErrBadArgType
    282 	srpcErrTooFewArgs
    283 	srpcErrTooManyArgs
    284 	srpcErrInArgTypeMismatch
    285 	srpcErrOutArgTypeMismatch
    286 	srpcErrInternalError
    287 	srpcErrAppError
    288 )
    289 
    290 var srpcErrstr = [...]string{
    291 	srpcOK - srpcOK:                    "ok",
    292 	srpcErrBreak - srpcOK:              "break",
    293 	srpcErrMessageTruncated - srpcOK:   "message truncated",
    294 	srpcErrNoMemory - srpcOK:           "out of memory",
    295 	srpcErrProtocolMismatch - srpcOK:   "protocol mismatch",
    296 	srpcErrBadRPCNumber - srpcOK:       "invalid RPC method number",
    297 	srpcErrBadArgType - srpcOK:         "unexpected argument type",
    298 	srpcErrTooFewArgs - srpcOK:         "too few arguments",
    299 	srpcErrTooManyArgs - srpcOK:        "too many arguments",
    300 	srpcErrInArgTypeMismatch - srpcOK:  "input argument type mismatch",
    301 	srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
    302 	srpcErrInternalError - srpcOK:      "internal error",
    303 	srpcErrAppError - srpcOK:           "application error",
    304 }
    305 
    306 func (e srpcErrno) Error() string {
    307 	if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
    308 		return "srpcErrno(" + itoa(int(e)) + ")"
    309 	}
    310 	return srpcErrstr[e-srpcOK]
    311 }
    312 
    313 // A msgHdr is the data argument to the imc_recvmsg
    314 // and imc_sendmsg system calls.
    315 type msgHdr struct {
    316 	iov   *iov
    317 	niov  int32
    318 	desc  *int32
    319 	ndesc int32
    320 	flags uint32
    321 }
    322 
    323 // A single region for I/O.
    324 type iov struct {
    325 	base *byte
    326 	len  int32
    327 }
    328 
    329 const maxMsgSize = 1<<16 - 4*4
    330 
    331 // A msgReceiver receives messages from a file descriptor.
    332 type msgReceiver struct {
    333 	fd   int
    334 	data [maxMsgSize]byte
    335 	desc [8]int32
    336 	hdr  msgHdr
    337 	iov  iov
    338 }
    339 
    340 func (r *msgReceiver) recv() (*msg, error) {
    341 	// Init pointers to buffers where syscall recvmsg can write.
    342 	r.iov.base = &r.data[0]
    343 	r.iov.len = int32(len(r.data))
    344 	r.hdr.iov = &r.iov
    345 	r.hdr.niov = 1
    346 	r.hdr.desc = &r.desc[0]
    347 	r.hdr.ndesc = int32(len(r.desc))
    348 	n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
    349 	if e != 0 {
    350 		println("Native Client imc_recvmsg: ", e.Error())
    351 		return nil, e
    352 	}
    353 
    354 	// Make a copy of the data so that the next recvmsg doesn't
    355 	// smash it.  The system call did not update r.iov.len.  Instead it
    356 	// returned the total byte count as n.
    357 	m := new(msg)
    358 	m.data = make([]byte, n)
    359 	copy(m.data, r.data[0:])
    360 
    361 	// Make a copy of the desc too.
    362 	// The system call *did* update r.hdr.ndesc.
    363 	if r.hdr.ndesc > 0 {
    364 		m.desc = make([]int32, r.hdr.ndesc)
    365 		copy(m.desc, r.desc[:])
    366 	}
    367 
    368 	return m, nil
    369 }
    370 
    371 // A msgSender sends messages on a file descriptor.
    372 type msgSender struct {
    373 	fd  int
    374 	hdr msgHdr
    375 	iov iov
    376 }
    377 
    378 func (s *msgSender) send(m *msg) error {
    379 	if len(m.data) > 0 {
    380 		s.iov.base = &m.data[0]
    381 	}
    382 	s.iov.len = int32(len(m.data))
    383 	s.hdr.iov = &s.iov
    384 	s.hdr.niov = 1
    385 	s.hdr.desc = nil
    386 	s.hdr.ndesc = 0
    387 	_, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
    388 	if e != 0 {
    389 		println("Native Client imc_sendmsg: ", e.Error())
    390 		return e
    391 	}
    392 	return nil
    393 }
    394 
    395 // A msg is the Go representation of an SRPC message.
    396 type msg struct {
    397 	data []byte  // message data
    398 	desc []int32 // message file descriptors
    399 
    400 	// parsed version of message
    401 	id        uint32
    402 	isRequest uint32
    403 	rpc       uint32
    404 	status    uint32
    405 	value     []interface{}
    406 	template  []interface{}
    407 	size      []int
    408 	format    string
    409 	broken    bool
    410 }
    411 
    412 // reading from a msg
    413 
    414 func (m *msg) uint32() uint32 {
    415 	if m.broken {
    416 		return 0
    417 	}
    418 	if len(m.data) < 4 {
    419 		m.broken = true
    420 		return 0
    421 	}
    422 	b := m.data[:4]
    423 	x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
    424 	m.data = m.data[4:]
    425 	return x
    426 }
    427 
    428 func (m *msg) uint64() uint64 {
    429 	x := uint64(m.uint32()) | uint64(m.uint32())<<32
    430 	if m.broken {
    431 		return 0
    432 	}
    433 	return x
    434 }
    435 
    436 func (m *msg) bytes(n int) []byte {
    437 	if m.broken {
    438 		return nil
    439 	}
    440 	if len(m.data) < n {
    441 		m.broken = true
    442 		return nil
    443 	}
    444 	x := m.data[0:n]
    445 	m.data = m.data[n:]
    446 	return x
    447 }
    448 
    449 // writing to a msg
    450 
    451 func (m *msg) wuint32(x uint32) {
    452 	m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
    453 }
    454 
    455 func (m *msg) wuint64(x uint64) {
    456 	lo := uint32(x)
    457 	hi := uint32(x >> 32)
    458 	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))
    459 }
    460 
    461 func (m *msg) wbytes(p []byte) {
    462 	m.data = append(m.data, p...)
    463 }
    464 
    465 func (m *msg) wstring(s string) {
    466 	m.data = append(m.data, s...)
    467 }
    468 
    469 // Parsing of RPC messages.
    470 //
    471 // Each message begins with
    472 //	total_size uint32
    473 //	total_descs uint32
    474 //	fragment_size uint32
    475 //	fragment_descs uint32
    476 //
    477 // If fragment_size < total_size or fragment_descs < total_descs, the actual
    478 // message is broken up in multiple messages; follow-up messages omit
    479 // the "total" fields and begin with the "fragment" fields.
    480 // We do not support putting fragmented messages back together.
    481 // To do this we would need to change the message receiver.
    482 //
    483 // After that size information, the message header follows:
    484 //	protocol uint32
    485 //	requestID uint32
    486 //	isRequest uint32
    487 //	rpcNumber uint32
    488 //	status uint32
    489 //	numValue uint32
    490 //	numTemplate uint32
    491 //
    492 // After the header come numTemplate fixed-size arguments,
    493 // numValue fixed-size arguments, and then the variable-sized
    494 // part of the values. The templates describe the expected results
    495 // and have no associated variable sized data in the request.
    496 //
    497 // Each fixed-size argument has the form:
    498 //	tag uint32 // really a char, like 'b' or 'C'
    499 //	pad uint32 // unused
    500 //	val1 uint32
    501 //	val2 uint32
    502 //
    503 // The tags are:
    504 //	'b':	bool; val1 == 0 or 1
    505 //	'C':	[]byte; val1 == len, data in variable-sized section
    506 //	'd':	float64; (val1, val2) is data
    507 //	'D':	[]float64; val1 == len, data in variable-sized section
    508 //	'h':	int; val1 == file descriptor
    509 //	'i':	int32; descriptor in next entry in m.desc
    510 //	'I':	[]int; val1 == len, data in variable-sized section
    511 //	's':	string; val1 == len, data in variable-sized section
    512 //
    513 
    514 func (m *msg) pack() error {
    515 	m.data = m.data[:0]
    516 	m.desc = m.desc[:0]
    517 
    518 	// sizes, to fill in later
    519 	m.wuint32(0)
    520 	m.wuint32(0)
    521 	m.wuint32(0)
    522 	m.wuint32(0)
    523 
    524 	// message header
    525 	m.wuint32(protocol)
    526 	m.wuint32(m.id)
    527 	m.wuint32(m.isRequest)
    528 	m.wuint32(m.rpc)
    529 	m.wuint32(m.status)
    530 	m.wuint32(uint32(len(m.value)))
    531 	m.wuint32(uint32(len(m.template)))
    532 
    533 	// fixed-size templates
    534 	for i, x := range m.template {
    535 		var tag, val1, val2 uint32
    536 		switch x.(type) {
    537 		default:
    538 			return errors.New("unexpected template type")
    539 		case bool:
    540 			tag = 'b'
    541 		case []byte:
    542 			tag = 'C'
    543 			val1 = uint32(m.size[i])
    544 		case float64:
    545 			tag = 'd'
    546 		case []float64:
    547 			tag = 'D'
    548 			val1 = uint32(m.size[i])
    549 		case int:
    550 			tag = 'h'
    551 		case int32:
    552 			tag = 'i'
    553 		case []int32:
    554 			tag = 'I'
    555 			val1 = uint32(m.size[i])
    556 		case string:
    557 			tag = 's'
    558 			val1 = uint32(m.size[i])
    559 		}
    560 		m.wuint32(tag)
    561 		m.wuint32(0)
    562 		m.wuint32(val1)
    563 		m.wuint32(val2)
    564 	}
    565 
    566 	// fixed-size values
    567 	for _, x := range m.value {
    568 		var tag, val1, val2 uint32
    569 		switch x := x.(type) {
    570 		default:
    571 			return errors.New("unexpected value type")
    572 		case bool:
    573 			tag = 'b'
    574 			if x {
    575 				val1 = 1
    576 			}
    577 		case []byte:
    578 			tag = 'C'
    579 			val1 = uint32(len(x))
    580 		case float64:
    581 			tag = 'd'
    582 			v := float64bits(x)
    583 			val1 = uint32(v)
    584 			val2 = uint32(v >> 32)
    585 		case []float64:
    586 			tag = 'D'
    587 			val1 = uint32(len(x))
    588 		case int32:
    589 			tag = 'i'
    590 			m.desc = append(m.desc, x)
    591 		case []int32:
    592 			tag = 'I'
    593 			val1 = uint32(len(x))
    594 		case string:
    595 			tag = 's'
    596 			val1 = uint32(len(x) + 1)
    597 		}
    598 		m.wuint32(tag)
    599 		m.wuint32(0)
    600 		m.wuint32(val1)
    601 		m.wuint32(val2)
    602 	}
    603 
    604 	// variable-length data for values
    605 	for _, x := range m.value {
    606 		switch x := x.(type) {
    607 		case []byte:
    608 			m.wbytes(x)
    609 		case []float64:
    610 			for _, f := range x {
    611 				m.wuint64(float64bits(f))
    612 			}
    613 		case []int32:
    614 			for _, j := range x {
    615 				m.wuint32(uint32(j))
    616 			}
    617 		case string:
    618 			m.wstring(x)
    619 			m.wstring("\x00")
    620 		}
    621 	}
    622 
    623 	// fill in sizes
    624 	data := m.data
    625 	m.data = m.data[:0]
    626 	m.wuint32(uint32(len(data)))
    627 	m.wuint32(uint32(len(m.desc)))
    628 	m.wuint32(uint32(len(data)))
    629 	m.wuint32(uint32(len(m.desc)))
    630 	m.data = data
    631 
    632 	return nil
    633 }
    634 
    635 func (m *msg) unpack() error {
    636 	totalSize := m.uint32()
    637 	totalDesc := m.uint32()
    638 	fragSize := m.uint32()
    639 	fragDesc := m.uint32()
    640 	if totalSize != fragSize || totalDesc != fragDesc {
    641 		return errors.New("Native Client: fragmented RPC messages not supported")
    642 	}
    643 	if m.uint32() != protocol {
    644 		return errors.New("Native Client: RPC protocol mismatch")
    645 	}
    646 
    647 	// message header
    648 	m.id = m.uint32()
    649 	m.isRequest = m.uint32()
    650 	m.rpc = m.uint32()
    651 	m.status = m.uint32()
    652 	m.value = make([]interface{}, m.uint32())
    653 	m.template = make([]interface{}, m.uint32())
    654 	m.size = make([]int, len(m.template))
    655 	if m.broken {
    656 		return errors.New("Native Client: malformed message")
    657 	}
    658 
    659 	// fixed-size templates
    660 	for i := range m.template {
    661 		tag := m.uint32()
    662 		m.uint32() // padding
    663 		val1 := m.uint32()
    664 		m.uint32() // val2
    665 		switch tag {
    666 		default:
    667 			return errors.New("Native Client: unexpected template type " + string(rune(tag)))
    668 		case 'b':
    669 			m.template[i] = false
    670 		case 'C':
    671 			m.template[i] = []byte(nil)
    672 			m.size[i] = int(val1)
    673 		case 'd':
    674 			m.template[i] = float64(0)
    675 		case 'D':
    676 			m.template[i] = []float64(nil)
    677 			m.size[i] = int(val1)
    678 		case 'i':
    679 			m.template[i] = int32(0)
    680 		case 'I':
    681 			m.template[i] = []int32(nil)
    682 			m.size[i] = int(val1)
    683 		case 'h':
    684 			m.template[i] = int(0)
    685 		case 's':
    686 			m.template[i] = ""
    687 			m.size[i] = int(val1)
    688 		}
    689 	}
    690 
    691 	// fixed-size values
    692 	var (
    693 		strsize []uint32
    694 		d       int
    695 	)
    696 	for i := range m.value {
    697 		tag := m.uint32()
    698 		m.uint32() // padding
    699 		val1 := m.uint32()
    700 		val2 := m.uint32()
    701 		switch tag {
    702 		default:
    703 			return errors.New("Native Client: unexpected value type " + string(rune(tag)))
    704 		case 'b':
    705 			m.value[i] = val1 > 0
    706 		case 'C':
    707 			m.value[i] = []byte(nil)
    708 			strsize = append(strsize, val1)
    709 		case 'd':
    710 			m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
    711 		case 'D':
    712 			m.value[i] = make([]float64, val1)
    713 		case 'i':
    714 			m.value[i] = int32(val1)
    715 		case 'I':
    716 			m.value[i] = make([]int32, val1)
    717 		case 'h':
    718 			m.value[i] = int(m.desc[d])
    719 			d++
    720 		case 's':
    721 			m.value[i] = ""
    722 			strsize = append(strsize, val1)
    723 		}
    724 	}
    725 
    726 	// variable-sized parts of values
    727 	for i, x := range m.value {
    728 		switch x := x.(type) {
    729 		case []byte:
    730 			m.value[i] = m.bytes(int(strsize[0]))
    731 			strsize = strsize[1:]
    732 		case []float64:
    733 			for i := range x {
    734 				x[i] = float64frombits(m.uint64())
    735 			}
    736 		case []int32:
    737 			for i := range x {
    738 				x[i] = int32(m.uint32())
    739 			}
    740 		case string:
    741 			m.value[i] = string(m.bytes(int(strsize[0])))
    742 			strsize = strsize[1:]
    743 		}
    744 	}
    745 
    746 	if len(m.data) > 0 {
    747 		return errors.New("Native Client: junk at end of message")
    748 	}
    749 	return nil
    750 }
    751 
    752 func float64bits(x float64) uint64 {
    753 	return *(*uint64)(unsafe.Pointer(&x))
    754 }
    755 
    756 func float64frombits(x uint64) float64 {
    757 	return *(*float64)(unsafe.Pointer(&x))
    758 }
    759 
    760 // At startup, connect to the name service.
    761 var nsClient = nsConnect()
    762 
    763 func nsConnect() *srpcClient {
    764 	var ns int32 = -1
    765 	_, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
    766 	if errno != 0 {
    767 		println("Native Client nameservice:", errno.Error())
    768 		return nil
    769 	}
    770 
    771 	sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
    772 	if errno != 0 {
    773 		println("Native Client nameservice connect:", errno.Error())
    774 		return nil
    775 	}
    776 
    777 	c, err := newClient(int(sock))
    778 	if err != nil {
    779 		println("Native Client nameservice init:", err.Error())
    780 		return nil
    781 	}
    782 
    783 	return c
    784 }
    785 
    786 const (
    787 	nsSuccess               = 0
    788 	nsNameNotFound          = 1
    789 	nsDuplicateName         = 2
    790 	nsInsufficientResources = 3
    791 	nsPermissionDenied      = 4
    792 	nsInvalidArgument       = 5
    793 )
    794 
    795 func openNamedService(name string, mode int32) (fd int, err error) {
    796 	if nsClient == nil {
    797 		return 0, errors.New("no name service")
    798 	}
    799 	ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
    800 	if err != nil {
    801 		return 0, err
    802 	}
    803 	status := ret[0].(int32)
    804 	fd = ret[1].(int)
    805 	switch status {
    806 	case nsSuccess:
    807 		// ok
    808 	case nsNameNotFound:
    809 		return -1, ENOENT
    810 	case nsDuplicateName:
    811 		return -1, EEXIST
    812 	case nsInsufficientResources:
    813 		return -1, EWOULDBLOCK
    814 	case nsPermissionDenied:
    815 		return -1, EPERM
    816 	case nsInvalidArgument:
    817 		return -1, EINVAL
    818 	default:
    819 		return -1, EINVAL
    820 	}
    821 	return fd, nil
    822 }
    823