github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/services/sm/sm.go (about)

     1  package sm
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/racerxdl/gonx/nx/nxerrors"
     6  	"github.com/racerxdl/gonx/nx/nxtypes"
     7  	"github.com/racerxdl/gonx/services/ipc"
     8  	"github.com/racerxdl/gonx/svc"
     9  )
    10  
    11  var smInitializations = 0
    12  var smObject ipc.Object
    13  
    14  const (
    15  	smServiceName = "sm:\x00"
    16  	debugSm       = false
    17  )
    18  
    19  // str2u64 converts a string to uint64 representation
    20  // used on SM service name
    21  func str2u64(str string) uint64 {
    22  	var b [8]byte
    23  
    24  	for i := 0; i < 8; i++ {
    25  		if len(str) <= i {
    26  			break
    27  		}
    28  		b[i] = str[i]
    29  	}
    30  
    31  	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
    32  		uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
    33  }
    34  
    35  // Init initializes the SM Service if needed
    36  func Init() error {
    37  	if debugSm {
    38  		println("SM::Init")
    39  	}
    40  	if smInitializations > 0 {
    41  		smInitializations++ // Already initialized, increment ref count
    42  		return nil
    43  	}
    44  
    45  	smInitializations++
    46  
    47  	smObject.ObjectID = -1
    48  	handle := nxtypes.Handle(0)
    49  	smName := []byte(smServiceName)
    50  	r := svc.ConnectToNamedPort(&handle, &smName[0])
    51  	if r != nxtypes.ResultOK {
    52  		smInitializations--
    53  		return nxerrors.IPCError{
    54  			Message: "error initializing sm",
    55  			Result:  r,
    56  		}
    57  	}
    58  
    59  	smObject.SetSession(handle)
    60  
    61  	// sm:#0 Initialize
    62  	rq := ipc.MakeDefaultRequest(0)
    63  	rq.SendPID = true
    64  	rq.SetRawDataFromUint64(uint64(0))
    65  
    66  	rs := ipc.ResponseFmt{}
    67  
    68  	err := ipc.Send(smObject, &rq, &rs)
    69  	if err != nil {
    70  		if debugSm {
    71  			fmt.Printf("error initializing sm: %s", err)
    72  		}
    73  		_ = ipc.Close(&smObject)
    74  		smInitializations--
    75  		return err
    76  	}
    77  
    78  	return nil
    79  }
    80  
    81  // Finalize closes the a initialized SM Service
    82  func Finalize() {
    83  	smInitializations--
    84  	if smInitializations == 0 {
    85  		smForceFinalize()
    86  	}
    87  }
    88  
    89  func smForceFinalize() {
    90  	_ = ipc.Close(&smObject)
    91  	smInitializations = 0
    92  }
    93  
    94  func GetService(outObject *ipc.Object, name string) error {
    95  	if debugSm {
    96  		fmt.Printf("SM::GetService(%p, %s)\n", outObject, name)
    97  	}
    98  	if smObject.GetSession() == 0 {
    99  		return nxerrors.SmNotInitialized
   100  	}
   101  
   102  	if len(name) > 8 {
   103  		return nxerrors.SmServiceNameTooLong
   104  	}
   105  
   106  	serviceName := str2u64(name)
   107  	outObject.ObjectID = -1
   108  	outObject.IsBorrowed = false
   109  
   110  	rq := ipc.MakeDefaultRequest(1)
   111  	rq.SetRawDataFromUint64(serviceName)
   112  
   113  	rs := ipc.ResponseFmt{}
   114  	rs.MoveHandles = make([]nxtypes.Handle, 1)
   115  
   116  	err := ipc.Send(smObject, &rq, &rs)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	outObject.SetSession(rs.MoveHandles[0])
   122  
   123  	return nil
   124  }