1
/******************************************************************************
2
* $Id: tr-io.c 5276 2008-03-18 01:22:11Z charles $
4
* Copyright (c) 2006-2008 Transmission authors and contributors
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the "Software"),
8
* to deal in the Software without restriction, including without limitation
9
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
* and/or sell copies of the Software, and to permit persons to whom the
11
* Software is furnished to do so, subject to the following conditions:
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
* DEALINGS IN THE SOFTWARE.
23
*****************************************************************************/
25
#include <sys/types.h>
26
#include <sys/socket.h>
28
#include <string.h> /* memset, memmove */
29
#include <unistd.h> /* read, write */
33
#include <libevent/evutil.h> /* evutil_make_socket_nonblocking */
38
#define IO_BLOCKSIZE (1024)
45
iodatafunc_t received;
64
io_prepare(GSource *source UNUSED, gint *timeout_) {
70
io_check(GSource *source) {
71
struct iosource *io = (struct iosource*)source;
75
if(NULL != io->outbufs && io->outfd.revents)
82
io_disconnect(struct iosource *io, int err) {
83
if(NULL != io->closed) {
85
io->closed((GSource*)io, io->cbdata);
88
if(NULL != io->outbufs)
89
g_source_remove_poll((GSource*)io, &io->outfd);
91
g_source_remove_poll((GSource*)io, &io->infd);
92
g_source_remove(g_source_get_id((GSource*)io));
93
g_source_unref((GSource*)io);
97
io_biggify(char **buf, size_t used, size_t *max) {
98
if(used + IO_BLOCKSIZE > *max) {
100
*buf = g_renew(char, *buf, *max);
105
io_read(struct iosource *io) {
107
gboolean newdata = FALSE;
111
g_source_ref((GSource*)io);
114
if(!newdata && 0 < res)
117
io_biggify(&io->inbuf, io->inused, &io->inmax);
119
res = read(io->infd.fd, io->inbuf + io->inused, io->inmax - io->inused);
124
if(NULL == io->received)
127
used = io->received((GSource*)io, io->inbuf, io->inused, io->cbdata);
128
if(used > io->inused)
131
if(used < io->inused)
132
memmove(io->inbuf, io->inbuf + used, io->inused - used);
137
if(0 != err && EAGAIN != err)
138
io_disconnect(io, err);
140
io_disconnect(io, 0);
141
g_source_unref((GSource*)io);
145
io_accept(struct iosource *io) {
150
if(0 > (fd = accept(io->infd.fd, (struct sockaddr*)io->inbuf, &len))) {
151
if(EAGAIN == errno || ECONNABORTED == errno || EWOULDBLOCK == errno)
153
io_disconnect(io, errno);
156
io->accepted((GSource*)io, fd, (struct sockaddr*)io->inbuf, len, io->cbdata);
160
freeoutbuf(struct iooutbuf *buf) {
161
if(NULL != buf->data)
167
io_write(struct iosource *io) {
168
struct iooutbuf *buf;
172
g_source_ref((GSource*)io);
174
while(NULL != io->outbufs && 0 == err) {
175
buf = io->outbufs->data;
176
while(buf->off < buf->len && 0 < res) {
178
res = write(io->outfd.fd, buf->data + buf->off, buf->len - buf->off);
185
if(buf->off >= buf->len) {
186
io->outbufs = g_slist_remove(io->outbufs, buf);
187
if(NULL == io->outbufs)
188
g_source_remove_poll((GSource*)io, &io->outfd);
190
io->sent((GSource*)io, buf->id, io->cbdata);
195
if(0 != err && EAGAIN != err)
196
io_disconnect(io, err);
198
g_source_unref((GSource*)io);
202
io_dispatch(GSource *source, GSourceFunc callback UNUSED,
203
gpointer gdata UNUSED) {
204
struct iosource *io = (struct iosource*)source;
206
if(io->infd.revents & (G_IO_ERR | G_IO_HUP) ||
207
io->outfd.revents & G_IO_ERR)
208
io_disconnect(io, 0 /* XXX how do I get errors here? */ );
209
else if(io->infd.revents & G_IO_IN)
210
(NULL == io->accepted ? io_read : io_accept)(io);
211
else if(io->outfd.revents & G_IO_OUT)
220
io_finalize(GSource *source UNUSED) {
221
struct iosource *io = (struct iosource*)source;
223
g_slist_foreach(io->outbufs, (GFunc)freeoutbuf, NULL);
224
g_slist_free(io->outbufs);
231
static GSourceFuncs sourcefuncs = {
240
static struct iosource *
242
GSource *source = g_source_new(&sourcefuncs, sizeof(struct iosource));
243
struct iosource *io = (struct iosource*)source;
250
memset(&io->infd, 0, sizeof(io->infd));
252
memset(&io->outfd, 0, sizeof(io->outfd));
264
io_new(int fd, ioidfunc_t sent, iodatafunc_t received,
265
iofunc_t closed, void *cbdata) {
268
if( evutil_make_socket_nonblocking( fd ) )
273
io->received = received;
277
io->infd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
278
io->infd.revents = 0;
280
io->outfd.events = G_IO_OUT | G_IO_ERR;
281
io->outfd.revents = 0;
283
g_source_add_poll((GSource*)io, &io->infd);
284
g_source_attach((GSource*)io, NULL);
290
io_new_listening(int fd, socklen_t len, ionewfunc_t accepted,
291
iofunc_t closed, void *cbdata) {
294
g_assert(NULL != accepted);
296
if( evutil_make_socket_nonblocking( fd ) )
300
io->accepted = accepted;
304
io->infd.events = G_IO_IN | G_IO_ERR;
305
io->infd.revents = 0;
306
io->inbuf = g_new(char, len);
309
g_source_add_poll((GSource*)io, &io->infd);
310
g_source_attach((GSource*)io, NULL);
316
io_send_keepdata(GSource *source, void *data, size_t len) {
317
struct iosource *io = (struct iosource*)source;
318
struct iooutbuf *buf = g_new(struct iooutbuf, 1);
324
buf->id = io->lastid;
326
if(NULL != io->outbufs)
327
io->outbufs = g_slist_append(io->outbufs, buf);
329
io->outbufs = g_slist_append(io->outbufs, buf);
330
g_source_add_poll(source, &io->outfd);