Lookup message name by ID when receiving unexpected message
[govpp.git] / adapter / vppapiclient / vppapiclient_adapter.go
index 82c820e..e9948e8 100644 (file)
@@ -77,12 +77,22 @@ govpp_get_msg_index(char *name_and_crc)
 import "C"
 
 import (
-       "errors"
        "fmt"
+       "os"
        "reflect"
        "unsafe"
 
-       "gerrit.fd.io/r/govpp.git/adapter"
+       "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 name of the file in the watchedFolder. Once the file is present
+       // the vpp is ready to accept a new connection.
+       watchedFile = watchedFolder + "vpe-api"
 )
 
 // vppAPIClientAdapter is the opaque context of the adapter.
@@ -114,12 +124,12 @@ func (a *vppAPIClientAdapter) Disconnect() {
 
 // 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
@@ -139,6 +149,42 @@ func (a *vppAPIClientAdapter) SetMsgCallback(cb func(context uint32, msgID uint1
        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
+       }
+
+       if fileExists(watchedFile) {
+               return nil
+       }
+
+       for {
+               ev := <-watcher.Events
+               if ev.Name == watchedFile && (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