ZeroTierOne/attic/go/pkg/zerotier/endpoint.go
2021-02-22 22:58:16 -05:00

178 lines
4.8 KiB
Go

/*
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
package zerotier
// #include "../../serviceiocore/GoGlue.h"
// const ZT_Fingerprint *_getFP(const ZT_Endpoint *ep) { return &(ep->value.fp); }
// uint64_t _getAddress(const ZT_Endpoint *ep) { return ep->value.fp.address; }
// uint64_t _getMAC(const ZT_Endpoint *ep) { return ep->value.mac; }
// const struct sockaddr_storage *_getSS(const ZT_Endpoint *ep) { return &(ep->value.ss); }
// void _setSS(ZT_Endpoint *ep,const void *ss) { memcpy(&(ep->value.ss),ss,sizeof(struct sockaddr_storage)); }
import "C"
import (
"encoding/json"
"unsafe"
)
const (
EndpointTypeNil = C.ZT_ENDPOINT_TYPE_NIL
EndpointTypeZeroTier = C.ZT_ENDPOINT_TYPE_ZEROTIER
EndpointTypeEthernet = C.ZT_ENDPOINT_TYPE_ETHERNET
EndpointTypeWifiDirect = C.ZT_ENDPOINT_TYPE_WIFI_DIRECT
EndpointTypeBluetooth = C.ZT_ENDPOINT_TYPE_BLUETOOTH
EndpointTypeIp = C.ZT_ENDPOINT_TYPE_IP
EndpointTypeIpUdp = C.ZT_ENDPOINT_TYPE_IP_UDP
EndpointTypeIpTcp = C.ZT_ENDPOINT_TYPE_IP_TCP
EndpointTypeIpHttp = C.ZT_ENDPOINT_TYPE_IP_HTTP
)
type Endpoint struct {
cep C.ZT_Endpoint
}
func EndpointTypeToString(t int) string {
switch t {
case EndpointTypeZeroTier:
return "zerotier"
case EndpointTypeEthernet:
return "ethernet"
case EndpointTypeWifiDirect:
return "wifi-direct"
case EndpointTypeBluetooth:
return "bluetooth"
case EndpointTypeIp:
return "ip/raw"
case EndpointTypeIpUdp:
return "ip/udp"
case EndpointTypeIpTcp:
return "ip/tcp"
case EndpointTypeIpHttp:
return "ip/http"
}
return "unsupported"
}
// NewEndpointFromString constructs a new endpoint from an InetAddress or Endpoint string.
// This will auto detect whether this is a plain InetAddress or an Endpoint in string
// format. If the former it's created as a ZT_ENDPOINT_TYPE_IP_UDP endpoint.
func NewEndpointFromString(s string) (*Endpoint, error) {
if len(s) == 0 {
var ep Endpoint
ep.cep._type = C.ZT_ENDPOINT_TYPE_NIL
return &ep, nil
}
var ep Endpoint
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))
if C.ZT_Endpoint_fromString(&ep.cep, cs) != 0 {
return nil, ErrInvalidParameter
}
return &ep, nil
}
func NewEndpointFromInetAddress(addr *InetAddress) (*Endpoint, error) {
var ep Endpoint
var ss C.struct_sockaddr_storage
if !makeSockaddrStorage(addr.IP, addr.Port, &ss) {
return nil, ErrInvalidParameter
}
ep.cep._type = C.ZT_ENDPOINT_TYPE_IP_UDP
C._setSS(&ep.cep, unsafe.Pointer(&ss))
return &ep, nil
}
// Type returns this endpoint's type.
func (ep *Endpoint) Type() int {
return int(ep.cep._type)
}
// TypeString returns a human-readable endpoint type.
func (ep *Endpoint) TypeString() string {
return EndpointTypeToString(int(ep.cep._type))
}
// InetAddress gets this Endpoint as an InetAddress or nil if its type is not addressed by one.
func (ep *Endpoint) InetAddress() *InetAddress {
switch ep.cep._type {
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp:
ua := sockaddrStorageToUDPAddr(C._getSS(&ep.cep))
return &InetAddress{IP: ua.IP, Port: ua.Port}
}
return nil
}
// Address returns a ZeroTier address if this is a ZeroTier endpoint or a zero address otherwise.
func (ep *Endpoint) Address() Address {
switch ep.cep._type {
case EndpointTypeZeroTier:
return Address(C._getAddress(&ep.cep))
}
return Address(0)
}
// Fingerprint returns a fingerprint if this is a ZeroTier endpoint or nil otherwise.
func (ep *Endpoint) Fingerprint() *Fingerprint {
switch ep.cep._type {
case EndpointTypeZeroTier:
cfp := C._getFP(&ep.cep)
fp := Fingerprint{Address: Address(cfp.address), Hash: C.GoBytes(unsafe.Pointer(&cfp.hash[0]), 48)}
if allZero(fp.Hash) {
fp.Hash = nil
}
return &fp
}
return nil
}
// MAC returns a MAC address if this is an Ethernet type endpoint or a zero address otherwise.
func (ep *Endpoint) MAC() MAC {
switch ep.cep._type {
case EndpointTypeEthernet, EndpointTypeWifiDirect, EndpointTypeBluetooth:
return MAC(C._getMAC(&ep.cep))
}
return MAC(0)
}
func (ep *Endpoint) String() string {
var buf [4096]byte
cs := C.ZT_Endpoint_toString(&ep.cep, (*C.char)(unsafe.Pointer(&buf[0])), 4096)
if cs == nil {
return "0"
}
return C.GoString(cs)
}
func (ep *Endpoint) MarshalJSON() ([]byte, error) {
s := ep.String()
return json.Marshal(&s)
}
func (ep *Endpoint) UnmarshalJSON(j []byte) error {
var s string
err := json.Unmarshal(j, &s)
if err != nil {
return err
}
ep2, err := NewEndpointFromString(s)
if err != nil {
return err
}
*ep = *ep2
return nil
}
func (ep *Endpoint) setFromCEndpoint(cp *C.ZT_Endpoint) {
ep.cep = *cp
}