+ sc.isConnected = true
+ return ss, nil
+}
+
+// reconnect disconnects from the socket, re-validates it and
+// connects again
+func (sc *StatsClient) reconnect() (err error) {
+ if err = sc.disconnect(); err != nil {
+ return fmt.Errorf("error disconnecting socket: %v", err)
+ }
+ if err = sc.validate(); err != nil {
+ return fmt.Errorf("error validating socket: %v", err)
+ }
+ if sc.statSegment, err = sc.connect(); err != nil {
+ return fmt.Errorf("error connecting socket: %v", err)
+ }
+ return nil
+}
+
+// disconnect unmaps socket data from the memory and resets the header
+func (sc *StatsClient) disconnect() error {
+ sc.isConnected = false
+ if sc.headerData == nil {
+ return nil
+ }
+ if err := syscall.Munmap(sc.headerData); err != nil {
+ Log.Debugf("unmapping shared memory failed: %v", err)
+ return fmt.Errorf("unmapping shared memory failed: %v", err)
+ }
+ sc.headerData = nil
+
+ Log.Debugf("successfully unmapped shared memory")
+ return nil
+}
+
+func (sc *StatsClient) monitorSocket() {
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ Log.Errorf("error starting socket monitor: %v", err)
+ return
+ }
+
+ go func() {
+ for {
+ select {
+ case event := <-watcher.Events:
+ if event.Op == fsnotify.Remove {
+ if err := sc.reconnect(); err != nil {
+ Log.Errorf("error occurred during socket reconnect: %v", err)
+ }
+ // path must be re-added to the watcher
+ if err = watcher.Add(sc.sockAddr); err != nil {
+ Log.Errorf("failed to add socket address to the watcher: %v", err)
+ }
+ }
+ case err := <-watcher.Errors:
+ Log.Errorf("socket monitor delivered error event: %v", err)
+ case <-sc.done:
+ err := watcher.Close()
+ Log.Debugf("socket monitor closed (error: %v)", err)
+ return
+ }
+ }
+ }()
+
+ if err := watcher.Add(sc.sockAddr); err != nil {
+ Log.Errorf("failed to add socket address to the watcher: %v", err)
+ }