-
Notifications
You must be signed in to change notification settings - Fork 28
/
io.h
342 lines (293 loc) · 10.9 KB
/
io.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
/* libnih
*
* Copyright © 2009 Scott James Remnant <[email protected]>.
* Copyright © 2009 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef NIH_IO_H
#define NIH_IO_H
#include <sys/types.h>
#include <sys/socket.h>
#include <nih/macros.h>
#include <nih/list.h>
/**
* NihIoType:
*
* Whether an NihIo structure is used for a buffered stream of data, or
* a queue of discreet messages.
**/
typedef enum {
NIH_IO_STREAM,
NIH_IO_MESSAGE
} NihIoType;
/**
* NihIoEvents:
*
* Events that we can watch for, generally used as a bit mask of the events
* that have occurred.
**/
typedef enum {
NIH_IO_NONE = 00,
NIH_IO_READ = 01,
NIH_IO_WRITE = 02,
NIH_IO_EXCEPT = 04,
} NihIoEvents;
/* Predefine the typedefs as we use them in the callbacks */
typedef struct nih_io_watch NihIoWatch;
typedef struct nih_io NihIo;
/**
* NihIoWatcher:
* @data: data pointer given when registered,
* @watch: #NihIoWatch for which an event occurred,
* @events: events that occurred.
*
* An I/O watcher is a function that is called whenever an event occurs
* on a file descriptor or socket being watched. It is safe for the
* watcher to remove the watch during the call.
**/
typedef void (*NihIoWatcher) (void *data, NihIoWatch *watch,
NihIoEvents events);
/**
* NihIoReader:
* @data: data pointer given when registered,
* @io: NihIo with data to be read,
* @buf: buffer data is available in,
* @len: bytes in @buf.
*
* An I/O reader is a function that is called whenever new data or a new
* message has been received on a file descriptor or socket and placed
* into the receive buffer or queue.
*
* In stream mode, @buf and @len will point to the entire receive buffer
* and this function need not clear the buffer, it is entirely permitted
* for the data to be left there. When further data arrives, the buffer
* will be extended and the reader called again.
*
* In message mode, @buf and @len will point to the contents of the oldest
* message in the receive queue. You'll almost certainly want to remove
* this message from the queue, otherwise when a new message arrives, the
* function will still be called with the same oldest message.
*
* It is safe to call nih_io_close() from within the reader function, this
* results in the structure being flagged to be closed when the watcher
* that invokes it has finished. You must not nih_free() @io or cause it
* to be freed from within this function, except by nih_io_close().
**/
typedef void (*NihIoReader) (void *data, NihIo *io,
const char *buf, size_t len);
/**
* NihIoCloseHandler:
* @data: data pointer given when registered.
* @io: NihIo that closed.
*
* An I/O close handler is a function that is called when the remote end
* of a file descriptor or socket is closed and data can no longer be
* read from it.
*
* It should take appropriate action, which may include closing the
* file descriptor with nih_io_close(). You must not nih_free() @io or
* cause it to be freed from within this function, except by nih_io_close().
**/
typedef void (*NihIoCloseHandler) (void *data, NihIo *io);
/**
* NihIoErrorHandler:
* @data: data pointer given when registered,
* @io: NihIo that caused the error.
*
* An I/O error handler is a function that is called to handle an error
* raise while reading from the file descriptor or socket. The error
* itself can be obtained using nih_error_get().
*
* It should take appropriate action, which may include closing the
* file descriptor with nih_io_close(). You must not nih_free() @io or
* cause it to be freed from within this function, except by nih_io_close().
**/
typedef void (*NihIoErrorHandler) (void *data, NihIo *io);
/**
* NihIoWatch:
* @entry: list header,
* @fd: file descriptor,
* @events: events to watch for,
* @watcher: function called when @events occur on @fd,
* @data: pointer passed to @watcher.
*
* This structure represents the most basic kind of I/O handling, a watch
* on a file descriptor or socket that causes a function to be called
* when listed events occur.
*
* The watch can be cancelled by calling nih_list_remove() on the structure
* as they are held in a list internally.
**/
struct nih_io_watch {
NihList entry;
int fd;
NihIoEvents events;
NihIoWatcher watcher;
void *data;
};
/**
* NihIoBuffer:
* @buf: memory allocated for buffer,
* @size: allocated size of @buf,
* @len: number of bytes of @buf used.
*
* This structure is used to represent a buffer holding data that is
* waiting to be sent or processed.
**/
typedef struct nih_io_buffer {
char *buf;
size_t size;
size_t len;
} NihIoBuffer;
/**
* NihIoMessage:
* @entry: list header,
* @addr: address received from or to be sent to,
* @addrlen: length of @addr,
* @data: buffer for message data,
* @control: NULL-terminated array of control messages,
* @int_data: user-supplied integer data,
* @ptr_data: user-supplied pointer data.
*
* This structure is used to represent an individual message waiting in
* a queue to be sent or processed.
*
* When a message is in the queue, it is sometimes useful to be able to
* associate it with the source or destination of the message, for example
* when handling errors. You may use the @int_data or @ptr_member to store
* an integer or pointer value that is useful to you. These are not usually
* initialised.
**/
typedef struct nih_io_message {
NihList entry;
struct sockaddr *addr;
socklen_t addrlen;
NihIoBuffer *data;
struct cmsghdr **control;
union {
int int_data;
void *ptr_data;
};
} NihIoMessage;
/**
* NihIo:
* @type: type of structure,
* @watch: associated file descriptor watch,
* @send_buf: buffer that pools data to be sent (NIH_IO_STREAM),
* @send_q: queue of messages to be sent (NIH_IO_MESSAGE),
* @recv_buf: buffer that pools data received (NIH_IO_STREAM),
* @recv_q: queue of messages received (NIH_IO_MESSAGE),
* @reader: function called when new data in @recv_buf or @recv_q,
* @close_handler: function called when socket closes,
* @error_handler: function called when an error occurs,
* @data: pointer passed to functions,
* @shutdown: TRUE if the structure should be freed once the buffers are empty,
* @free: pointer to variable to set to TRUE if freed during the watcher.
*
* This structure implements more featureful I/O handling than provided by
* an NihIoWatch alone.
*
* When used in the stream mode (@type is NIH_IO_STREAM), it combines an
* NihIoWatch and two NihIoBuffer structures to implement a high-throughput
* alternative to the traditional stdio functions.
*
* Those functions are optimised to reduce the number of read() or write()
* calls made on a file descriptor, and cannot be used to pool large
* amounts of data for processing.
*
* The NihIo functions are instead optimised for being able to queue and
* receive much data as possible, and have the data sent in the background
* or processed at your leisure.
*
* When used in the message mode (@type is NIH_IO_MESSAGE), it combines the
* NihIoWatch with an NihList of NihIoMessage structures to implement
* asynchronous handling of datagram sockets.
**/
struct nih_io {
NihIoType type;
NihIoWatch *watch;
union {
NihIoBuffer *send_buf;
NihList *send_q;
};
union {
NihIoBuffer *recv_buf;
NihList *recv_q;
};
NihIoReader reader;
NihIoCloseHandler close_handler;
NihIoErrorHandler error_handler;
void *data;
int shutdown;
int *free;
};
NIH_BEGIN_EXTERN
extern NihList *nih_io_watches;
void nih_io_init (void);
NihIoWatch * nih_io_add_watch (const void *parent, int fd,
NihIoEvents events,
NihIoWatcher watcher, void *data)
__attribute__ ((warn_unused_result, malloc));
void nih_io_select_fds (int *nfds, fd_set *readfds,
fd_set *writefds, fd_set *exceptfds);
void nih_io_handle_fds (fd_set *readfds, fd_set *writewfds,
fd_set *exceptfds);
NihIoBuffer * nih_io_buffer_new (const void *parent)
__attribute__ ((warn_unused_result, malloc));
int nih_io_buffer_resize (NihIoBuffer *buffer, size_t grow);
char * nih_io_buffer_pop (const void *parent,
NihIoBuffer *buffer, size_t *len)
__attribute__ ((warn_unused_result, malloc));
void nih_io_buffer_shrink (NihIoBuffer *buffer, size_t len);
int nih_io_buffer_push (NihIoBuffer *buffer,
const char *str, size_t len)
__attribute__ ((warn_unused_result));
NihIoMessage *nih_io_message_new (const void *parent)
__attribute__ ((warn_unused_result, malloc));
int nih_io_message_add_control (NihIoMessage *message, int level,
int type, socklen_t len,
const void *data)
__attribute__ ((warn_unused_result));
NihIoMessage *nih_io_message_recv (const void *parent, int fd,
size_t *len)
__attribute__ ((warn_unused_result, malloc));
ssize_t nih_io_message_send (NihIoMessage *message, int fd)
__attribute__ ((warn_unused_result));
NihIo * nih_io_reopen (const void *parent, int fd,
NihIoType type, NihIoReader reader,
NihIoCloseHandler close_handler,
NihIoErrorHandler error_handler,
void *data)
__attribute__ ((warn_unused_result, malloc));
void nih_io_shutdown (NihIo *io);
int nih_io_destroy (NihIo *io);
NihIoMessage *nih_io_read_message (const void *parent, NihIo *io);
void nih_io_send_message (NihIo *io, NihIoMessage *message);
char * nih_io_read (const void *parent, NihIo *io,
size_t *len)
__attribute__ ((warn_unused_result, malloc));
int nih_io_write (NihIo *io, const char *str,
size_t len)
__attribute__ ((warn_unused_result));
char * nih_io_get (const void *parent, NihIo *io,
const char *delim)
__attribute__ ((warn_unused_result, malloc));
int nih_io_printf (NihIo *io, const char *format, ...)
__attribute__ ((warn_unused_result, format (printf, 2, 3)));
int nih_io_set_nonblock (int fd);
int nih_io_set_cloexec (int fd);
ssize_t nih_io_get_family (int fd);
NIH_END_EXTERN
#endif /* NIH_IO_H */