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
|
//
// Copyright 2017 Garrett D'Amore <garrett@damore.org>
//
// 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_SOCKET_H
#define CORE_SOCKET_H
// NB: This structure is supplied here for use by the CORE. Use of this library
// OUSIDE of the core is STRICTLY VERBOTEN. NO DIRECT ACCESS BY PROTOCOLS OR
// TRANSPORTS.
struct nni_socket {
nni_mtx s_mx;
nni_cv s_cv;
uint32_t s_id;
uint32_t s_refcnt;
nni_cv s_refcv;
nni_msgq * s_uwq; // Upper write queue
nni_msgq * s_urq; // Upper read queue
uint16_t s_protocol;
uint16_t s_peer;
uint32_t s_flags;
nni_proto_pipe_ops s_pipe_ops;
nni_proto_sock_ops s_sock_ops;
void * s_data; // Protocol private
// XXX: options
nni_duration s_linger; // linger time
nni_duration s_sndtimeo; // send timeout
nni_duration s_rcvtimeo; // receive timeout
nni_duration s_reconn; // reconnect time
nni_duration s_reconnmax; // max reconnect time
nni_list s_eps; // active endpoints
nni_list s_pipes; // ready pipes (started)
nni_list s_idles; // idle pipes (not ready)
size_t s_rcvmaxsz; // maximum receive size
int s_ep_pend; // EP dial/listen in progress
int s_closing; // Socket is closing
int s_closed; // Socket closed
int s_besteffort; // Best effort mode delivery
int s_senderr; // Protocol state machine use
int s_recverr; // Protocol state machine use
nni_event s_recv_ev; // Event for readability
nni_event s_send_ev; // Event for sendability
nni_notifyfd s_send_fd;
nni_notifyfd s_recv_fd;
uint32_t s_nextid; // Next Pipe ID.
};
extern int nni_sock_hold(nni_sock **, uint32_t);
extern int nni_sock_hold_close(nni_sock **, uint32_t);
extern void nni_sock_rele(nni_sock *);
extern int nni_sock_open(nni_sock **, uint16_t);
extern void nni_sock_close(nni_sock *);
extern int nni_sock_shutdown(nni_sock *);
extern uint16_t nni_sock_proto(nni_sock *);
extern uint16_t nni_sock_peer(nni_sock *);
extern int nni_sock_setopt(nni_sock *, int, const void *, size_t);
extern int nni_sock_getopt(nni_sock *, int, void *, size_t *);
extern int nni_sock_recvmsg(nni_sock *, nni_msg **, nni_time);
extern int nni_sock_sendmsg(nni_sock *, nni_msg *, nni_time);
extern int nni_sock_dial(nni_sock *, const char *, nni_ep **, int);
extern int nni_sock_listen(nni_sock *, const char *, nni_ep **, int);
extern uint32_t nni_sock_id(nni_sock *);
extern void nni_sock_lock(nni_sock *);
extern void nni_sock_unlock(nni_sock *);
extern nni_notify *nni_sock_notify(nni_sock *, int, nng_notify_func, void *);
extern void nni_sock_unnotify(nni_sock *, nni_notify *);
// nni_sock_pipe_add is called by the pipe to register the pipe with
// with the socket. The pipe is added to the idle list. The protocol
// private pipe data is initialized as well.
extern int nni_sock_pipe_add(nni_sock *, nni_pipe *);
// nni_sock_pipe_rem deregisters the pipe from the socket. The socket
// will block during close if there are registered pipes outstanding.
// This also frees any protocol private pipe data.
extern void nni_sock_pipe_rem(nni_sock *, nni_pipe *);
// nni_sock_pipe_ready lets the socket know the pipe is ready for
// business. This also calls the socket/protocol specific add function,
// and it may return an error. A reference count on the pipe is incremented
// on success. The reference count should be dropped by nni_sock_pipe_closed.
extern int nni_sock_pipe_ready(nni_sock *, nni_pipe *);
// nni_sock_pipe_closed lets the socket know that the pipe is closed.
// This keeps the socket from trying to schedule traffic to it. It
// also lets the endpoint know about it, to possibly restart a dial
// operation.
extern void nni_sock_pipe_closed(nni_sock *, nni_pipe *);
// Set error codes for applications. These are only ever
// called from the filter functions in protocols, and thus
// already have the socket lock held.
extern void nni_sock_recverr(nni_sock *, int);
extern void nni_sock_senderr(nni_sock *, int);
// These are socket methods that protocol operations can expect to call.
// Note that each of these should be called without any locks held, since
// the socket can reenter the protocol.
// nni_socket_sendq obtains the upper writeq. The protocol should
// recieve messages from this, and place them on the appropriate pipe.
extern nni_msgq *nni_sock_sendq(nni_sock *);
// nni_socket_recvq obtains the upper readq. The protocol should
// inject incoming messages from pipes to it.
extern nni_msgq *nni_sock_recvq(nni_sock *);
// nni_sock_mtx obtains the socket mutex. This is for protocols to use
// from separate threads; they must not hold the lock for extended periods.
// Additionally, this can only be acquired from separate threads. The
// synchronous entry points (excluding the send/recv thread workers) will
// be called with this lock already held. We expose the mutex directly
// here so that protocols can use it to initialize condvars.
extern nni_mtx *nni_sock_mtx(nni_sock *);
extern nni_duration nni_sock_linger(nni_sock *);
extern size_t nni_sock_rcvmaxsz(nni_sock *);
#endif // CORE_SOCKET_H
|