O2 2.0
A communication protocol for interactive music and media applications.
o2network.h
1//* network.h -- interface for network communication */
2//
3// Roger B. Dannenberg, 2019
4//
5// This module isolates low-level network communication from higher-level
6// O2 protocols. The main abstraction here is asynchronous message passing
7// over UDP and TCP. This abstraction layer handle asynchrony and
8// assembling messages.
9//
10// Uses o2n_ prefix to try to distinguish the "network" abstraction layer (o2n)
11// from the "O2" abstraction layer (o2).
12
13// The data structures are similar to the original O2 implementation:
14// 2 parallel arrays:
15// fds -- pollfd file descriptors
16// fds_info -- additional information/state
17// Each fds_info object has an index so that the corresponding fds can be
18// retrieved. When a socket is removed, the last element of each
19// array is copied to the position that just opened up, and the index
20// is updated to the new location.
21//
22// On initialization, there is:
23// - one TCP server socket to receive connections, asynchronous
24// - one pre-allocated UDP broadcast socket, sends are synchronous
25// - one pre-allocated UDP send socket, sends are synchronous
26
27#ifdef WIN32
28#include <winsock2.h> // define SOCKET, INVALID_SOCKET
29#include <WS2tcpip.h>
30#define inet_ntop InetNtop
31typedef SSIZE_T ssize_t;
32#else
33#include "arpa/inet.h" // Headers for all inet functions
34typedef int SOCKET; // In O2, we'll use SOCKET to denote the type of a socket
35#define INVALID_SOCKET -1
36#endif
48// messages are received in containers with a link so messages
49// may be queued in the application
50//
51// When sending a message, options are "raw": send only length bytes
52// starting at payload, or "default": send length + 4 bytes starting
53// at length, but convert length field to network byte order and then
54// restore the field. For UDP, the length is always assigned to the
55// packet length, so only length bytes of payload are in the packet.
56
57typedef struct O2netmsg {
58 union {
59 struct O2netmsg *next;
60 int64_t pad_if_needed;
61 };
62 int32_t length;
63 char payload[4];
65
66// macro to make a byte pointer
67#define PTR(addr) ((char *) (addr))
68
70#define O2N_MESSAGE_EXTRA (offsetof(O2netmsg, payload))
71
73#define O2N_MESSAGE_SIZE_FROM_DATA_SIZE(len) ((len) + O2N_MESSAGE_EXTRA)
74#define O2N_MESSAGE_ALLOC(len) \
75 ((O2netmsg_ptr) O2_MALLOC(O2N_MESSAGE_SIZE_FROM_DATA_SIZE(len)))
76
77// net_tag values
78// server socket to receive UDP messages: (0x200000)
79#define NET_UDP_SERVER (O2TAG_HIGH << 1)
80
81// server port for accepting TCP connections: (0x400000)
82#define NET_TCP_SERVER (O2TAG_HIGH << 2)
83
84// client side socket during async connection: (0x800000)
85#define NET_TCP_CONNECTING (O2TAG_HIGH << 3)
86
87// client side of a TCP connection: (0x1000000)
88#define NET_TCP_CLIENT (O2TAG_HIGH << 4)
89
90// server side accepted TCP connection: (0x2000000)
91#define NET_TCP_CONNECTION (O2TAG_HIGH << 5)
92
93// o2n_close_socket() has been called on this socket: (0x4000000)
94#define NET_INFO_CLOSED (O2TAG_HIGH << 6)
95
96// an input file for asynchronous reads -- treated as a socket (0x8000000)
97#define NET_INFILE (O2TAG_HIGH << 7)
98
99// Any open, sendable TCP socket (NET_TCP_SERVER is not actually sendable
100// as a socket, but if we get the Proc_info that owns this, it is the
101// local process, and we can always "send" to the local process because
102// we just find and invoke the local handler.
103#define NET_TCP_MASK (NET_TCP_SERVER | NET_TCP_CLIENT | NET_TCP_CONNECTION)
104
106public:
107 struct sockaddr_in sa; // address includes port number in network order
108
109 O2err init(const char *ip, int port_num, bool tcp_flag);
110 O2err init_hex(const char *ip, int port_num, bool tcp_flag);
111 int get_port() { return ntohs(sa.sin_port); }
112 void set_port(int port) { sa.sin_port = htons(port); }
113 struct sockaddr *get_sockaddr() { return (struct sockaddr *) &sa; }
114 struct in_addr *get_in_addr() { return &sa.sin_addr; }
115 const char *to_dot(char *ip) { // returns ip (or NULL on error)
116 return inet_ntop(AF_INET, get_in_addr(), ip, O2N_IP_LEN); }
117};
118
119class Fds_info; // forward declaration
120
122public:
123 Fds_info *fds_info;
124 virtual O2err accepted(Fds_info *conn) = 0;
125 virtual O2err connected() {
126 printf("ERROR: connected called by mistake\n"); return O2_FAIL; }
127 virtual O2err deliver(O2netmsg_ptr msg) = 0;
128
129 // override writeable iff WRITE_CUSTOM:
130 virtual O2err writeable() { return O2_SUCCESS; };
131
132 // since Net_interface is a just an interface (set of methods), it is
133 // always multiple-inherited along with some other class that you can
134 // actually delete. This remove method converts "this" to the proper
135 // class that provides the delete operator and invokes it. It would be
136 // nice if we could declare operator delete here and have it implemented
137 // by the other class, but I don't think C++ works that way.
138 virtual void remove() = 0;
139};
140
141typedef enum {READ_O2, READ_RAW, READ_CUSTOM} Read_type;
142typedef enum {WRITE_O2, WRITE_CUSTOM} Write_type;
143
144// an abstract class -- subclass with application-specific
145// message/event handlers
146//
147class Fds_info : public O2obj {
148 public:
149 int net_tag; // the type of socket: see list above
150 int fds_index; // the index of this object in the fds and fds_info arrays
151 int delete_me; // set to 1 to request the socket should be removed
152 // set to 2 when the socket is not blocked (is writable)
153 // (note that removing array elements while scanning for
154 // events would be very tricky, so we make a second
155 // cleanup pass).
156
157 Read_type read_type; // READ_RAW means message data is sent as is with
158 // no length count (unless it is in the message data).
159 // Incoming bytes are formed into O2netmsgs with length
160 // field and bytes, but there is no segmentation of the
161 // byte stream as a sequence of alternating length fields
162 // and message payloads. Only meaningful for TCP since UDP
163 // connections are inherently packetized.
164 // READ_CUSTOM means the Net_interface deliver method is
165 // responsible for reading from the socket.
166 // READ_O2 means o2network.h reads length counts, buffers
167 // incoming messages until complete, and then delivers the
168 // message by calling Net_interface deliver method.
169
170 Write_type write_type; // WRITE_O2 means o2network.h delivers messages
171 // with length counts. Messages can be pending without
172 // blocking and O2 provides a way to block to avoid
173 // accumulating a long queue of outgoing messages.
174 // WRITE_CUSTOM means the Net_interface writeable method
175 // is called when the socket is writeable, and the
176 // socket creator is responsible for setting events
177 // and writing to the socket. (Used for Avahi_info).
178
179 int32_t in_length; // incoming message length
180 O2netmsg_ptr in_message; // message data from TCP stream goes here
181 int in_length_got; // how many bytes of length have been read?
182 int in_msg_got; // how many bytes of message have been read?
183
184 O2netmsg_ptr out_message; // list of pending output messages with
185 // data in network byte order
186 int out_msg_sent; // how many bytes of message have been sent?
187 int port; // used to save port number if this is a UDP receive socket,
188 // or the server port if this is a process
189 Net_interface *owner;
190
191 Fds_info(SOCKET sock, int net_tag, int port, Net_interface *own);
192 ~Fds_info();
193
194 void set_events(short events);
195 short get_events();
196
197 static Fds_info *create_tcp_client(const char *ip, int port,
198 Net_interface *own);
199 static Fds_info *create_tcp_client(Net_address *remote_addr,
200 Net_interface *own);
201
202 // create a UDP server port. Set reuse to true unless this is a discovery
203 // port. We want discovery ports to be unique and not shared. Other
204 // ports might be stuck in TIME_WAIT state, and setting reuse = true
205 // might allow the process to reopen a recently used port.
206 static Fds_info *create_udp_server(int *port, bool reuse);
207
208 static Fds_info *create_tcp_server(int *port, Net_interface *own);
209 O2err connect(const char *ip, int tcp_port);
210 O2err can_send();
211 O2err send_tcp(bool block, O2netmsg_ptr msg);
212
213 // Send a message. Named "enqueue" to emphasize that this is asynchronous.
214 // Follow this call with o2n_send(info, true) to force a blocking
215 // (synchronous) send.
216 // msg must be in network byte order
217 void enqueue(O2netmsg_ptr msg);
218
219 // Take next step to send a message. If block is true, this call will
220 // block until all queued messages are sent or an error or closed
221 // socket breaks the connection. If block is false, sending is
222 // asynchronous and only one step is taken, e.g. sending the next
223 // message in the queue. This function is normally used internally
224 // without blocking. To avoid queuing up more than one, user-level
225 // message, the o2_send() function will call this *with* blocking
226 // when a message is already pending and o2_send is called again.
227 O2err send(bool block);
228
229 int read_event_handler();
230 O2err read_whole_message(SOCKET sock);
231 void message_cleanup();
232 Fds_info *cleanup(const char *error, SOCKET sock);
233 void reset();
234 void close_socket(bool now);
235
236#ifndef O2_NO_DEBUG
237 static const char *tag_to_string(int tag);
238#endif
239 SOCKET get_socket();
240};
241
242extern Vec<Fds_info *> o2n_fds_info;
243
244extern bool o2n_network_enabled; // network connections are permitted
245extern bool o2n_network_found; // local area network exists
246// if !o2n_network_found, o2n_internal_ip will be "7f000001" (localhost)
247extern char o2n_public_ip[O2N_IP_LEN]; // in 8 hex characters
248extern char o2n_internal_ip[O2N_IP_LEN]; // in 8 hex characters
249
250// initialize this module
251O2err o2n_initialize();
252
253O2netmsg_ptr O2netmsg_new(int size);
254
255// prepare to exit this module
256void o2n_finish(void);
257
258// free sockets that have been flagged as freed (sockets are normally not
259// freed immediately because doing so will cause other sockets to move
260// to a new position in fds and fds_info arrays, which is a problem if
261// you are iterating through the array)
262//
263// Since this is an O(N) search for deleted sockets, this function is only
264// called when o2n_socket_delete_flag is set, and it is only set when
265// a socket is marked for deletion.
266//
267void o2n_free_deleted_sockets(void);
268
269// poll for messages
270O2err o2n_recv(void);
271
272O2err o2n_send_udp(Net_address *ua, O2netmsg_ptr msg);
273
274O2err o2n_send_udp_via_socket(SOCKET socket, Net_address *ua,
275 O2netmsg_ptr msg);
276
277#define o2n_send_udp_via_info(info, ua, msg) \
278 o2n_send_udp_via_socket(info->get_socket(), ua, msg);
279
280// send a UDP message to localhost
281void o2n_send_udp_local(int port, O2netmsg_ptr msg);
282
283ssize_t o2n_send_broadcast(int port, O2netmsg_ptr msg);
284
285// create a socket for UDP broadcasting messages
286SOCKET o2n_broadcast_socket_new();
287
288// create a socket for sending UDP messages
289SOCKET o2n_udp_send_socket_new();
290
291SOCKET o2n_tcp_socket_new();
292
293void o2_disable_sigpipe(SOCKET sock);
Definition: o2network.h:147
Definition: o2network.h:105
Definition: o2network.h:121
Definition: o2obj.h:9
Definition: vec.h:6
O2err
return values used generally by O2 functions
Definition: o2.h:329
@ O2_SUCCESS
function was successful
Definition: o2.h:332
@ O2_FAIL
a non-specific error occurred.
Definition: o2.h:339
Definition: o2network.h:57
int64_t pad_if_needed
make sure allocated is 8-byte aligned
Definition: o2network.h:60
struct O2netmsg * next
link for application use
Definition: o2network.h:59
int32_t length
length of message in data part
Definition: o2network.h:62
char payload[4]
data
Definition: o2network.h:63