File: vanessa_socket_pipe.c

package info (click to toggle)
vanessa-socket 0.0.13-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,728 kB
  • sloc: sh: 11,325; ansic: 1,659; makefile: 69
file content (336 lines) | stat: -rw-r--r-- 10,900 bytes parent folder | download | duplicates (5)
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
/**********************************************************************
 * vanessa_socket_pipe.c                                  November 1999
 * Simon Horman                                      horms@verge.net.au
 *
 * Functions to pipe data between two open file descriptors (sockets)
 *
 * vanessa_socket
 * Library to simplify handling of TCP sockets
 * Copyright (C) 1999-2008  Simon Horman <horms@verge.net.au>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 *
 **********************************************************************/

#include "vanessa_socket.h"
#include "unused.h"

#include <errno.h>


/**********************************************************************
 * vanessa_socket_pipe_fd_read
 * Read bytes from fd
 * Intended to be passed to vanessa_socket_pipe_*func()
 * pre: fd: file descriptor to read bytes from
 *      buf: buffer to read bytes into
 *      count: maximum number of bytes to read
 *      data: not used
 * post: A maximum of count bytes are read into buf from fd using read(2)
 *       If an error occurs the errno is read and logged using the
 *       installed logger. See vanessa_logger_set().
 * return: Number of bytes read (may be zero)
 *         -1 on error
 **********************************************************************/

ssize_t vanessa_socket_pipe_fd_read(int fd, void *buf, size_t count,
				    void *UNUSED(data))
{
	ssize_t bytes;

	bytes = read(fd, buf, count);

	if (bytes < 0) {
		if (errno) {
			VANESSA_LOGGER_DEBUG_ERRNO("read");
		}
		return (-1);
	}

	return (bytes);
}


/**********************************************************************
 * vanessa_socket_pipe_fd_write
 * Write bytes to fd
 * Intended to be passed to vanessa_socket_pipe_*func()
 * pre: fd: file descriptor to write bytes to
 *      buf: buffer to write bytes from
 *      count: maximum number of bytes to write
 *      data: not used
 * post: A maximum of count bytes are written to fd from buf using write(2)
 *       If an error occurs the errno is read and logged using the
 *       installed logger. See vanessa_logger_set().
 * return: Number of bytes read (may be zero)
 *         -1 on error
 **********************************************************************/

ssize_t vanessa_socket_pipe_fd_write(int fd, const void *buf, size_t count,
				     void *UNUSED(data))
{
	size_t bytes;

	bytes = write(fd, buf, count);

	if (bytes <= 0) {
		if (errno) {
			VANESSA_LOGGER_DEBUG_ERRNO("write");
		}
		return (bytes == 0 ? 0 : -1);
	}

	return (bytes);
}


/**********************************************************************
 * vanessa_socket_pipe_func
 * pipe data between two pairs of file descriptors until there is an 
 * error, * timeout or one or both the file descriptors are closed.
 * pre: rfd_a: One read file descriptor
 *      wfd_a: One write file descriptor
 *      rfd_b: The other read file descriptor
 *      wfd_b: The other write file descriptor
 *      buffer:   allocated buffer to read data into
 *      buffer_length: size of buffer in bytes
 *      idle_timeout:  timeout in seconds to wait for input
 *                     timeout of 0 = infinite timeout
 *      return_a_read_bytes: Pointer to size_t where number
 *                           of bytes read from a will be recorded.
 *                           Note that this may wrap
 *      return_b_read_bytes: Pointer to size_t where number
 *                           of bytes read from b will be recorded.
 *                           Note that this may wrap
 *      read_func: Function to use for low level reading.
 *                 If null, then a simple wrapper around read(2) is used
 *      write_func: Function to use for low level writing.
 *                 If null, then a simple wrapper around write(2) is used
 *      select_func: Function to use for select.
 *                 If null, then a simple wrapper around select(2) is used
 *      data: opaque data, passed to read_func, write_func and select_func
 * post: data is read from rfd_a and written to wfd_b and read
 *       from rfd_b and written to wfd_a.
 * return: -1 on error
 *         1 on idle timeout
 *         0 otherwise (one of the file desciptors closes gracefully)
 **********************************************************************/

static int __vanessa_socket_pipe_dummy_select(int n, fd_set *readfds, 
		fd_set *writefds, fd_set *exceptfds, struct timeval *timeout, 
		void *UNUSED(data))
{
	return(select(n, readfds, writefds, exceptfds, timeout));
}


int vanessa_socket_pipe_func(int rfd_a, int wfd_a, int rfd_b, int wfd_b, 
		char *buffer, int buffer_length, int idle_timeout,
		size_t *return_a_read_bytes, size_t *return_b_read_bytes, 
		ssize_t(*read_func) (int fd, void *buf, size_t count, 
			void *data), 
		ssize_t(*write_func) (int fd, const void *buf, size_t count, 
			void *data), 
		int(*select_func) (int n, fd_set *readfds, fd_set *writefds, 
			fd_set *exceptfds, struct timeval *timeout, 
			void *data), 
		void *data)
{
	fd_set read_template;
	fd_set except_template;
	struct timeval timeout;
	int status;
	ssize_t bytes = 0;
	int hifd;

	if(read_func == NULL) {
		read_func = vanessa_socket_pipe_fd_read;
	}
	if(write_func == NULL) {
		write_func = vanessa_socket_pipe_fd_write;
	}
	if(select_func == NULL) {
		select_func = __vanessa_socket_pipe_dummy_select;
	}

	hifd = (rfd_a > rfd_b) ? rfd_a : rfd_b;

	for (;;) {
		FD_ZERO(&read_template);
		FD_SET(rfd_a, &read_template);
		FD_SET(rfd_b, &read_template);

		FD_ZERO(&except_template);
		FD_SET(rfd_a, &except_template);
		FD_SET(rfd_b, &except_template);

		timeout.tv_sec = idle_timeout;
		timeout.tv_usec = 0;

		status = select_func(hifd + 1, &read_template, NULL, 
				&except_template, 
				idle_timeout ? &timeout : NULL, data);
		if (status < 0) {
			if (errno != EINTR) {
				VANESSA_LOGGER_DEBUG_ERRNO("select");
				return (-1);
			}
			continue;	/* Ignore EINTR */
		} else if (FD_ISSET(rfd_a, &except_template) ||
			   FD_ISSET(rfd_b, &except_template)
		    ) {
			VANESSA_LOGGER_DEBUG("except_template set");
			return (-1);
		} else if (status == 0) {
			return (1);
		} else if (FD_ISSET(rfd_a, &read_template)) {
			bytes = vanessa_socket_pipe_read_write_func(rfd_a, 
					wfd_b, buffer, buffer_length, 
					read_func, write_func, data);
			*return_a_read_bytes += (bytes > 0) ? (size_t)bytes : 0;
		} else if (FD_ISSET(rfd_b, &read_template)) {
			bytes = vanessa_socket_pipe_read_write_func(rfd_b, 
					wfd_a, buffer, buffer_length, 
					read_func, write_func, data);
			*return_b_read_bytes += (bytes > 0) ? (size_t)bytes : 0;
		}
		if (bytes < 0) {
			VANESSA_LOGGER_DEBUG
			    ("vanessa_socket_pipe_read_write_func");
			return (-1);
		} else if (!bytes) {
			return (0);
		}
	}
}


/**********************************************************************
 * vanessa_socket_pipe 
 * Moved to a macro defined elsewhere
 **********************************************************************/


/**********************************************************************
 * vanessa_socket_pipe_read_write_func
 * Read data from one file io_t and write to another
 * pre: rfd: file descriptor to read from
 *      wfd: file descriptor to write to
 *      buffer: allocated buffer to store read data in
 *      buffer_length: size of the buffer
 *      read_func: function to use for low level reading
 *                  If null, then a simple wrapper around read(2) is used
 *      write_func: function to use for low level writing
 *                  If null, then a simple wrapper around write(2) is used
 *      data: opaque data passed to read_func and write_func
 * post: at most buffer_length bytes are read from in_fd and written 
 *       to out_fd. 
 * return: bytes read on success
 *         0 on EOF
 *         -1 on error
 **********************************************************************/

ssize_t vanessa_socket_pipe_read_write_func(int rfd, int wfd, 
		char *buffer, int buffer_length,
		ssize_t(*read_func) (int fd, void *buf, size_t count, 
			void *data), 
		ssize_t(*write_func) (int fd, const void *buf, size_t count, 
			void *data), 
		void *data)
{
	ssize_t bytes;

	if(read_func == NULL) {
		read_func = vanessa_socket_pipe_fd_read;
	}
	if(write_func == NULL) {
		write_func = vanessa_socket_pipe_fd_write;
	}


	bytes = read_func(rfd, buffer, buffer_length, data);
	if (bytes < 0) {
		if (errno) {
			VANESSA_LOGGER_DEBUG("vanessa_socket_io_read");
		}
		return (-1);
	} else if (bytes == 0) {
		return (0);
	}
	if (vanessa_socket_pipe_write_bytes_func
	    (wfd, buffer, bytes, write_func, data)) {
		VANESSA_LOGGER_DEBUG("vanessa_socket_pipe_write_bytes");
		return (-1);
	}

	return (bytes);
}


/**********************************************************************
 * vanessa_socket_pipe_read_write
 * Moved to a macro defined elsewhere
 **********************************************************************/


/**********************************************************************
 * vanessa_socket_pipe_write_bytes_func
 * write a n bytes of a buffer to fd
 * Pre: fd: file descriptor to write to
 *      buffer: buffer to write
 *      n: number or bytes to write
 *      write_func: function to use for low level writing
 *      fd_data: opaque data relating to fd, to pass to write_func
 * Return: -1 on error
 *         0 otherwise
 **********************************************************************/

int vanessa_socket_pipe_write_bytes_func(int fd, const char *buffer,
		const ssize_t n, 
		ssize_t(*write_func) (int fd, const void *buf, size_t count, 
			void *data), 
		void *fd_data)
{
	ssize_t offset;
	ssize_t bytes_written;

	if (n == 0) {
		return (0);
	}

	if(write_func == NULL) {
		write_func = vanessa_socket_pipe_fd_write;
	}

	offset = 0;
	do {
		bytes_written = write_func(fd, buffer + offset, n - offset, 
				fd_data);
		if (bytes_written < 0) {
			VANESSA_LOGGER_DEBUG_ERRNO("write_func");
			return (-1);
		}
		offset += bytes_written;
	} while (offset < n);

	return (0);
}


/**********************************************************************
 * vanessa_socket_pipe_write_bytes
 * Moved to a macro defined elsewhere
 **********************************************************************/