How does a 3rd party (Go/Golang) app call a service?

@CoRfr outside the sandbox is the same behavior.

Last time I’ve tried CoreOS it was a pain to debug exactly for the reason that you couldn’t really use the normal linux debugging tools. So careful what you wish for :slight_smile:

The fact that the directory service does not respond means that it is either dropping the message silently or that it is not permitted to send a response and won’t even send an error. I’ll try to find the source for the directory service but does this ring any bell? Also, is there a quick way for me to recompile the directory service so that I can add some debug messages or do I have to rebuild legato for this?

@CoRfr found it. The binding definition was wrong. Must be printServer.printer and not printerService.printer. Now I can implement the rest of the protocol … :slight_smile:

This is more idiomatic Go using the net package and that works now as well:

package main

import (
	"bytes"
	"encoding/binary"
	"log"
	"net"
)

const (
	ProtocolID          = "e2533dc76a5bf9ba6b2d3e74d8f95bd6" // /legato/apps/sample/helloIpc/printer.api
	ServiceInstanceName = "printer"
	MaxMsgSize          = 112
	msgID_printer_Print = 0

	sock = "/tmp/legato/serviceDirectoryClient"
)

type OpenMsg struct {
	MaxSize  uint32
	ProtoID  [128]byte
	IntfName [128]byte
	Wait     bool
	_        [3]byte // padding
}

func NewOpenMsg() *OpenMsg {
	openMsg := &OpenMsg{
		MaxSize: MaxMsgSize + 4,
		Wait:    true,
	}
	copy(openMsg.ProtoID[:], []byte(ProtocolID))
	copy(openMsg.IntfName[:], []byte(ServiceInstanceName))
	return openMsg
}

func main() {
	conn, err := net.Dial("unixpacket", sock)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	msg := NewOpenMsg()
	var b bytes.Buffer
	if err := binary.Write(&b, binary.LittleEndian, msg); err != nil {
		log.Fatal(err)
	}

	n, err := conn.Write(b.Bytes())
	if err != nil {
		log.Fatal(err)
	}

	buf := make([]byte, 4)
	n, err = conn.Read(buf)
	if err != nil {
		log.Fatal(err)
	}
	buf = buf[:n]
	log.Printf("resp: buf: %#v", buf)
	log.Print("Done")
}

Oh that is really nice!

I guess that file could be generated by ifgen with the appropriate values regarding ProtocolID and ServiceInstanceName, but that opens things a bit.

One big thing as well is the rest of the IPC, as there needs to be a packing/unpacking of things that goes on the wire.
It might be possible to reuse quite a bit of what other languages are doing like the python implementation is doing, cf https://github.com/legatoproject/legato-af/blob/master/framework/tools/ifgen/langPython/__init__.py for instance.

Success. This works:

package main

import (
	"bytes"
	"encoding/binary"
	"log"
	"net"
	"unsafe"
)

const (
	ProtocolID          = "e2533dc76a5bf9ba6b2d3e74d8f95bd6" // /legato/apps/sample/helloIpc/printer.api
	ServiceInstanceName = "printer"
	MaxMsgSize          = 112
	msgID_printer_Print = 0

	sock = "/tmp/legato/serviceDirectoryClient"
)

type OpenMsg struct {
	MaxSize  uint32
	ProtoID  [128]byte
	IntfName [128]byte
	Wait     bool
	_        [3]byte // padding
}

func NewOpenMsg() *OpenMsg {
	openMsg := &OpenMsg{
		MaxSize: MaxMsgSize + 4,
		Wait:    true,
	}
	copy(openMsg.ProtoID[:], []byte(ProtocolID))
	copy(openMsg.IntfName[:], []byte(ServiceInstanceName))
	return openMsg
}

func main() {
	// log.Print("Starting socket")
	// time.Sleep(10 * time.Second)

	conn, err := net.Dial("unixpacket", sock)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	if err := SendMsg(conn, NewOpenMsg()); err != nil {
		log.Fatal(err)
	}

	var res int32
	if err := ReadMsg(conn, &res); err != nil {
		log.Fatal(err)
	}
	if res != 0 {
		log.Fatal("got %d want 0", res)
	}

	log.Print("Session Created")

	type PrinterMessage struct {
		TxID    uint32 // pointer size 32 or 64 bit I guess
		MsgID   uint32
		Len     uint32
		Payload [MaxMsgSize - 4]byte
	}

	data := []byte("Hello from Go")
	msg := &PrinterMessage{
		TxID:  0xabbaabba,
		MsgID: msgID_printer_Print,
		Len:   uint32(len(data)),
	}
	copy(msg.Payload[:], data)
	if err := SendMsg(conn, msg); err != nil {
		log.Fatal(err)
	}
	log.Print("message sent")
	log.Print("Done")
}

func SendMsg(conn net.Conn, v interface{}) error {
	var b bytes.Buffer
	if err := binary.Write(&b, binary.LittleEndian, v); err != nil {
		return err
	}

	_, err := conn.Write(b.Bytes())
	return err
}

func ReadMsg(conn net.Conn, v interface{}) error {
	b := make([]byte, unsafe.Sizeof(v))
	n, err := conn.Read(b)
	if err != nil {
		return err
	}
	b = b[:n]
	return binary.Read(bytes.NewReader(b), binary.LittleEndian, v)
}

Now for cleaning up the code and message multiplexing… :slight_smile: