~ubuntu-branches/ubuntu/jaunty/transmission/jaunty-security

« back to all changes in this revision

Viewing changes to gtk/tr-io.c

  • Committer: Bazaar Package Importer
  • Author(s): Chris Coulson
  • Date: 2008-11-28 15:33:48 UTC
  • mfrom: (1.1.19 upstream)
  • Revision ID: james.westby@ubuntu.com-20081128153348-it70trfnxiroblmc
Tags: 1.40-0ubuntu1
* New upstream release (LP: #302672)
  - Tracker communication uses fewer resources
  - More accurate bandwidth limits
  - Reduce disk fragmentation by preallocating files (LP: #287726)
  - Stability, security and performance improvements to the RPC /
    Web UI server (closes LP: #290423)
  - Support compression when serving Web UI and RPC responses
  - Simplify the RPC whitelist
  - Fix bug that prevented handshakes with encrypted BitComet peers
  - Fix 1.3x bug that could re-download some data unnecessarily
    (LP: #295040)
  - Option to automatically update the blocklist weekly
  - Added off-hour bandwidth scheduling
  - Simplify file/priority selection in the details dialog
  - Fix a couple of crashes
  - New / updated translations
  - Don't inhibit hibernation by default (LP: #292929)
  - Use "close" animation when sending to notification area (LP: #130811)
  - Fix resize problems (LP: #269872)
  - Support "--version" option when launching from command line
    (LP: #292011)
  - Correctly parse announce URLs that have leading or trailing
    spaces (LP: #262411)
  - Display an error when "Open Torrent" fails (LP: #281463)
* Dropped 10_fix_crasher_from_upstream.dpatch: Fix is in this
  upstream release.
* debian/control: Don't just build-depend on libcurl-dev, which is
  a virtual package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 * $Id: tr-io.c 5276 2008-03-18 01:22:11Z charles $
3
 
 *
4
 
 * Copyright (c) 2006-2008 Transmission authors and contributors
5
 
 *
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:
12
 
 *
13
 
 * The above copyright notice and this permission notice shall be included in
14
 
 * all copies or substantial portions of the Software.
15
 
 *
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
 
 *****************************************************************************/
24
 
 
25
 
#include <sys/types.h>
26
 
#include <sys/socket.h>
27
 
#include <errno.h>
28
 
#include <string.h> /* memset, memmove */
29
 
#include <unistd.h> /* read, write */
30
 
 
31
 
#include <glib.h>
32
 
 
33
 
#include <libevent/evutil.h> /* evutil_make_socket_nonblocking */
34
 
 
35
 
#include "tr-io.h"
36
 
#include "util.h"
37
 
 
38
 
#define IO_BLOCKSIZE (1024)
39
 
 
40
 
struct iosource {
41
 
  GSource source;
42
 
  GPollFD infd;
43
 
  GPollFD outfd;
44
 
  ioidfunc_t sent;
45
 
  iodatafunc_t received;
46
 
  ionewfunc_t accepted;
47
 
  iofunc_t closed;
48
 
  void *cbdata;
49
 
  char *inbuf;
50
 
  size_t inused;
51
 
  size_t inmax;
52
 
  GSList *outbufs;
53
 
  unsigned int lastid;
54
 
};
55
 
 
56
 
struct iooutbuf {
57
 
  char *data;
58
 
  size_t len;
59
 
  size_t off;
60
 
  unsigned int id;
61
 
};
62
 
 
63
 
static gboolean
64
 
io_prepare(GSource *source UNUSED, gint *timeout_) {
65
 
  *timeout_ = -1;
66
 
  return FALSE;
67
 
}
68
 
 
69
 
static gboolean
70
 
io_check(GSource *source) {
71
 
  struct iosource *io = (struct iosource*)source;
72
 
 
73
 
  if(io->infd.revents)
74
 
    return TRUE;
75
 
  if(NULL != io->outbufs && io->outfd.revents)
76
 
    return TRUE;
77
 
  else
78
 
    return FALSE;
79
 
}
80
 
 
81
 
static void
82
 
io_disconnect(struct iosource *io, int err) {
83
 
  if(NULL != io->closed) {
84
 
    errno = err;
85
 
    io->closed((GSource*)io, io->cbdata);
86
 
  }
87
 
 
88
 
  if(NULL != io->outbufs)
89
 
    g_source_remove_poll((GSource*)io, &io->outfd);
90
 
 
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);
94
 
}
95
 
 
96
 
static void
97
 
io_biggify(char **buf, size_t used, size_t *max) {
98
 
  if(used + IO_BLOCKSIZE > *max) {
99
 
    *max += IO_BLOCKSIZE;
100
 
    *buf = g_renew(char, *buf, *max);
101
 
  }
102
 
}
103
 
 
104
 
static void
105
 
io_read(struct iosource *io) {
106
 
  ssize_t res = 0;
107
 
  gboolean newdata = FALSE;
108
 
  size_t used;
109
 
  int err = 0;
110
 
 
111
 
  g_source_ref((GSource*)io);
112
 
 
113
 
  do {
114
 
    if(!newdata && 0 < res)
115
 
      newdata = TRUE;
116
 
    io->inused += res;
117
 
    io_biggify(&io->inbuf, io->inused, &io->inmax);
118
 
    errno = 0;
119
 
    res = read(io->infd.fd, io->inbuf + io->inused, io->inmax - io->inused);
120
 
    if(0 > res)
121
 
      err = errno;
122
 
  } while(0 < res);
123
 
 
124
 
  if(NULL == io->received)
125
 
    io->inused = 0;
126
 
  else if(newdata) {
127
 
    used = io->received((GSource*)io, io->inbuf, io->inused, io->cbdata);
128
 
    if(used > io->inused)
129
 
      used = io->inused;
130
 
    if(0 < used) {
131
 
      if(used < io->inused)
132
 
        memmove(io->inbuf, io->inbuf + used, io->inused - used);
133
 
      io->inused -= used;
134
 
    }
135
 
  }
136
 
 
137
 
  if(0 != err && EAGAIN != err)
138
 
    io_disconnect(io, err);
139
 
  else if(0 == res)
140
 
    io_disconnect(io, 0);
141
 
  g_source_unref((GSource*)io);
142
 
}
143
 
 
144
 
static void
145
 
io_accept(struct iosource *io) {
146
 
  int fd;
147
 
  socklen_t len;
148
 
 
149
 
  len = io->inmax;
150
 
  if(0 > (fd = accept(io->infd.fd, (struct sockaddr*)io->inbuf, &len))) {
151
 
    if(EAGAIN == errno || ECONNABORTED == errno || EWOULDBLOCK == errno)
152
 
      return;
153
 
    io_disconnect(io, errno);
154
 
  }
155
 
 
156
 
  io->accepted((GSource*)io, fd, (struct sockaddr*)io->inbuf, len, io->cbdata);
157
 
}
158
 
 
159
 
static void
160
 
freeoutbuf(struct iooutbuf *buf) {
161
 
  if(NULL != buf->data)
162
 
    g_free(buf->data);
163
 
  g_free(buf);
164
 
}
165
 
 
166
 
static void
167
 
io_write(struct iosource *io) {
168
 
  struct iooutbuf *buf;
169
 
  ssize_t res = 1;
170
 
  int err = 0;
171
 
 
172
 
  g_source_ref((GSource*)io);
173
 
 
174
 
  while(NULL != io->outbufs && 0 == err) {
175
 
    buf = io->outbufs->data;
176
 
    while(buf->off < buf->len && 0 < res) {
177
 
      errno = 0;
178
 
      res = write(io->outfd.fd, buf->data + buf->off, buf->len - buf->off);
179
 
      if(0 > res)
180
 
        err = errno;
181
 
      else
182
 
        buf->off += res;
183
 
    }
184
 
 
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);
189
 
      if(NULL != io->sent)
190
 
        io->sent((GSource*)io, buf->id, io->cbdata);
191
 
      freeoutbuf(buf);
192
 
    }
193
 
  }
194
 
 
195
 
  if(0 != err && EAGAIN != err)
196
 
    io_disconnect(io, err);
197
 
 
198
 
  g_source_unref((GSource*)io);
199
 
}
200
 
 
201
 
static gboolean
202
 
io_dispatch(GSource *source, GSourceFunc callback UNUSED,
203
 
            gpointer gdata UNUSED) {
204
 
  struct iosource *io = (struct iosource*)source;
205
 
 
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)
212
 
    io_write(io);
213
 
  else
214
 
    return FALSE;
215
 
 
216
 
  return TRUE;
217
 
}
218
 
 
219
 
static void
220
 
io_finalize(GSource *source UNUSED) {
221
 
  struct iosource *io = (struct iosource*)source;
222
 
 
223
 
  g_slist_foreach(io->outbufs, (GFunc)freeoutbuf, NULL);
224
 
  g_slist_free(io->outbufs);
225
 
  g_free(io->inbuf);
226
 
 
227
 
  io->outbufs = NULL;
228
 
  io->inbuf = NULL;
229
 
}
230
 
 
231
 
static GSourceFuncs sourcefuncs = {
232
 
  io_prepare,
233
 
  io_check,
234
 
  io_dispatch,
235
 
  io_finalize,
236
 
  NULL,
237
 
  NULL
238
 
};
239
 
 
240
 
static struct iosource *
241
 
newsource(void) {
242
 
  GSource *source = g_source_new(&sourcefuncs, sizeof(struct iosource));
243
 
  struct iosource *io = (struct iosource*)source;
244
 
 
245
 
  io->sent = NULL;
246
 
  io->received = NULL;
247
 
  io->accepted = NULL;
248
 
  io->closed = NULL;
249
 
  io->cbdata = NULL;
250
 
  memset(&io->infd, 0,  sizeof(io->infd));
251
 
  io->infd.fd = -1;
252
 
  memset(&io->outfd, 0,  sizeof(io->outfd));
253
 
  io->outfd.fd = -1;
254
 
  io->inbuf = NULL;
255
 
  io->inused = 0;
256
 
  io->inmax = 0;
257
 
  io->outbufs = NULL;
258
 
  io->lastid = 0;
259
 
 
260
 
  return io;
261
 
}
262
 
 
263
 
GSource *
264
 
io_new(int fd, ioidfunc_t sent, iodatafunc_t received,
265
 
       iofunc_t closed, void *cbdata) {
266
 
  struct iosource *io;
267
 
 
268
 
  if( evutil_make_socket_nonblocking( fd ) )
269
 
    return NULL;
270
 
 
271
 
  io = newsource();
272
 
  io->sent = sent;
273
 
  io->received = received;
274
 
  io->closed = closed;
275
 
  io->cbdata = cbdata;
276
 
  io->infd.fd = fd;
277
 
  io->infd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
278
 
  io->infd.revents = 0;
279
 
  io->outfd.fd = fd;
280
 
  io->outfd.events = G_IO_OUT | G_IO_ERR;
281
 
  io->outfd.revents = 0;
282
 
 
283
 
  g_source_add_poll((GSource*)io, &io->infd);
284
 
  g_source_attach((GSource*)io, NULL);
285
 
 
286
 
  return (GSource*)io;
287
 
}
288
 
 
289
 
GSource *
290
 
io_new_listening(int fd, socklen_t len, ionewfunc_t accepted,
291
 
                 iofunc_t closed, void *cbdata) {
292
 
  struct iosource *io;
293
 
 
294
 
  g_assert(NULL != accepted);
295
 
 
296
 
  if( evutil_make_socket_nonblocking( fd ) )
297
 
    return NULL;
298
 
 
299
 
  io = newsource();
300
 
  io->accepted = accepted;
301
 
  io->closed = closed;
302
 
  io->cbdata = cbdata;
303
 
  io->infd.fd = fd;
304
 
  io->infd.events = G_IO_IN | G_IO_ERR;
305
 
  io->infd.revents = 0;
306
 
  io->inbuf = g_new(char, len);
307
 
  io->inmax = len;
308
 
 
309
 
  g_source_add_poll((GSource*)io, &io->infd);
310
 
  g_source_attach((GSource*)io, NULL);
311
 
 
312
 
  return (GSource*)io;
313
 
}
314
 
 
315
 
unsigned int
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);
319
 
 
320
 
  buf->data = data;
321
 
  buf->len = len;
322
 
  buf->off = 0;
323
 
  io->lastid++;
324
 
  buf->id = io->lastid;
325
 
 
326
 
  if(NULL != io->outbufs)
327
 
    io->outbufs = g_slist_append(io->outbufs, buf);
328
 
  else {
329
 
    io->outbufs = g_slist_append(io->outbufs, buf);
330
 
    g_source_add_poll(source, &io->outfd);
331
 
  }
332
 
 
333
 
  return io->lastid;
334
 
}