package salticidae
// #include <stdlib.h>
// #include "salticidae/network.h"
import "C"
import "runtime"
// The C pointer type for a MsgNetwork handle.
type CMsgNetwork = *C.msgnetwork_t
type msgNetwork struct { inner CMsgNetwork }
// The handle for a message network.
type MsgNetwork = *msgNetwork
// Convert an existing C pointer into a go object. Notice that when the go
// object does *not* own the resource of the C pointer, so it is only valid to
// the extent in which the given C pointer is valid. The C memory will not be
// deallocated when the go object is finalized by GC. This applies to all other
// "FromC" functions.
func MsgNetworkFromC(ptr CMsgNetwork) MsgNetwork {
return &msgNetwork{ inner: ptr }
}
// The C pointer type for a MsgNetworkConn handle.
type CMsgNetworkConn = *C.msgnetwork_conn_t
type msgNetworkConn struct {
inner CMsgNetworkConn
autoFree bool
}
// The handle for a message network connection.
type MsgNetworkConn = *msgNetworkConn
func MsgNetworkConnFromC(ptr CMsgNetworkConn) MsgNetworkConn {
return &msgNetworkConn{ inner: ptr }
}
var (
CONN_MODE_ACTIVE = MsgNetworkConnMode(C.CONN_MODE_ACTIVE)
CONN_MODE_PASSIVE = MsgNetworkConnMode(C.CONN_MODE_PASSIVE)
)
// The connection mode. CONN_MODE_ACTIVE: a connection established from the
// local side. CONN_MODE_PASSIVE: a connection established from the remote
// side. CONN_MODE_DEAD: a connection that is already closed.
type MsgNetworkConnMode = C.msgnetwork_conn_mode_t
func msgNetworkConnSetFinalizer(res MsgNetworkConn, autoFree bool) {
res.autoFree = autoFree
if res != nil && autoFree {
runtime.SetFinalizer(res, func(self MsgNetworkConn) { self.Free() })
}
}
func (self MsgNetworkConn) Free() {
C.msgnetwork_conn_free(self.inner)
if self.autoFree {
runtime.SetFinalizer(self, nil)
}
}
// Get the corresponding MsgNetwork handle that manages this connection. The
// returned handle is only valid during the lifetime of this connection.
func (self MsgNetworkConn) GetNet() MsgNetwork {
return MsgNetworkFromC(C.msgnetwork_conn_get_net(self.inner))
}
func (self MsgNetworkConn) GetMode() MsgNetworkConnMode {
return C.msgnetwork_conn_get_mode(self.inner)
}
// Get the address of the remote end of this connection. Use Copy() to make a
// copy of the address if you want to use the address object beyond the
// lifetime of the connection.
func (self MsgNetworkConn) GetAddr() NetAddr {
return NetAddrFromC(C.msgnetwork_conn_get_addr(self.inner))
}
// Check if the connection has been terminated.
func (self MsgNetworkConn) IsTerminated() bool {
return bool(C.msgnetwork_conn_is_terminated(self.inner))
}
// Get the certificate of the remote end of this connection. Use Copy() to make a
// copy of the certificate if you want to use the certificate object beyond the
// lifetime of the connection.
func (self MsgNetworkConn) GetPeerCert() X509 {
return &x509{ inner: C.msgnetwork_conn_get_peer_cert(self.inner) }
}
// Make a copy of the object. This is required if you want to keep the
// connection passed as a callback parameter by other salticidae methods (such
// like MsgNetwork/PeerNetwork).
func (self MsgNetworkConn) Copy(autoFree bool) MsgNetworkConn {
res := MsgNetworkConnFromC(C.msgnetwork_conn_copy(self.inner))
msgNetworkConnSetFinalizer(res, autoFree)
return res
}
// The C pointer type for a MsgNetworkConfig object.
type CMsgNetworkConfig = *C.msgnetwork_config_t
type msgNetworkConfig struct { inner CMsgNetworkConfig }
// Configuration for MsgNetwork.
type MsgNetworkConfig = *msgNetworkConfig
func MsgNetworkConfigFromC(ptr CMsgNetworkConfig) MsgNetworkConfig {
return &msgNetworkConfig{ inner: ptr }
}
// Create the configuration object with default settings.
func NewMsgNetworkConfig() MsgNetworkConfig {
res := MsgNetworkConfigFromC(C.msgnetwork_config_new())
runtime.SetFinalizer(res, func(self MsgNetworkConfig) { self.free() })
return res
}
func (self MsgNetworkConfig) free() { C.msgnetwork_config_free(self.inner) }
// Set the number of consecutive read attempts in the message delivery queue.
// Usually the default value is good enough. This is used to make the tradeoff
// between the event loop fairness and the amortization of syscall cost.
func (self MsgNetworkConfig) BurstSize(size int) {
C.msgnetwork_config_burst_size(self.inner, C.size_t(size))
}
// Set the maximum backlogs (see POSIX TCP backlog).
func (self MsgNetworkConfig) MaxListenBacklog(backlog int) {
C.msgnetwork_config_max_listen_backlog(self.inner, C.int(backlog))
}
// Set the timeout for connecting to the remote (in seconds).
func (self MsgNetworkConfig) ConnServerTimeout(timeout float64) {
C.msgnetwork_config_conn_server_timeout(self.inner, C.double(timeout))
}
// Set the size for an inbound data chunk (per read() syscall).
func (self MsgNetworkConfig) SegBuffSize(size int) {
C.msgnetwork_config_seg_buff_size(self.inner, C.size_t(size))
}
// Set the number of worker threads.
func (self MsgNetworkConfig) NWorker(nworker int) {
C.msgnetwork_config_nworker(self.inner, C.size_t(nworker))
}
// Set the capacity of the send buffer.
func (self MsgNetworkConfig) QueueCapacity(capacity int) {
C.msgnetwork_config_queue_capacity(self.inner, C.size_t(capacity))
}
// Specify whether to use SSL/TLS. When this flag is enabled, MsgNetwork uses
// TLSKey (or TLSKeyFile) or TLSCert (or TLSCertFile) to setup the underlying
// OpenSSL.
func (self MsgNetworkConfig) EnableTLS(enabled bool) {
C.msgnetwork_config_enable_tls(self.inner, C.bool(enabled))
}
// Load the TLS key from a file. The file should be an unencrypted PEM file.
// Use TLSKey() instead for more complex usage.
func (self MsgNetworkConfig) TLSKeyFile(fname string) {
c_str := C.CString(fname)
C.msgnetwork_config_tls_key_file(self.inner, c_str)
C.free(rawptr_t(c_str))
}
// Load the TLS certificate from a file. The file should be an unencrypted
// (X509) PEM file. Use TLSCert() instead for more complex usage.
func (self MsgNetworkConfig) TLSCertFile(fname string) {
c_str := C.CString(fname)
C.msgnetwork_config_tls_cert_file(self.inner, c_str)
C.free(rawptr_t(c_str))
}
// Use the given TLS key. This overrides TLSKeyFile(). pkey will be moved and
// kept by the library. Thus, no methods of msg involving the payload should be
// called afterwards.
func (self MsgNetworkConfig) TLSKeyByMove(pkey PKey) {
C.msgnetwork_config_tls_key_by_move(self.inner, pkey.inner)
}
//// Load the TLS certificate from a file. The file should be an unencrypted
//// (X509) PEM file. Use TLSCert() instead for more complex usage.
//func (self MsgNetworkConfig) TLSCert(fname string) {
// c_str := C.CString(fname)
// C.msgnetwork_config_tls_cert(self.inner, c_str)
// C.free(rawptr_t(c_str))
//}
// Create a message network handle which is attached to given event loop.
func NewMsgNetwork(ec EventContext, config MsgNetworkConfig, err *Error) MsgNetwork {
res := MsgNetworkFromC(C.msgnetwork_new(ec.inner, config.inner, err))
if res != nil {
ec.attach(rawptr_t(res.inner), res)
runtime.SetFinalizer(res, func(self MsgNetwork) { self.free() })
}
return res
}
func (self MsgNetwork) free() { C.msgnetwork_free(self.inner) }
// Start the message network (by spawning worker threads). This should be
// called before using any other methods.
func (self MsgNetwork) Start() { C.msgnetwork_start(self.inner) }
// Listen to the specified network address.
func (self MsgNetwork) Listen(addr NetAddr, err *Error) { C.msgnetwork_listen(self.inner, addr.inner, err) }
// Stop the message network. No other methods should be called after this.
func (self MsgNetwork) Stop() { C.msgnetwork_stop(self.inner) }
// Send a message through the given connection.
func (self MsgNetwork) SendMsg(msg Msg, conn MsgNetworkConn) bool {
return bool(C.msgnetwork_send_msg(self.inner, msg.inner, conn.inner))
}
// Send a message through the given connection, using a worker thread to
// seralize and put data to the send buffer. The payload contained in the given
// msg will be moved and sent. Thus, no methods of msg involving the payload
// should be called afterwards.
func (self MsgNetwork) SendMsgDeferredByMove(msg Msg, conn MsgNetworkConn) int32 {
return int32(C.msgnetwork_send_msg_deferred_by_move(self.inner, msg.inner, conn.inner))
}
// Try to connect to a remote address. The connection handle is returned. The
// returned connection handle could be kept in your program.
func (self MsgNetwork) ConnectSync(addr NetAddr, autoFree bool, err *Error) MsgNetworkConn {
res := MsgNetworkConnFromC(C.msgnetwork_connect_sync(self.inner, addr.inner, err))
msgNetworkConnSetFinalizer(res, autoFree)
return res
}
// Try to connect to a remote address (async). It returns an id which could be
// used to identify the corresponding error in the error callback.
func (self MsgNetwork) Connect(addr NetAddr) int32 {
return int32(C.msgnetwork_connect(self.inner, addr.inner))
}
// Terminate the given connection.
func (self MsgNetwork) Terminate(conn MsgNetworkConn) { C.msgnetwork_terminate(self.inner, conn.inner) }
// The C function pointer type which takes msg_t*, msgnetwork_conn_t* and void*
// (passing in the custom user data allocated by C.malloc) as parameters.
type MsgNetworkMsgCallback = C.msgnetwork_msg_callback_t
// The C function pointer type which takes msgnetwork_conn_t*, bool (true for
// the connection is established, false for the connection is terminated) and
// void* as parameters.
type MsgNetworkConnCallback = C.msgnetwork_conn_callback_t
// The C function Pointer type which takes SalticidaeCError* and void* as parameters.
type MsgNetworkErrorCallback = C.msgnetwork_error_callback_t
// Register a message handler for the type of message identified by opcode. The
// callback function will be invoked upon the delivery of each message with the
// given opcode, by the thread of the event loop the MsgNetwork is attached to.
func (self MsgNetwork) RegHandler(opcode Opcode, callback MsgNetworkMsgCallback, userdata rawptr_t) {
C.msgnetwork_reg_handler(self.inner, C._opcode_t(opcode), callback, userdata)
}
// Register a connection handler invoked when the connection state is changed.
func (self MsgNetwork) RegConnHandler(callback MsgNetworkConnCallback, userdata rawptr_t) {
C.msgnetwork_reg_conn_handler(self.inner, callback, userdata)
}
// Register an error handler invoked when there is recoverable errors during any
// asynchronous call/execution inside the MsgNetwork.
func (self MsgNetwork) RegErrorHandler(callback MsgNetworkErrorCallback, userdata rawptr_t) {
C.msgnetwork_reg_error_handler(self.inner, callback, userdata)
}
// The C pointer type for a PeerNetwork handle.
type CPeerNetwork = *C.peernetwork_t
type peerNetwork struct { inner CPeerNetwork }
// The handle for a peer-to-peer network.
type PeerNetwork = *peerNetwork
func PeerNetworkFromC(ptr CPeerNetwork) PeerNetwork {
return &peerNetwork{ inner: ptr }
}
// The C pointer type for a PeerNetworkConn handle.
type CPeerNetworkConn = *C.peernetwork_conn_t
type peerNetworkConn struct {
inner CPeerNetworkConn
autoFree bool
}
// The handle for a PeerNetwork connection.
type PeerNetworkConn = *peerNetworkConn
func PeerNetworkConnFromC(ptr CPeerNetworkConn) PeerNetworkConn {
return &peerNetworkConn{ inner: ptr }
}
func peerNetworkConnSetFinalizer(res PeerNetworkConn, autoFree bool) {
res.autoFree = autoFree
if res != nil && autoFree {
runtime.SetFinalizer(res, func(self PeerNetworkConn) { self.Free() })
}
}
var (
ADDR_BASED = PeerNetworkIdMode(C.ID_MODE_ADDR_BASED)
CERT_BASED = PeerNetworkIdMode(C.ID_MODE_CERT_BASED)
)
// The identity mode. ID_MODE_IP_BASED: a remote peer is identified by the IP
// only. ID_MODE_IP_PORT_BASED: a remote peer is identified by IP + port
// number.
type PeerNetworkIdMode = C.peernetwork_id_mode_t
// The C pointer type for a PeerNetworkConfig handle.
type CPeerNetworkConfig = *C.peernetwork_config_t
type peerNetworkConfig struct { inner CPeerNetworkConfig }
// Configuration for PeerNetwork.
type PeerNetworkConfig = *peerNetworkConfig
func PeerNetworkConfigFromC(ptr CPeerNetworkConfig) PeerNetworkConfig {
return &peerNetworkConfig{ inner: ptr }
}
// Create the configuration object with default settings.
func NewPeerNetworkConfig() PeerNetworkConfig {
res := PeerNetworkConfigFromC(C.peernetwork_config_new())
runtime.SetFinalizer(res, func(self PeerNetworkConfig) { self.free() })
return res
}
func (self PeerNetworkConfig) free() { C.peernetwork_config_free(self.inner) }
// Set the connection retry delay (in seconds).
func (self PeerNetworkConfig) RetryConnDelay(t_sec float64) {
C.peernetwork_config_retry_conn_delay(self.inner, C.double(t_sec))
}
// Set the period for sending ping messsages (in seconds).
func (self PeerNetworkConfig) PingPeriod(t_sec float64) {
C.peernetwork_config_ping_period(self.inner, C.double(t_sec))
}
// Set the time it takes after sending a ping message before a connection is
// considered as broken.
func (self PeerNetworkConfig) ConnTimeout(t_sec float64) {
C.peernetwork_config_conn_timeout(self.inner, C.double(t_sec))
}
// Set the identity mode.
func (self PeerNetworkConfig) IdMode(mode PeerNetworkIdMode) {
C.peernetwork_config_id_mode(self.inner, mode)
}
// Use the PeerNetworkConfig object as a MsgNetworkConfig object (to invoke the
// methods inherited from MsgNetworkConfig, such as NWorker).
func (self PeerNetworkConfig) AsMsgNetworkConfig() MsgNetworkConfig {
return MsgNetworkConfigFromC(C.peernetwork_config_as_msgnetwork_config(self.inner))
}
// Create a peer-to-peer message network handle.
func NewPeerNetwork(ec EventContext, config PeerNetworkConfig, err *Error) PeerNetwork {
res := PeerNetworkFromC(C.peernetwork_new(ec.inner, config.inner, err))
if res != nil {
ec.attach(rawptr_t(res.inner), res)
runtime.SetFinalizer(res, func(self PeerNetwork) { self.free() })
}
return res
}
func (self PeerNetwork) free() { C.peernetwork_free(self.inner) }
// Add a peer to the list of known peers. The P2P network will try to keep
// bi-direction connections to all known peers in the list (through
// reconnection and connection deduplication).
func (self PeerNetwork) AddPeer(addr NetAddr) { C.peernetwork_add_peer(self.inner, addr.inner) }
// Remove a peer from the list of known peers. The P2P network will teardown
// the existing bi-direction connection and the PeerHandler callback will not be called.
func (self PeerNetwork) DelPeer(addr NetAddr) { C.peernetwork_del_peer(self.inner, addr.inner) }
// Test whether a peer is already in the list.
func (self PeerNetwork) HasPeer(addr NetAddr) bool { return bool(C.peernetwork_has_peer(self.inner, addr.inner)) }
// Get the connection of the known peer. The connection handle is returned. The
// returned connection handle could be kept in your program.
func (self PeerNetwork) GetPeerConn(addr NetAddr, autoFree bool, err *Error) PeerNetworkConn {
res := PeerNetworkConnFromC(C.peernetwork_get_peer_conn(self.inner, addr.inner, err))
peerNetworkConnSetFinalizer(res, autoFree)
return res
}
// Use the PeerNetwork handle as a MsgNetwork handle (to invoke the methods
// inherited from MsgNetwork, such as RegHandler).
func (self PeerNetwork) AsMsgNetwork() MsgNetwork {
return MsgNetworkFromC(C.peernetwork_as_msgnetwork(self.inner))
}
// Use the MsgNetwork handle as a PeerNetwork handle (forcing the conversion).
func (self MsgNetwork) AsPeerNetworkUnsafe() PeerNetwork {
return PeerNetworkFromC(C.msgnetwork_as_peernetwork_unsafe(self.inner))
}
// Create a MsgNetworkConn handle from a PeerNetworkConn (representing the same
// connection).
func NewMsgNetworkConnFromPeerNetworkConn(conn PeerNetworkConn, autoFree bool) MsgNetworkConn {
res := MsgNetworkConnFromC(C.msgnetwork_conn_new_from_peernetwork_conn(conn.inner))
msgNetworkConnSetFinalizer(res, autoFree)
return res
}
// Create a PeerNetworkConn handle from a MsgNetworkConn (representing the same
// connection and forcing the conversion).
func NewPeerNetworkConnFromMsgNetworkConnUnsafe(conn MsgNetworkConn, autoFree bool) PeerNetworkConn {
res := PeerNetworkConnFromC(C.peernetwork_conn_new_from_msgnetwork_conn_unsafe(conn.inner))
peerNetworkConnSetFinalizer(res, autoFree)
return res
}
// Make a copy of the connection handle.
func (self PeerNetworkConn) Copy(autoFree bool) PeerNetworkConn {
res := PeerNetworkConnFromC(C.peernetwork_conn_copy(self.inner))
peerNetworkConnSetFinalizer(res, autoFree)
return res
}
// Get the listening address of the remote peer (no Copy() is needed).
func (self PeerNetworkConn) GetPeerAddr(autoFree bool) NetAddr {
res := NetAddrFromC(C.peernetwork_conn_get_peer_addr(self.inner))
netAddrSetFinalizer(res, autoFree)
return res
}
func (self PeerNetworkConn) Free() {
C.peernetwork_conn_free(self.inner)
if self.autoFree {
runtime.SetFinalizer(self, nil)
}
}
// Listen to the specified network address. Notice that this method overrides
// Listen() in MsgNetwork, so you should always call this one instead of
// AsMsgNetwork().Listen().
func (self PeerNetwork) Listen(listenAddr NetAddr, err *Error) {
C.peernetwork_listen(self.inner, listenAddr.inner, err)
}
// Send a message to the given peer.
func (self PeerNetwork) SendMsg(msg Msg, addr NetAddr) bool {
return bool(C.peernetwork_send_msg(self.inner, msg.inner, addr.inner))
}
// Send a message to the given peer, using a worker thread to seralize and put
// data to the send buffer. The payload contained in the given msg will be
// moved and sent. Thus, no methods of msg involving the payload should be
// called afterwards.
func (self PeerNetwork) SendMsgDeferredByMove(msg Msg, addr NetAddr) int32 {
return int32(C.peernetwork_send_msg_deferred_by_move(self.inner, msg.inner, addr.inner))
}
// Send a message to the given list of peers. The payload contained in the
// given msg will be moved and sent. Thus, no methods of msg involving the
// payload should be called afterwards.
func (self PeerNetwork) MulticastMsgByMove(msg Msg, addrs []NetAddr) (res int32) {
na := NewNetAddrArrayFromAddrs(addrs, false)
res = int32(C.peernetwork_multicast_msg_by_move(self.inner, msg.inner, na.inner))
na.Free()
return res
}
// The C function pointer type which takes peernetwork_conn_t*, bool and void*
// (passing in the custom user data allocated by C.malloc) as parameters.
type PeerNetworkPeerCallback = C.peernetwork_peer_callback_t
// Register a connection handler invoked when p2p connection is established/broken.
func (self PeerNetwork) RegPeerHandler(callback PeerNetworkPeerCallback, userdata rawptr_t) {
C.peernetwork_reg_peer_handler(self.inner, callback, userdata)
}
// The C function pointer type which takes netaddr_t*, x509_t* and void* (passing in the
// custom user data allocated by C.malloc) as parameters.
type PeerNetworkUnknownPeerCallback = C.peernetwork_unknown_peer_callback_t
// Register a connection handler invoked when a remote peer that is not in the
// list of known peers attempted to connect. By default configuration, the
// connection was rejected, and you can call AddPeer() to enroll this peer if
// you hope to establish the connection soon.
func (self PeerNetwork) RegUnknownPeerHandler(callback PeerNetworkUnknownPeerCallback, userdata rawptr_t) {
C.peernetwork_reg_unknown_peer_handler(self.inner, callback, userdata)
}
// The C pointer type for a ClientNetwork handle.
type CClientNetwork = *C.clientnetwork_t
type clientNetwork struct { inner CClientNetwork }
// The handle for a client-server network.
type ClientNetwork = *clientNetwork
func ClientNetworkFromC(ptr CClientNetwork) ClientNetwork {
return &clientNetwork{ inner: ptr }
}
// The C pointer type for a ClientNetworkConn handle.
type CClientNetworkConn = *C.clientnetwork_conn_t
type clientNetworkConn struct {
inner CClientNetworkConn
autoFree bool
}
// The handle for a ClientNetwork connection.
type ClientNetworkConn = *clientNetworkConn
func ClientNetworkConnFromC(ptr CClientNetworkConn) ClientNetworkConn {
return &clientNetworkConn{ inner: ptr }
}
func clientNetworkConnSetFinalizer(res ClientNetworkConn, autoFree bool) {
res.autoFree = autoFree
if res != nil && autoFree {
runtime.SetFinalizer(res, func(self ClientNetworkConn) { self.Free() })
}
}
// Create a client-server message network handle.
func NewClientNetwork(ec EventContext, config MsgNetworkConfig, err *Error) ClientNetwork {
res := ClientNetworkFromC(C.clientnetwork_new(ec.inner, config.inner, err))
if res != nil {
ec.attach(rawptr_t(res.inner), res)
runtime.SetFinalizer(res, func(self ClientNetwork) { self.free() })
}
return res
}
func (self ClientNetwork) free() { C.clientnetwork_free(self.inner) }
// Use the ClientNetwork handle as a MsgNetwork handle (to invoke the methods
// inherited from MsgNetwork, such as RegHandler).
func (self ClientNetwork) AsMsgNetwork() MsgNetwork {
return MsgNetworkFromC(C.clientnetwork_as_msgnetwork(self.inner))
}
// Use the MsgNetwork handle as a ClientNetwork handle (forcing the conversion).
func (self MsgNetwork) AsClientNetworkUnsafe() ClientNetwork {
return ClientNetworkFromC(C.msgnetwork_as_clientnetwork_unsafe(self.inner))
}
// Create a MsgNetworkConn handle from a ClientNetworkConn (representing the same
// connection).
func NewMsgNetworkConnFromClientNetworkConn(conn ClientNetworkConn, autoFree bool) MsgNetworkConn {
res := MsgNetworkConnFromC(C.msgnetwork_conn_new_from_clientnetwork_conn(conn.inner))
msgNetworkConnSetFinalizer(res, autoFree)
return res
}
// Create a ClientNetworkConn handle from a MsgNetworkConn (representing the same
// connection and forcing the conversion).
func NewClientNetworkConnFromMsgNetworkConnUnsafe(conn MsgNetworkConn, autoFree bool) ClientNetworkConn {
res := ClientNetworkConnFromC(C.clientnetwork_conn_new_from_msgnetwork_conn_unsafe(conn.inner))
clientNetworkConnSetFinalizer(res, autoFree)
return res
}
// Make a copy of the connection handle.
func (self ClientNetworkConn) Copy(autoFree bool) ClientNetworkConn {
res := ClientNetworkConnFromC(C.clientnetwork_conn_copy(self.inner))
clientNetworkConnSetFinalizer(res, autoFree)
return res
}
func (self ClientNetworkConn) Free() {
C.clientnetwork_conn_free(self.inner)
if self.autoFree {
runtime.SetFinalizer(self, nil)
}
}
// Send a message to the given client.
func (self ClientNetwork) SendMsg(msg Msg, addr NetAddr) bool {
return bool(C.clientnetwork_send_msg(self.inner, msg.inner, addr.inner))
}
// Send a message to the given client, using a worker thread to seralize and put
// data to the send buffer. The payload contained in the given msg will be
// moved and sent. Thus, no methods of msg involving the payload should be
// called afterwards.
func (self ClientNetwork) SendMsgDeferredByMove(msg Msg, addr NetAddr) int32 {
return int32(C.clientnetwork_send_msg_deferred_by_move(self.inner, msg.inner, addr.inner))
}