zhangmeng
2024-04-22 16935f4aebffdd1b6580b844391a0aa0f4f3012b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//
// Copyright 2021 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt).  A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
 
#ifndef CORE_PROTOCOL_H
#define CORE_PROTOCOL_H
 
#include "core/options.h"
 
// Protocol implementation details.  Protocols must implement the
// interfaces in this file.  Note that implementing new protocols is
// not necessarily intended to be a trivial task.  The protocol developer
// must understand the nature of nng, as they are responsible for handling
// most of the logic.  The protocol generally does most of the work for
// locking, and calls into the transport's pipe functions to do actual
// work, and the pipe functions generally assume no locking is needed.
// As a consequence, most of the concurrency in nng exists in the protocol
// implementations.
 
// nni_proto_pipe contains protocol-specific per-pipe operations.
struct nni_proto_pipe_ops {
    // pipe_size is the size of a protocol pipe object.  The common
    // code allocates this memory for the protocol private state.
    size_t pipe_size;
 
    // pipe_init initializes the protocol-specific pipe data structure.
    // The last argument is the per-socket protocol private data.
    int (*pipe_init)(void *, nni_pipe *, void *);
 
    // pipe_fini releases any pipe data structures.  This is called after
    // the pipe has been removed from the protocol, and the generic
    // pipe threads have been stopped.
    void (*pipe_fini)(void *);
 
    // pipe_start is called to register a pipe with the protocol.  The
    // protocol can reject this, for example if another pipe is already
    // active on a 1:1 protocol.  The protocol may not block during this.
    int (*pipe_start)(void *);
 
    // pipe_close is an idempotent, non-blocking, operation, called
    // when the pipe is being closed.  Any operations pending on the
    // pipe should be canceled with NNG_ECLOSED.  (Best option is to
    // use nng_aio_close() on them)
    void (*pipe_close)(void *);
 
    // pipe_stop is called during finalization, to ensure that
    // the protocol is absolutely finished with the pipe.  It should
    // wait if necessary to ensure that the pipe is not referenced
    // any more by the protocol.  It should not destroy resources.
    void (*pipe_stop)(void *);
};
 
struct nni_proto_ctx_ops {
    // ctx_size is the size of a protocol context object.  The common
    // code allocates this memory for the protocol private state.
    size_t ctx_size;
 
    // ctx_init initializes a new context. The second argument is the
    // protocol specific socket structure.
    int (*ctx_init)(void *, void *);
 
    // ctx_fini destroys a context.
    void (*ctx_fini)(void *);
 
    // ctx_recv is an asynchronous recv.
    void (*ctx_recv)(void *, nni_aio *);
 
    // ctx_send is an asynchronous send.
    void (*ctx_send)(void *, nni_aio *);
 
    // ctx_options array.
    nni_option *ctx_options;
};
 
struct nni_proto_sock_ops {
    // ctx_size is the size of a protocol socket object.  The common
    // code allocates this memory for the protocol private state.
    size_t sock_size;
 
    // sock_init initializes the protocol instance, which will be stored
    // on the socket. This is run without the sock lock held.
    int (*sock_init)(void *, nni_sock *);
 
    // sock_fini destroys the protocol instance.  This is run without the
    // socket lock held, and is intended to release resources.  It may
    // block as needed.
    void (*sock_fini)(void *);
 
    // Open the protocol instance.  This is run with the lock held,
    // and intended to allow the protocol to start any asynchronous
    // processing.
    void (*sock_open)(void *);
 
    // Close the protocol instance.  This is run with the lock held,
    // and intended to initiate closure of the socket.  For example,
    // it can signal the socket worker threads to exit.
    void (*sock_close)(void *);
 
    // Send a message.
    void (*sock_send)(void *, nni_aio *);
 
    // Receive a message.
    void (*sock_recv)(void *, nni_aio *);
 
    // Options. Must not be NULL. Final entry should have NULL name.
    nni_option *sock_options;
};
 
typedef struct nni_proto_id {
    uint16_t    p_id;
    const char *p_name;
} nni_proto_id;
 
struct nni_proto {
    uint32_t                  proto_version;  // Ops vector version
    nni_proto_id              proto_self;     // Our identity
    nni_proto_id              proto_peer;     // Peer identity
    uint32_t                  proto_flags;    // Protocol flags
    const nni_proto_sock_ops *proto_sock_ops; // Per-socket operations
    const nni_proto_pipe_ops *proto_pipe_ops; // Per-pipe operations
    const nni_proto_ctx_ops * proto_ctx_ops;  // Context operations
};
 
// We quite intentionally use a signature where the upper word is nonzero,
// which ensures that if we get garbage we will reject it.  This is more
// likely to mismatch than all zero bytes would.  The actual version is
// stored in the lower word; this is not semver -- the numbers are just
// increasing - we doubt it will increase more than a handful of times
// during the life of the project.  If we add a new version, please keep
// the old version around -- it may be possible to automatically convert
// older versions in the future.
#define NNI_PROTOCOL_V3 0x50520003u // "pr\0\3"
#define NNI_PROTOCOL_VERSION NNI_PROTOCOL_V3
 
// These flags determine which operations make sense.  We use them so that
// we can reject attempts to create notification fds for operations that make
// no sense.  Also, we can detect raw mode, thereby providing handling for
// that at the socket layer (NNG_PROTO_FLAG_RAW).
#define NNI_PROTO_FLAG_RCV 1u    // Protocol can receive
#define NNI_PROTO_FLAG_SND 2u    // Protocol can send
#define NNI_PROTO_FLAG_SNDRCV 3u // Protocol can both send & recv
#define NNI_PROTO_FLAG_RAW 4u    // Protocol is raw
 
// nni_proto_open is called by the protocol to create a socket instance
// with its ops vector.  The intent is that applications will only see
// the single protocol-specific constructor, like nng_pair_v0_open(),
// which should just be a thin wrapper around this.  If the protocol has
// not been initialized yet, this routine will do so.
extern int nni_proto_open(nng_socket *, const nni_proto *);
 
// Protocol numbers.
// These values are used on the wire, so must not be changed.  The major
// number of the protocol is shifted left by 4 bits, and a sub-protocol is
// assigned in the lower 4 bits.
//
// There are gaps in the list, which are obsolete or unsupported protocols.
// Protocol numbers are never more than 16 bits.  Also, there will never be
// a valid protocol numbered 0 (NNG_PROTO_NONE).
#define NNI_PROTO(major, minor) (((major) *16) + (minor))
 
// Protocol major numbers.  This is here for documentation only, and
// to serve as a "registry" for managing new protocol numbers.  Consider
// updating this table when adding new protocols.
//
// Protocol     Maj Min Name       Notes
// -------------------------------------------
// NONE          0   0             reserved
// PAIRv0        1   0  pair
// PAIRv1        1   1  pair1      nng only, experimental
// PUBv0         2   0  pub
// SUBv0         2   1  sub
// REQv0         3   0  req
// REPv0         3   1  rep
// PUSHv0        5   0  push
// PULLv0        5   1  pull
// SURVEYORv0    6   2  surveyor   minors 0 & 1 retired
// RESPONDENTv0  6   3  respondent
// BUSv0         7   0  bus
// STARv0      100   0  star       mangos only, experimental
//
 
#endif // CORE_PROTOCOL_H