~ubuntu-branches/ubuntu/precise/transmission/precise

« back to all changes in this revision

Viewing changes to daemon/proxy.c

  • Committer: Bazaar Package Importer
  • Author(s): Leo Costela
  • Date: 2009-05-17 19:39:51 UTC
  • mto: (1.3.4 upstream) (2.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 36.
  • Revision ID: james.westby@ubuntu.com-20090517193951-k8x15sqoxzf7cuyx
ImportĀ upstreamĀ versionĀ 1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 * $Id: proxy.c 5646 2008-04-19 00:41:32Z charles $
3
 
 *
4
 
 * Copyright (c) 2007 Joshua Elsasser
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/param.h>
27
 
#include <sys/socket.h>
28
 
#include <sys/time.h>
29
 
#include <sys/un.h>
30
 
#include <event.h>
31
 
#include <getopt.h>
32
 
#include <stdarg.h>
33
 
#include <stdlib.h>
34
 
#include <stdio.h>
35
 
#include <string.h>
36
 
#include <unistd.h>
37
 
 
38
 
#include <libtransmission/transmission.h>
39
 
#include <libtransmission/trcompat.h>
40
 
 
41
 
#include "errors.h"
42
 
#include "misc.h"
43
 
 
44
 
static void              usage    ( const char *, ... );
45
 
static enum confpathtype readargs ( int, char **, char **, char ** );
46
 
static int               makesock ( enum confpathtype, const char *, const char * );
47
 
static void              inread   ( struct bufferevent *, void * );
48
 
static void              noop     ( struct bufferevent *, void * );
49
 
static void              inerr    ( struct bufferevent *, short, void * );
50
 
static void              wtf      ( struct bufferevent *, void * );
51
 
static void              outerr   ( struct bufferevent *, short, void * );
52
 
static void              sockread ( struct bufferevent *, void * );
53
 
static void              sockwrite( struct bufferevent *, void * );
54
 
static void              sockerr  ( struct bufferevent *, short, void * );
55
 
 
56
 
static struct bufferevent * gl_in   = NULL;
57
 
static struct bufferevent * gl_out  = NULL;
58
 
static struct bufferevent * gl_sock = NULL;
59
 
 
60
 
int
61
 
main( int argc, char ** argv )
62
 
{
63
 
    struct event_base  * base;
64
 
    enum confpathtype    type;
65
 
    char               * configdir;
66
 
    char               * sockpath;
67
 
    int                  sockfd;
68
 
 
69
 
    setmyname( argv[0] );
70
 
    type = readargs( argc, argv, &configdir, &sockpath );
71
 
    if( configdir == NULL )
72
 
        configdir = strdup( tr_getDefaultConfigDir( ) );
73
 
 
74
 
    base = event_init();
75
 
 
76
 
    sockfd = makesock( type, configdir, sockpath );
77
 
    if( 0 > sockfd )
78
 
    {
79
 
        return EXIT_FAILURE;
80
 
    }
81
 
 
82
 
    gl_in = bufferevent_new( STDIN_FILENO, inread, noop, inerr, NULL );
83
 
    if( NULL == gl_in )
84
 
    {
85
 
        errnomsg( "failed to set up event buffer for stdin" );
86
 
        return EXIT_FAILURE;
87
 
    }
88
 
    /* XXX bufferevent_base_set( base, gl_in ); */
89
 
    bufferevent_enable( gl_in, EV_READ );
90
 
    bufferevent_disable( gl_in, EV_WRITE );
91
 
 
92
 
    gl_out  = bufferevent_new( STDOUT_FILENO, wtf, noop, outerr,  NULL );
93
 
    if( NULL == gl_in )
94
 
    {
95
 
        errnomsg( "failed to set up event buffer for stdin" );
96
 
        return EXIT_FAILURE;
97
 
    }
98
 
    /* XXX bufferevent_base_set( base, gl_out ); */
99
 
    bufferevent_disable( gl_out, EV_READ );
100
 
    bufferevent_enable( gl_out, EV_WRITE );
101
 
 
102
 
    gl_sock = bufferevent_new( sockfd, sockread, sockwrite, sockerr, NULL );
103
 
    if( NULL == gl_in )
104
 
    {
105
 
        errnomsg( "failed to set up event buffer for stdin" );
106
 
        return EXIT_FAILURE;
107
 
    }
108
 
    /* XXX bufferevent_base_set( base, gl_sock ); */
109
 
    bufferevent_enable( gl_sock, EV_READ );
110
 
    bufferevent_enable( gl_sock, EV_WRITE );
111
 
 
112
 
    event_dispatch();
113
 
    /* XXX event_base_dispatch( base ); */
114
 
 
115
 
    return EXIT_FAILURE;
116
 
}
117
 
 
118
 
void
119
 
usage( const char * msg, ... )
120
 
{
121
 
    va_list ap;
122
 
 
123
 
    if( NULL != msg )
124
 
    {
125
 
        printf( "%s: ", getmyname() );
126
 
        va_start( ap, msg );
127
 
        vprintf( msg, ap );
128
 
        va_end( ap );
129
 
        printf( "\n" );
130
 
    }
131
 
 
132
 
    printf(
133
 
  "usage: %s [options] [files]...\n"
134
 
  "\n"
135
 
  "Transmission %s http://www.transmissionbt.com/\n"
136
 
  "A fast and easy BitTorrent client\n"
137
 
  "\n"
138
 
  "  -h --help                 Display this message and exit\n"
139
 
  "  -g --config-dir <path>    Where to look for configuration files\n"
140
 
  "  -t --type daemon          Use the daemon frontend, transmission-daemon\n"
141
 
  "  -t --type gtk             Use the GTK+ frontend, transmission\n"
142
 
  "  -t --type mac             Use the Mac OS X frontend\n",
143
 
            getmyname(), LONG_VERSION_STRING );
144
 
    exit( EXIT_SUCCESS );
145
 
}
146
 
 
147
 
enum confpathtype
148
 
readargs( int argc, char ** argv, char ** configdir, char ** sockpath )
149
 
{
150
 
    char optstr[] = "g:ht:";
151
 
    struct option longopts[] =
152
 
    {
153
 
        { "config-dir",         required_argument, NULL, 'g' },
154
 
        { "help",               no_argument,       NULL, 'h' },
155
 
        { "type",               required_argument, NULL, 't' },
156
 
        { NULL, 0, NULL, 0 }
157
 
    };
158
 
    enum confpathtype type;
159
 
    int opt;
160
 
 
161
 
    type       = CONF_PATH_TYPE_DAEMON;
162
 
    *configdir = NULL;
163
 
    *sockpath  = NULL;
164
 
 
165
 
    while( 0 <= ( opt = getopt_long( argc, argv, optstr, longopts, NULL ) ) )
166
 
    {
167
 
        switch( opt )
168
 
        {
169
 
            case 'g':
170
 
                *configdir = strdup( optarg );
171
 
                break;
172
 
 
173
 
            case 't':
174
 
                if( 0 == strcasecmp( "daemon", optarg ) )
175
 
                {
176
 
                    type      = CONF_PATH_TYPE_DAEMON;
177
 
                    *sockpath = NULL;
178
 
                }
179
 
                else if( 0 == strcasecmp( "gtk", optarg ) )
180
 
                {
181
 
                    type      = CONF_PATH_TYPE_GTK;
182
 
                    *sockpath = NULL;
183
 
                }
184
 
                else if( 0 == strcasecmp( "mac", optarg ) ||
185
 
                         0 == strcasecmp( "osx", optarg ) ||
186
 
                         0 == strcasecmp( "macos", optarg ) ||
187
 
                         0 == strcasecmp( "macosx", optarg ) )
188
 
                {
189
 
                    type      = CONF_PATH_TYPE_OSX;
190
 
                    *sockpath = NULL;
191
 
                }
192
 
                else
193
 
                {
194
 
                    *sockpath = optarg;
195
 
                }
196
 
                break;
197
 
            default:
198
 
                usage( NULL );
199
 
                break;
200
 
        }
201
 
    }
202
 
 
203
 
    return type;
204
 
}
205
 
 
206
 
int
207
 
makesock( enum confpathtype type,
208
 
          const char * configdir,
209
 
          const char * sockpath )
210
 
{
211
 
    struct sockaddr_un sa;
212
 
    int                fd;
213
 
 
214
 
    memset( &sa, 0, sizeof sa );
215
 
    sa.sun_family = AF_LOCAL;
216
 
    if( !sockpath )
217
 
    {
218
 
        confpath( sa.sun_path, sizeof sa.sun_path, configdir, CONF_FILE_SOCKET, type );
219
 
    }
220
 
    else
221
 
    {
222
 
        strlcpy( sa.sun_path, sockpath, sizeof sa.sun_path );
223
 
    }
224
 
 
225
 
    fd = socket( AF_UNIX, SOCK_STREAM, 0 );
226
 
    if( 0 > fd )
227
 
    {
228
 
        errnomsg( "failed to create socket" );
229
 
        return -1;
230
 
    }
231
 
 
232
 
    if( 0 > connect( fd, ( struct sockaddr * )&sa, SUN_LEN( &sa ) ) )
233
 
    {
234
 
        errnomsg( "failed to connect to socket file: %s", sa.sun_path );
235
 
        close( fd );
236
 
        return -1;
237
 
    }
238
 
 
239
 
    return fd;
240
 
}
241
 
 
242
 
void
243
 
inread( struct bufferevent * ev UNUSED, void * arg UNUSED )
244
 
{
245
 
    bufferevent_write_buffer( gl_sock, EVBUFFER_INPUT( gl_in ) );
246
 
}
247
 
 
248
 
void
249
 
noop( struct bufferevent * ev UNUSED, void * arg UNUSED )
250
 
{
251
 
}
252
 
 
253
 
void
254
 
inerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
255
 
{
256
 
    if( EVBUFFER_EOF & what )
257
 
    {
258
 
        bufferevent_free( gl_in );
259
 
        gl_in = NULL;
260
 
        sockwrite( NULL, NULL );
261
 
        return;
262
 
    }
263
 
 
264
 
    if( EVBUFFER_TIMEOUT & what )
265
 
    {
266
 
        errmsg( "timed out reading from stdin" );
267
 
    }
268
 
    else if( EVBUFFER_READ & what )
269
 
    {
270
 
        errmsg( "read error on stdin" );
271
 
    }
272
 
    else if( EVBUFFER_ERROR & what )
273
 
    {
274
 
        errmsg( "error on stdin" );
275
 
    }
276
 
    else
277
 
    {
278
 
        errmsg( "unknown error on stdin: 0x%x", what );
279
 
    }
280
 
 
281
 
    exit( EXIT_FAILURE );
282
 
}
283
 
 
284
 
void
285
 
wtf( struct bufferevent * ev, void * arg UNUSED )
286
 
{
287
 
    /* this shouldn't happen, but let's drain the buffer anyway */
288
 
    evbuffer_drain( EVBUFFER_INPUT( ev ),
289
 
                    EVBUFFER_LENGTH( EVBUFFER_INPUT( ev ) ) );
290
 
}
291
 
 
292
 
void
293
 
outerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
294
 
{
295
 
    if( EVBUFFER_TIMEOUT & what )
296
 
    {
297
 
        errmsg( "timed out writing to stdout" );
298
 
    }
299
 
    else if( EVBUFFER_WRITE & what )
300
 
    {
301
 
        errmsg( "write error on stdout" );
302
 
    }
303
 
    else if( EVBUFFER_ERROR & what )
304
 
    {
305
 
        errmsg( "error on client stdout" );
306
 
    }
307
 
    else
308
 
    {
309
 
        errmsg( "unknown error on stdout connection: 0x%x", what );
310
 
    }
311
 
 
312
 
    exit( EXIT_FAILURE );
313
 
}
314
 
 
315
 
void
316
 
sockread( struct bufferevent * ev UNUSED, void * arg UNUSED )
317
 
{
318
 
    bufferevent_write_buffer( gl_out, EVBUFFER_INPUT( gl_sock ) );
319
 
}
320
 
 
321
 
void
322
 
sockwrite( struct bufferevent * ev UNUSED, void * arg UNUSED )
323
 
{
324
 
    if( NULL == gl_in && 0 == EVBUFFER_LENGTH( EVBUFFER_OUTPUT( gl_sock ) ) )
325
 
    {
326
 
        exit( EXIT_SUCCESS );
327
 
    }
328
 
}
329
 
 
330
 
void
331
 
sockerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
332
 
{
333
 
    if( EVBUFFER_EOF & what )
334
 
    {
335
 
        errmsg( "server closed connection" );
336
 
    }
337
 
    else if( EVBUFFER_TIMEOUT & what )
338
 
    {
339
 
        errmsg( "server connection timed out" );
340
 
    }
341
 
    else if( EVBUFFER_READ & what )
342
 
    {
343
 
        errmsg( "read error on server connection" );
344
 
    }
345
 
    else if( EVBUFFER_WRITE & what )
346
 
    {
347
 
        errmsg( "write error on server connection" );
348
 
    }
349
 
    else if( EVBUFFER_ERROR & what )
350
 
    {
351
 
        errmsg( "error on server connection" );
352
 
    }
353
 
    else
354
 
    {
355
 
        errmsg( "unknown error on server connection: 0x%x", what );
356
 
    }
357
 
 
358
 
    exit( EXIT_FAILURE );
359
 
}