-
Notifications
You must be signed in to change notification settings - Fork 3
/
iemnet.h
357 lines (310 loc) · 11.9 KB
/
iemnet.h
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
/* *********************************************+
* iemnet
* networking for Pd
*
* (c) 2010 IOhannes m zmölnig
* Institute of Electronic Music and Acoustics (IEM)
* University of Music and Dramatic Arts (KUG), Graz, Austria
*
* based on net/ library by Martin Peach
* based on maxlib by Olaf Matthes
*/
/* ---------------------------------------------------------------------------- */
/* This program is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU General Public License */
/* as published by the Free Software Foundation; either version 2 */
/* of the License, or (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, see */
/* http://www.gnu.org/licenses/ */
/* */
/* ---------------------------------------------------------------------------- */
#ifndef INCLUDE_IEMNET_H_
#define INCLUDE_IEMNET_H_
#ifdef __GNUC__
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
# define MAYBE_UNUSED(x) x __attribute__((__unused__))
#else
# define UNUSED(x) UNUSED_ ## x
# define MAYBE_UNUSED(x) x
#endif
#ifdef __GNUC__
# define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x
# define MAYBE_UNUSED_FUNCTION(x) __attribute__((__unused__)) x
#else
# define UNUSED_FUNCTION(x) UNUSED_ ## x
# define MAYBE_UNUSED_FUNCTION(x) x
#endif
#include "m_pd.h"
/* from s_stuff.h */
typedef void (*t_fdpollfn)(void *ptr, int fd);
EXTERN void sys_closesocket(int fd);
EXTERN void sys_sockerror(char *s);
EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
EXTERN void sys_rmpollfn(int fd);
#ifdef _WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
#else
# include <netdb.h>
# include <arpa/inet.h>
# include <sys/socket.h>
#endif
#include <sys/types.h>
/* iemnet_data.c */
#include "iemnet_data.h"
/* iemnet_sender.c */
/**
* opaque data type used for sending data over a socket
*/
typedef struct _iemnet_sender t_iemnet_sender;
EXTERN_STRUCT _iemnet_sender;
/**
* user provided send function
* (defaults to just using send)
* this function is guaranteed to be called with a valid 'chunk',
* and the 'userdata' and 'sockfd' provided at sender-creation
*/
typedef int (*t_iemnet_sendfunction)(const void*userdata, int sockfd,
t_iemnet_chunk*chunk);
/**
* create a sender to a given socket
*
* \param sock a previously opened socket
* \param sendfun a send()-implementation (or NULL, to use the default send/sendto based implementation)
* \param userdata pointer to optional userdata to be passsed to `sendfun`
* \param bool indicating whether this function is called from a subthread (1) or the mainthread (0)
* \return pointer to a sender object
* \note the socket must be writeable
*/
t_iemnet_sender*iemnet__sender_create(int sock,
t_iemnet_sendfunction sendfun, const void*userdata,
int);
/**
* destroy a sender to a given socket
* destroying a sender will free all resources of the sender
*
* \param pointer to a sender object to be destroyed
* \param bool indicating whether this function is called from a subthread (1) or the mainthread (0)
*
* \note it will also close() the socket
*/
void iemnet__sender_destroy(t_iemnet_sender*, int);
/**
* send data over a socket
*
* \param pointer to a sender object
* \param pointer to a chunk of data to be sent
* \return the current fill state of the send buffer
*
* \note the sender creates a local copy of chunk; the caller has to delete their own copy
*/
int iemnet__sender_send(t_iemnet_sender*, t_iemnet_chunk*);
/**
* query the fill state of the send buffer
*
* \param pointer to a sender object
* \return the current fill state of the send buffer
*/
int iemnet__sender_getsize(t_iemnet_sender*);
/**
* calls connect(2) with a timeout.
* if "timeout" is <0, then the original blocking behaviour is preserved.
*
* \param timeout timeout in ms
* \return success
*/
int iemnet__connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, float timeout);
/* iemnet_receiver.c */
/**
* opaque data type used for receiving data from a socket
*/
typedef struct _iemnet_receiver t_iemnet_receiver;
EXTERN_STRUCT _iemnet_receiver;
/**
* callback function for receiving
* whenever data arrives at the socket, a callback will be called synchronously
* if rawdata is NULL, this signifies that the socket has been closed
*/
typedef void (*t_iemnet_receivecallback)(void*userdata
, t_iemnet_chunk*rawdata
);
/**
* create a receiver object
*
* whenever something is received on the socket, the callback is called with the payload in the main thread of the caller
*
* \param sock the (readable) socket to receive from
* \param data user data to be passed to callback
* \param callback a callback function that is called on the caller's side
* \param subthread bool indicating whether this function is called from a subthread (1) or the mainthread (0)
*
* \note the callback will be scheduled in the caller's thread with clock_delay()
*/
t_iemnet_receiver*iemnet__receiver_create(int sock, void*data,
t_iemnet_receivecallback callback, int subthread);
/**
* destroy a receiver at a given socket
* destroying a receiver will free all resources of the receiver
*
* \param pointer to a receiver object to be destroyed
* \param bool indicating whether this function is called from a subthread (1) or the mainthread (0)
*
* \note it will also close() the socket
*/
void iemnet__receiver_destroy(t_iemnet_receiver*, int subthread);
/**
* query the fill state of the receive buffer
*
* \param pointer to a receiver object
* \return the current fill state of the receive buffer
*/
int iemnet__receiver_getsize(t_iemnet_receiver*);
/* convenience functions */
/**
* properly close a socket fd
*
* \param sock socket to close
*/
void iemnet__closesocket(int fd, int verbose);
/**
* convert a sockaddr to an atom-list, that can be output
*
* \param address a pointer to sockaddr_in/sockaddr_in6/... that holds the address
* \param alist an array of at least 18 t_atoms to write the address to in the form:
* <s:family> {<f:IPitem>} {f:port}
*
* \return the number of atoms consumed
*/
int iemnet__sockaddr2list(const struct sockaddr_storage*address, t_atom alist[18]);
/**
* output the address (IP, port)
* the address is obtained from the sockfd via getsockname().
* the given address is output through the status_outlet using the
* provided selector, using the form:
* '<selector> <family> [<address-component>] <port>'
* e.g. 'local_address IPv4 127 0 0 1 65432'
* resp. 'local_address IPv6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 55555'
*
* \param sockfd the socket to read the address from
* \param status_outlet outlet for general status messages
* \param selector the selector to use when sending the status-message
*
* \note depending on the address-family the output can have different length.
* e.g. with IPv4 the address will be output as a 6 element list, with
* the 1st 4 elements denoting the quads of the IPv4 address (as
* bytes) and the last element the port.
*/
void iemnet__socket2addressout(int sockfd,
t_outlet*status_outlet, t_symbol*selector);
/**
* output the address (IP, port)
* the given address is first output through the status_outlet as a "host" message
* and then as a list through the address_outlet
*
* \param status_outlet outlet for general status messages
* \param address_outlet outlet for addresses only
* \param address the host ip
* \param port the host port
*
* \note the address will be output as a 5 element list, with the 1st 4 elements denoting the quads of the IP address (as bytes) and the last element the port
*/
void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet,
uint32_t address, uint16_t port);
/**
* output the socket we received data from
* the given socket is first output through the status_outlet as a "socket" message
* and then as a single number through the socket_outlet
*
* \param status_outlet outlet for general status messages
* \param socket_outlet outlet for sockets only
* \param sockfd the socket
*/
void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet,
int sockfd);
/**
* output the number of connections
* the given number of connections is first output through the status_outlet as a "connections" message
* and then as a single number through the numconn_outlet
*
* \param status_outlet outlet for general status messages
* \param address_outlet outlet for numconnections only
* \param numconnections the number of connections
*/
void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numconn_outlet,
int numconnections);
/**
* output a list as a stream (serialize)
*
* the given list of atoms will be sent to the output one-by-one
*
* \param outlet outlet to sent the data to
* \param argc size of the list
* \param argv data
* \param stream if true, serialize the data; if false output as "packets"
*
* \note with stream based protocols (TCP/IP) the length of the received lists has no meaning, so the data has to be serialized anyhow; however when creating proxies, sending serialized data is often slow, so there is an option to disable serialization
*/
void iemnet__streamout(t_outlet*outlet, int argc, t_atom*argv, int stream);
/**
* register an objectname and printout a banner
*
* this will printout a copyright notice
* additionally, it will return whether it has already been called for the given name
*
* \param name an objectname to "register"
* \return 1 if this function has been called the first time with the given name, 0 otherwise
*
*/
int iemnet__register(const char*name);
#if defined(_MSC_VER)
# define snprintf _snprintf
# define IEMNET_EXTERN __declspec(dllexport) extern
# define IEMNET_INITIALIZER(f)
#elif defined(__GNUC__)
# define IEMNET_EXTERN extern
# define IEMNET_INITIALIZER(f)
#endif
typedef enum {
IEMNET_FATAL = 0,
IEMNET_ERROR = 1,
IEMNET_NORMAL = 2,
IEMNET_VERBOSE = 3,
IEMNET_DEBUG = 4
} t_iemnet_loglevel;
void iemnet_log(const void *object, const t_iemnet_loglevel level, const char *fmt, ...);
/**
* \fn void DEBUG(const char* format,...);
*
* \brief debug output
* \note this will only take effect if DEBUG is not undefined
*/
#ifdef IEMNET_HAVE_DEBUG
# undef IEMNET_HAVE_DEBUG
#endif
#ifdef DEBUG
# define IEMNET_HAVE_DEBUG 1
#endif
#define IEMNET_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
void iemnet_debuglevel(void*,t_float);
int iemnet_debug(int debuglevel, const char*file, unsigned int line,
const char*function);
#define DEBUGMETHOD(c) class_addmethod(c, (t_method)iemnet_debuglevel, gensym("debug"), A_FLOAT, 0)
#ifdef DEBUG
# undef DEBUG
# define DEBUG if(iemnet_debug(DEBUGLEVEL, __FILE__, __LINE__, __FUNCTION__))post
#else
static void MAYBE_UNUSED_FUNCTION(debug_dummy)(const char *format, ...)
{
(void)format; /* ignore unused variable */
}
# define DEBUG if(0)debug_dummy
#endif
#define MARK() post("%s:%d [%s]", __FILE__, __LINE__, __FUNCTION__)
#endif /* INCLUDE_IEMNET_H_ */