}
static int
-govpp_connect()
+govpp_connect (char *shm)
{
- return vac_connect("govpp", NULL, govpp_msg_callback, 32);
+ return vac_connect("govpp", shm, govpp_msg_callback, 32);
}
static int
import "C"
import (
- "errors"
"fmt"
+ "os"
"reflect"
"unsafe"
"git.fd.io/govpp.git/adapter"
+ "github.com/fsnotify/fsnotify"
+)
+
+const (
+ // watchedFolder is a folder where vpp's shared memory is supposed to be created.
+ // File system events are monitored in this folder.
+ watchedFolder = "/dev/shm/"
+ // watchedFile is a default name of the file in the watchedFolder. Once the file is present,
+ // the vpp is ready to accept a new connection.
+ watchedFile = "vpe-api"
)
// vppAPIClientAdapter is the opaque context of the adapter.
type vppAPIClientAdapter struct {
- callback func(context uint32, msgId uint16, data []byte)
+ shmPrefix string
+ callback func(context uint32, msgId uint16, data []byte)
}
var vppClient *vppAPIClientAdapter // global vpp API client adapter context
// NewVppAdapter returns a new vpp API client adapter.
-func NewVppAdapter() adapter.VppAdapter {
- return &vppAPIClientAdapter{}
+func NewVppAdapter(shmPrefix string) adapter.VppAdapter {
+ return &vppAPIClientAdapter{
+ shmPrefix: shmPrefix,
+ }
}
// Connect connects the process to VPP.
func (a *vppAPIClientAdapter) Connect() error {
vppClient = a
- rc := C.govpp_connect()
+ var rc _Ctype_int
+ if a.shmPrefix == "" {
+ rc = C.govpp_connect(nil)
+ } else {
+ shm := C.CString(a.shmPrefix)
+ rc = C.govpp_connect(shm)
+ }
if rc != 0 {
return fmt.Errorf("unable to connect to VPP (error=%d)", rc)
}
// GetMsgID returns a runtime message ID for the given message name and CRC.
func (a *vppAPIClientAdapter) GetMsgID(msgName string, msgCrc string) (uint16, error) {
- nameAndCrc := C.CString(fmt.Sprintf("%s_%s", msgName, msgCrc))
+ nameAndCrc := C.CString(msgName + "_" + msgCrc)
defer C.free(unsafe.Pointer(nameAndCrc))
msgID := uint16(C.govpp_get_msg_index(nameAndCrc))
if msgID == ^uint16(0) {
- return msgID, errors.New("unkonwn message")
+ return msgID, fmt.Errorf("unknown message: %v (crc: %v)", msgName, msgCrc)
}
return msgID, nil
a.callback = cb
}
+// WaitReady blocks until shared memory for sending
+// binary api calls is present on the file system.
+func (a *vppAPIClientAdapter) WaitReady() error {
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ return err
+ }
+ defer watcher.Close()
+
+ err = watcher.Add(watchedFolder)
+ if err != nil {
+ return err
+ }
+ // Path to the shared memory segment with prefix, if set
+ var path string
+ if a.shmPrefix == "" {
+ path = watchedFolder + watchedFile
+ } else {
+ path = watchedFolder + a.shmPrefix + "-" + watchedFile
+ }
+ if fileExists(path) {
+ return nil
+ }
+
+ for {
+ ev := <-watcher.Events
+ if ev.Name == path && (ev.Op&fsnotify.Create) == fsnotify.Create {
+ break
+ }
+ }
+ return nil
+}
+
+func fileExists(name string) bool {
+ if _, err := os.Stat(name); err != nil {
+ if os.IsNotExist(err) {
+ return false
+ }
+ }
+ return true
+}
+
//export go_msg_callback
func go_msg_callback(msgID C.uint16_t, context C.uint32_t, data unsafe.Pointer, size C.size_t) {
// convert unsafe.Pointer to byte slice
byteArr := *(*[]byte)(unsafe.Pointer(slice))
vppClient.callback(uint32(context), uint16(msgID), byteArr)
-}
+}
\ No newline at end of file