+ conn, err := net.DialUnix(addr.Net, nil, &addr)
+ if err != nil {
+ Log.Warnf("connecting to socket %s failed: %s", addr, err)
+ return nil, err
+ }
+ defer func() {
+ if err := conn.Close(); err != nil {
+ Log.Warnf("closing socket failed: %v", err)
+ }
+ }()
+ Log.Debugf("connected to socket")
+
+ files, err := fd.Get(conn, 1, nil)
+ if err != nil {
+ return nil, fmt.Errorf("getting file descriptor over socket failed: %v", err)
+ }
+ if len(files) == 0 {
+ return nil, fmt.Errorf("no files received over socket")
+ }
+
+ file := files[0]
+ defer func() {
+ if err := file.Close(); err != nil {
+ Log.Warnf("closing file failed: %v", err)
+ }
+ }()
+
+ info, err := file.Stat()
+ if err != nil {
+ return nil, err
+ }
+ size := info.Size()
+
+ sc.headerData, err = syscall.Mmap(int(file.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
+ if err != nil {
+ Log.Debugf("mapping shared memory failed: %v", err)
+ return nil, fmt.Errorf("mapping shared memory failed: %v", err)
+ }
+ Log.Debugf("successfully mmapped shared memory segment (size: %v) %v", size, len(sc.headerData))
+
+ version := getVersion(sc.headerData)
+ switch version {
+ case 1:
+ ss = newStatSegmentV1(sc.headerData, size)
+ case 2:
+ ss = newStatSegmentV2(sc.headerData, size)
+ default:
+ return nil, fmt.Errorf("stat segment version is not supported: %v (min: %v, max: %v)",
+ version, minVersion, maxVersion)
+ }
+
+ 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.checkSocketValid(); 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 {
+ 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")