~ubuntu-branches/ubuntu/maverick/transmission/maverick

« back to all changes in this revision

Viewing changes to gtk/io.c

  • Committer: Bazaar Package Importer
  • Author(s): Philipp Benner
  • Date: 2006-08-29 20:50:41 UTC
  • Revision ID: james.westby@ubuntu.com-20060829205041-mzhpiqksdf7pbk17
Tags: upstream-0.6.1.dfsg
ImportĀ upstreamĀ versionĀ 0.6.1.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  $Id: io.c 261 2006-05-29 21:27:31Z titer $
 
3
 
 
4
  Copyright (c) 2006 Joshua Elsasser. All rights reserved.
 
5
   
 
6
  Redistribution and use in source and binary forms, with or without
 
7
  modification, are permitted provided that the following conditions
 
8
  are met:
 
9
   
 
10
   1. Redistributions of source code must retain the above copyright
 
11
      notice, this list of conditions and the following disclaimer.
 
12
   2. Redistributions in binary form must reproduce the above copyright
 
13
      notice, this list of conditions and the following disclaimer in the
 
14
      documentation and/or other materials provided with the distribution.
 
15
   
 
16
  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
 
17
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
18
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
19
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 
20
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
21
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
22
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
23
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
24
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
25
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
26
  POSSIBILITY OF SUCH DAMAGE.
 
27
*/
 
28
 
 
29
#include <sys/types.h>
 
30
#include <sys/socket.h>
 
31
#include <sys/uio.h>
 
32
#include <errno.h>
 
33
#include <fcntl.h>
 
34
#include <string.h>
 
35
#include <unistd.h>
 
36
 
 
37
#include <glib.h>
 
38
 
 
39
#include "io.h"
 
40
#include "util.h"
 
41
 
 
42
#define IO_BLOCKSIZE            (1024)
 
43
 
 
44
struct iosource {
 
45
  GSource source;
 
46
  GPollFD infd;
 
47
  GPollFD outfd;
 
48
  ioidfunc_t sent;
 
49
  iodatafunc_t received;
 
50
  ionewfunc_t accepted;
 
51
  iofunc_t closed;
 
52
  void *cbdata;
 
53
  char *inbuf;
 
54
  unsigned int inused;
 
55
  unsigned int inmax;
 
56
  GList *outbufs;
 
57
  unsigned int lastid;
 
58
};
 
59
 
 
60
struct iooutbuf {
 
61
  char *data;
 
62
  unsigned int len;
 
63
  unsigned int off;
 
64
  unsigned int id;
 
65
};
 
66
 
 
67
static gboolean
 
68
nonblock(int fd);
 
69
static struct iosource *
 
70
newsource(void);
 
71
static void
 
72
freeoutbuf(struct iooutbuf *buf);
 
73
static gboolean
 
74
io_prepare(GSource *source, gint *timeout_);
 
75
static gboolean
 
76
io_check(GSource *source);
 
77
static gboolean
 
78
io_dispatch(GSource *source, GSourceFunc callback, gpointer gdata);
 
79
static void
 
80
io_finalize(GSource *source);
 
81
static void
 
82
io_accept(struct iosource *io);
 
83
static void
 
84
io_read(struct iosource *io);
 
85
static void
 
86
io_write(struct iosource *io);
 
87
static void
 
88
io_disconnect(struct iosource *io, int err);
 
89
 
 
90
static GSourceFuncs sourcefuncs = {
 
91
  io_prepare,
 
92
  io_check,
 
93
  io_dispatch,
 
94
  io_finalize,
 
95
  NULL,
 
96
  NULL
 
97
};
 
98
 
 
99
GSource *
 
100
io_new(int fd, ioidfunc_t sent, iodatafunc_t received,
 
101
       iofunc_t closed, void *cbdata) {
 
102
  struct iosource *io;
 
103
 
 
104
  if(!nonblock(fd))
 
105
    return NULL;
 
106
 
 
107
  io = newsource();
 
108
  io->sent = sent;
 
109
  io->received = received;
 
110
  io->closed = closed;
 
111
  io->cbdata = cbdata;
 
112
  io->infd.fd = fd;
 
113
  io->infd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
 
114
  io->infd.revents = 0;
 
115
  io->outfd.fd = fd;
 
116
  io->outfd.events = G_IO_OUT | G_IO_ERR;
 
117
  io->outfd.revents = 0;
 
118
 
 
119
  g_source_add_poll((GSource*)io, &io->infd);
 
120
  g_source_attach((GSource*)io, NULL);
 
121
 
 
122
  return (GSource*)io;
 
123
}
 
124
 
 
125
GSource *
 
126
io_new_listening(int fd, socklen_t len, ionewfunc_t accepted,
 
127
                 iofunc_t closed, void *cbdata) {
 
128
  struct iosource *io;
 
129
 
 
130
  g_assert(NULL != accepted);
 
131
 
 
132
  if(!nonblock(fd))
 
133
    return NULL;
 
134
 
 
135
  io = newsource();
 
136
  io->accepted = accepted;
 
137
  io->closed = closed;
 
138
  io->cbdata = cbdata;
 
139
  io->infd.fd = fd;
 
140
  io->infd.events = G_IO_IN | G_IO_ERR;
 
141
  io->infd.revents = 0;
 
142
  io->inbuf = g_new(char, len);
 
143
  io->inmax = len;
 
144
 
 
145
  g_source_add_poll((GSource*)io, &io->infd);
 
146
  g_source_attach((GSource*)io, NULL);
 
147
 
 
148
  return (GSource*)io;
 
149
}
 
150
 
 
151
static gboolean
 
152
nonblock(int fd) {
 
153
  int flags;
 
154
 
 
155
  if(0 > (flags = fcntl(fd, F_GETFL)) ||
 
156
     0 > fcntl(fd, F_SETFL, flags | O_NONBLOCK))
 
157
    return FALSE;
 
158
 
 
159
  return TRUE;
 
160
}
 
161
 
 
162
static struct iosource *
 
163
newsource(void) {
 
164
  GSource *source = g_source_new(&sourcefuncs, sizeof(struct iosource));
 
165
  struct iosource *io = (struct iosource*)source;
 
166
 
 
167
  io->sent = NULL;
 
168
  io->received = NULL;
 
169
  io->accepted = NULL;
 
170
  io->closed = NULL;
 
171
  io->cbdata = NULL;
 
172
  bzero(&io->infd, sizeof(io->infd));
 
173
  io->infd.fd = -1;
 
174
  bzero(&io->outfd, sizeof(io->outfd));
 
175
  io->outfd.fd = -1;
 
176
  io->inbuf = NULL;
 
177
  io->inused = 0;
 
178
  io->inmax = 0;
 
179
  io->outbufs = NULL;
 
180
  io->lastid = 0;
 
181
 
 
182
  return io;
 
183
}
 
184
 
 
185
unsigned int
 
186
io_send(GSource *source, const char *data, unsigned int len) {
 
187
  char *new = g_new(char, len);
 
188
 
 
189
  memcpy(new, data, len);
 
190
 
 
191
  return io_send_keepdata(source, new, len);
 
192
}
 
193
 
 
194
unsigned int
 
195
io_send_keepdata(GSource *source, char *data, unsigned int len) {
 
196
  struct iosource *io = (struct iosource*)source;
 
197
  struct iooutbuf *buf = g_new(struct iooutbuf, 1);
 
198
 
 
199
  buf->data = data;
 
200
  buf->len = len;
 
201
  buf->off = 0;
 
202
  io->lastid++;
 
203
  buf->id = io->lastid;
 
204
 
 
205
  if(NULL != io->outbufs)
 
206
    io->outbufs = g_list_append(io->outbufs, buf);
 
207
  else {
 
208
    io->outbufs = g_list_append(io->outbufs, buf);
 
209
    g_source_add_poll(source, &io->outfd);
 
210
  }
 
211
 
 
212
  return io->lastid;
 
213
}
 
214
 
 
215
static void
 
216
freeoutbuf(struct iooutbuf *buf) {
 
217
  if(NULL != buf->data)
 
218
    g_free(buf->data);
 
219
  g_free(buf);
 
220
}
 
221
 
 
222
static gboolean
 
223
io_prepare(GSource *source SHUTUP, gint *timeout_) {
 
224
  *timeout_ = -1;
 
225
  return FALSE;
 
226
}
 
227
 
 
228
static gboolean
 
229
io_check(GSource *source) {
 
230
  struct iosource *io = (struct iosource*)source;
 
231
 
 
232
  if(io->infd.revents)
 
233
    return TRUE;
 
234
  if(NULL != io->outbufs && io->outfd.revents)
 
235
    return TRUE;
 
236
  else
 
237
    return FALSE;
 
238
}
 
239
 
 
240
static gboolean
 
241
io_dispatch(GSource *source, GSourceFunc callback SHUTUP,
 
242
            gpointer gdata SHUTUP) {
 
243
  struct iosource *io = (struct iosource*)source;
 
244
 
 
245
  if(io->infd.revents & (G_IO_ERR | G_IO_HUP) ||
 
246
     io->outfd.revents & G_IO_ERR)
 
247
    io_disconnect(io, 0 /* XXX how do I get errors here? */ );
 
248
  else if(io->infd.revents & G_IO_IN)
 
249
    (NULL == io->accepted ? io_read : io_accept)(io);
 
250
  else if(io->outfd.revents & G_IO_OUT)
 
251
    io_write(io);
 
252
  else
 
253
    return FALSE;
 
254
 
 
255
  return TRUE;
 
256
}
 
257
 
 
258
 
 
259
static void
 
260
io_finalize(GSource *source SHUTUP) {
 
261
  struct iosource *io = (struct iosource*)source;
 
262
 
 
263
  if(NULL != io->outbufs) {
 
264
    g_list_foreach(io->outbufs, (GFunc)freeoutbuf, NULL);
 
265
    g_list_free(io->outbufs);
 
266
  }
 
267
 
 
268
  if(NULL != io->inbuf)
 
269
    g_free(io->inbuf);
 
270
}
 
271
 
 
272
static void
 
273
io_biggify(char **buf, unsigned int used, unsigned int *max) {
 
274
  if(used + IO_BLOCKSIZE > *max) {
 
275
    *max += IO_BLOCKSIZE;
 
276
    *buf = g_renew(char, *buf, *max);
 
277
  }
 
278
}
 
279
 
 
280
static void
 
281
io_accept(struct iosource *io) {
 
282
  int fd;
 
283
  socklen_t len;
 
284
 
 
285
  if(0 > (fd = accept(io->infd.fd, (struct sockaddr*)io->inbuf, &len))) {
 
286
    if(EAGAIN == errno || ECONNABORTED == errno || EWOULDBLOCK == errno)
 
287
      return;
 
288
    io_disconnect(io, errno);
 
289
  }
 
290
 
 
291
  io->accepted((GSource*)io, fd, (struct sockaddr*)io->inbuf, len, io->cbdata);
 
292
}
 
293
 
 
294
static void
 
295
io_read(struct iosource *io) {
 
296
  ssize_t res = 0;
 
297
  gboolean newdata = FALSE;
 
298
  unsigned int used;
 
299
  int err = 0;
 
300
 
 
301
  g_source_ref((GSource*)io);
 
302
 
 
303
  do {
 
304
    if(!newdata && 0 < res)
 
305
      newdata = TRUE;
 
306
    io->inused += res;
 
307
    io_biggify(&io->inbuf, io->inused, &io->inmax);
 
308
    errno = 0;
 
309
    res = read(io->infd.fd, io->inbuf + io->inused, io->inmax - io->inused);
 
310
    if(0 > res)
 
311
      err = errno;
 
312
  } while(0 < res);
 
313
 
 
314
  if(NULL == io->received)
 
315
    io->inused = 0;
 
316
  else if(newdata) {
 
317
    used = io->received((GSource*)io, io->inbuf, io->inused, io->cbdata);
 
318
    if(used > io->inused)
 
319
      used = io->inused;
 
320
    if(0 < used) {
 
321
      if(used < io->inused)
 
322
        memmove(io->inbuf, io->inbuf + used, io->inused - used);
 
323
      io->inused -= used;
 
324
    }
 
325
  }
 
326
 
 
327
  if(0 != err && EAGAIN != err)
 
328
    io_disconnect(io, err);
 
329
  else if(0 == res)
 
330
    io_disconnect(io, 0);
 
331
  g_source_unref((GSource*)io);
 
332
}
 
333
 
 
334
static void
 
335
io_write(struct iosource *io) {
 
336
  struct iooutbuf *buf;
 
337
  ssize_t res = 1;
 
338
  int err = 0;
 
339
 
 
340
  g_source_ref((GSource*)io);
 
341
 
 
342
  while(NULL != io->outbufs && 0 == err) {
 
343
    buf = io->outbufs->data;
 
344
    while(buf->off < buf->len && 0 < res) {
 
345
      errno = 0;
 
346
      res = write(io->outfd.fd, buf->data + buf->off, buf->len - buf->off);
 
347
      if(0 > res)
 
348
        err = errno;
 
349
      else
 
350
        buf->off += res;
 
351
    }
 
352
 
 
353
    if(buf->off >= buf->len) {
 
354
      io->outbufs = g_list_remove(io->outbufs, buf);
 
355
      if(NULL == io->outbufs)
 
356
        g_source_remove_poll((GSource*)io, &io->outfd);
 
357
      if(NULL != io->sent)
 
358
        io->sent((GSource*)io, buf->id, io->cbdata);
 
359
      freeoutbuf(buf);
 
360
    }
 
361
  }
 
362
 
 
363
  if(0 != err && EAGAIN != err)
 
364
    io_disconnect(io, err);
 
365
 
 
366
  g_source_unref((GSource*)io);
 
367
}
 
368
 
 
369
static void
 
370
io_disconnect(struct iosource *io, int err) {
 
371
  if(NULL != io->closed) {
 
372
    errno = err;
 
373
    io->closed((GSource*)io, io->cbdata);
 
374
  }
 
375
 
 
376
  if(NULL != io->outbufs)
 
377
    g_source_remove_poll((GSource*)io, &io->outfd);
 
378
 
 
379
  g_source_remove_poll((GSource*)io, &io->infd);
 
380
  g_source_remove(g_source_get_id((GSource*)io));
 
381
  g_source_unref((GSource*)io);
 
382
}