1
/******************************************************************************
2
* $Id: proxy.c 5646 2008-04-19 00:41:32Z charles $
4
* Copyright (c) 2007 Joshua Elsasser
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/param.h>
27
#include <sys/socket.h>
38
#include <libtransmission/transmission.h>
39
#include <libtransmission/trcompat.h>
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 * );
56
static struct bufferevent * gl_in = NULL;
57
static struct bufferevent * gl_out = NULL;
58
static struct bufferevent * gl_sock = NULL;
61
main( int argc, char ** argv )
63
struct event_base * base;
64
enum confpathtype type;
70
type = readargs( argc, argv, &configdir, &sockpath );
71
if( configdir == NULL )
72
configdir = strdup( tr_getDefaultConfigDir( ) );
76
sockfd = makesock( type, configdir, sockpath );
82
gl_in = bufferevent_new( STDIN_FILENO, inread, noop, inerr, NULL );
85
errnomsg( "failed to set up event buffer for stdin" );
88
/* XXX bufferevent_base_set( base, gl_in ); */
89
bufferevent_enable( gl_in, EV_READ );
90
bufferevent_disable( gl_in, EV_WRITE );
92
gl_out = bufferevent_new( STDOUT_FILENO, wtf, noop, outerr, NULL );
95
errnomsg( "failed to set up event buffer for stdin" );
98
/* XXX bufferevent_base_set( base, gl_out ); */
99
bufferevent_disable( gl_out, EV_READ );
100
bufferevent_enable( gl_out, EV_WRITE );
102
gl_sock = bufferevent_new( sockfd, sockread, sockwrite, sockerr, NULL );
105
errnomsg( "failed to set up event buffer for stdin" );
108
/* XXX bufferevent_base_set( base, gl_sock ); */
109
bufferevent_enable( gl_sock, EV_READ );
110
bufferevent_enable( gl_sock, EV_WRITE );
113
/* XXX event_base_dispatch( base ); */
119
usage( const char * msg, ... )
125
printf( "%s: ", getmyname() );
133
"usage: %s [options] [files]...\n"
135
"Transmission %s http://www.transmissionbt.com/\n"
136
"A fast and easy BitTorrent client\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 );
148
readargs( int argc, char ** argv, char ** configdir, char ** sockpath )
150
char optstr[] = "g:ht:";
151
struct option longopts[] =
153
{ "config-dir", required_argument, NULL, 'g' },
154
{ "help", no_argument, NULL, 'h' },
155
{ "type", required_argument, NULL, 't' },
158
enum confpathtype type;
161
type = CONF_PATH_TYPE_DAEMON;
165
while( 0 <= ( opt = getopt_long( argc, argv, optstr, longopts, NULL ) ) )
170
*configdir = strdup( optarg );
174
if( 0 == strcasecmp( "daemon", optarg ) )
176
type = CONF_PATH_TYPE_DAEMON;
179
else if( 0 == strcasecmp( "gtk", optarg ) )
181
type = CONF_PATH_TYPE_GTK;
184
else if( 0 == strcasecmp( "mac", optarg ) ||
185
0 == strcasecmp( "osx", optarg ) ||
186
0 == strcasecmp( "macos", optarg ) ||
187
0 == strcasecmp( "macosx", optarg ) )
189
type = CONF_PATH_TYPE_OSX;
207
makesock( enum confpathtype type,
208
const char * configdir,
209
const char * sockpath )
211
struct sockaddr_un sa;
214
memset( &sa, 0, sizeof sa );
215
sa.sun_family = AF_LOCAL;
218
confpath( sa.sun_path, sizeof sa.sun_path, configdir, CONF_FILE_SOCKET, type );
222
strlcpy( sa.sun_path, sockpath, sizeof sa.sun_path );
225
fd = socket( AF_UNIX, SOCK_STREAM, 0 );
228
errnomsg( "failed to create socket" );
232
if( 0 > connect( fd, ( struct sockaddr * )&sa, SUN_LEN( &sa ) ) )
234
errnomsg( "failed to connect to socket file: %s", sa.sun_path );
243
inread( struct bufferevent * ev UNUSED, void * arg UNUSED )
245
bufferevent_write_buffer( gl_sock, EVBUFFER_INPUT( gl_in ) );
249
noop( struct bufferevent * ev UNUSED, void * arg UNUSED )
254
inerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
256
if( EVBUFFER_EOF & what )
258
bufferevent_free( gl_in );
260
sockwrite( NULL, NULL );
264
if( EVBUFFER_TIMEOUT & what )
266
errmsg( "timed out reading from stdin" );
268
else if( EVBUFFER_READ & what )
270
errmsg( "read error on stdin" );
272
else if( EVBUFFER_ERROR & what )
274
errmsg( "error on stdin" );
278
errmsg( "unknown error on stdin: 0x%x", what );
281
exit( EXIT_FAILURE );
285
wtf( struct bufferevent * ev, void * arg UNUSED )
287
/* this shouldn't happen, but let's drain the buffer anyway */
288
evbuffer_drain( EVBUFFER_INPUT( ev ),
289
EVBUFFER_LENGTH( EVBUFFER_INPUT( ev ) ) );
293
outerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
295
if( EVBUFFER_TIMEOUT & what )
297
errmsg( "timed out writing to stdout" );
299
else if( EVBUFFER_WRITE & what )
301
errmsg( "write error on stdout" );
303
else if( EVBUFFER_ERROR & what )
305
errmsg( "error on client stdout" );
309
errmsg( "unknown error on stdout connection: 0x%x", what );
312
exit( EXIT_FAILURE );
316
sockread( struct bufferevent * ev UNUSED, void * arg UNUSED )
318
bufferevent_write_buffer( gl_out, EVBUFFER_INPUT( gl_sock ) );
322
sockwrite( struct bufferevent * ev UNUSED, void * arg UNUSED )
324
if( NULL == gl_in && 0 == EVBUFFER_LENGTH( EVBUFFER_OUTPUT( gl_sock ) ) )
326
exit( EXIT_SUCCESS );
331
sockerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
333
if( EVBUFFER_EOF & what )
335
errmsg( "server closed connection" );
337
else if( EVBUFFER_TIMEOUT & what )
339
errmsg( "server connection timed out" );
341
else if( EVBUFFER_READ & what )
343
errmsg( "read error on server connection" );
345
else if( EVBUFFER_WRITE & what )
347
errmsg( "write error on server connection" );
349
else if( EVBUFFER_ERROR & what )
351
errmsg( "error on server connection" );
355
errmsg( "unknown error on server connection: 0x%x", what );
358
exit( EXIT_FAILURE );