// Copyright 2009 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.

// SRPC server

package srpc

import (
	"bytes"
	"log"
	"os"
	"syscall"
)

// TODO(rsc): I'd prefer to make this
//	type Handler func(m *msg) Errno
// but NaCl can't use closures.
// The explicit interface is a way to attach state.

// A Handler is a handler for an SRPC method.
// It reads arguments from arg, checks size for array limits,
// writes return values to ret, and returns an Errno status code.
type Handler interface {
	Run(arg, ret []interface{}, size []int) Errno
}

type method struct {
	name    string
	fmt     string
	handler Handler
}

var rpcMethod []method

// BUG(rsc): Add's format string should be replaced by analyzing the
// type of an arbitrary func passed in an interface{} using reflection.

// Add registers a handler for the named method.
// Fmt is a Native Client format string, a sequence of
// alphabetic characters representing the types of the parameter values,
// a colon, and then a sequence of alphabetic characters
// representing the types of the returned values.
// The format characters and corresponding dynamic types are:
//
//	b	bool
//	C	[]byte
//	d	float64
//	D	[]float64
//	h	int	// a file descriptor (aka handle)
//	i	int32
//	I	[]int32
//	s	string
//
func Add(name, fmt string, handler Handler) {
	n := len(rpcMethod)
	if n >= cap(rpcMethod) {
		a := make([]method, n, (n+4)*2)
		for i := range a {
			a[i] = rpcMethod[i]
		}
		rpcMethod = a
	}
	rpcMethod = rpcMethod[0 : n+1]
	rpcMethod[n] = method{name, fmt, handler}
}

// Serve accepts new SRPC connections from the file descriptor fd
// and answers RPCs issued on those connections.
// It closes fd and returns an error if the imc_accept system call fails.
func Serve(fd int) os.Error {
	defer syscall.Close(fd)

	for {
		cfd, _, e := syscall.Syscall(syscall.SYS_IMC_ACCEPT, uintptr(fd), 0, 0)
		if e != 0 {
			return os.NewSyscallError("imc_accept", int(e))
		}
		go serveLoop(int(cfd))
	}
	panic("unreachable")
}

func serveLoop(fd int) {
	c := make(chan *msg)
	go sendLoop(fd, c)

	var r msgReceiver
	r.fd = fd
	for {
		m, err := r.recv()
		if err != nil {
			break
		}
		m.unpackRequest()
		if !m.gotHeader {
			log.Stderrf("cannot unpack header: %s", m.status)
			continue
		}
		// log.Stdoutf("<- %#v", m);
		m.isReq = false // set up for response
		go serveMsg(m, c)
	}
	close(c)
}

func sendLoop(fd int, c <-chan *msg) {
	var s msgSender
	s.fd = fd
	for m := range c {
		// log.Stdoutf("-> %#v", m);
		m.packResponse()
		s.send(m)
	}
	syscall.Close(fd)
}

func serveMsg(m *msg, c chan<- *msg) {
	if m.status != OK {
		c <- m
		return
	}
	if m.rpcNumber >= uint32(len(rpcMethod)) {
		m.status = ErrBadRPCNumber
		c <- m
		return
	}

	meth := &rpcMethod[m.rpcNumber]
	if meth.fmt != m.fmt {
		switch {
		case len(m.fmt) < len(meth.fmt):
			m.status = ErrTooFewArgs
		case len(m.fmt) > len(meth.fmt):
			m.status = ErrTooManyArgs
		default:
			// There's a type mismatch.
			// It's an in-arg mismatch if the mismatch happens
			// before the colon; otherwise it's an out-arg mismatch.
			m.status = ErrInArgTypeMismatch
			for i := 0; i < len(m.fmt) && m.fmt[i] == meth.fmt[i]; i++ {
				if m.fmt[i] == ':' {
					m.status = ErrOutArgTypeMismatch
					break
				}
			}
		}
		c <- m
		return
	}

	m.status = meth.handler.Run(m.Arg, m.Ret, m.Size)
	c <- m
}

// ServeRuntime serves RPCs issued by the Native Client embedded runtime.
// This should be called by main once all methods have been registered using Add.
func ServeRuntime() os.Error {
	// Call getFd to check that we are running embedded.
	if _, err := getFd(); err != nil {
		return err
	}

	// We are running embedded.
	// The fd returned by getFd is a red herring.
	// Accept connections on magic fd 3.
	return Serve(3)
}

// getFd runs the srpc_get_fd system call.
func getFd() (fd int, err os.Error) {
	r1, _, e := syscall.Syscall(syscall.SYS_SRPC_GET_FD, 0, 0, 0)
	return int(r1), os.NewSyscallError("srpc_get_fd", int(e))
}

// Enabled returns true if SRPC is enabled in the Native Client runtime.
func Enabled() bool {
	_, err := getFd()
	return err == nil
}

// Service #0, service_discovery, returns a list of the other services
// and their argument formats.
type serviceDiscovery struct{}

func (serviceDiscovery) Run(arg, ret []interface{}, size []int) Errno {
	var b bytes.Buffer
	for _, m := range rpcMethod {
		b.WriteString(m.name)
		b.WriteByte(':')
		b.WriteString(m.fmt)
		b.WriteByte('\n')
	}
	if b.Len() > size[0] {
		return ErrNoMemory
	}
	ret[0] = b.Bytes()
	return OK
}

func init() { Add("service_discovery", ":C", serviceDiscovery{}) }
