source: branches/daemon/daemon/proxy.c @ 1630

Last change on this file since 1630 was 1630, checked in by joshe, 15 years ago

Whoops, set keywords.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.2 KB
Line 
1/******************************************************************************
2 * $Id: proxy.c 1630 2007-04-01 03:46:09Z joshe $
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 "errors.h"
39#include "misc.h"
40#include "transmission.h"
41
42#define TIMEOUT                 ( 60 )
43
44static void                 usage    ( const char *, ... );
45static enum confpathtype    readargs ( int, char ** );
46static int                  makesock ( enum confpathtype );
47static struct bufferevent * setupev  ( struct event_base *, int,
48                                       void ( * )( struct bufferevent *, short,
49                                                   void * ), void * );
50static void                 noop     ( struct bufferevent *, void * );
51static void                 relay    ( struct bufferevent *, void * );
52static void                 outerr   ( struct bufferevent *, short, void * );
53static void                 inerr    ( struct bufferevent *, short, void * );
54static void                 sockerr  ( struct bufferevent *, short, void * );
55
56int
57main( int argc, char ** argv )
58{
59    struct event_base  * base;
60    enum confpathtype    type;
61    int                  sockfd;
62    struct bufferevent * outev, * inev, * sockev;
63
64    setmyname( argv[0] );
65    type = readargs( argc, argv );
66    base = event_init();
67
68    sockfd = makesock( type );
69    if( 0 > sockfd )
70    {
71        return EXIT_FAILURE;
72    }
73
74    outev  = setupev( base, STDOUT_FILENO, outerr,  NULL );
75    sockev = setupev( base, sockfd,        sockerr, outev );
76    inev   = setupev( base, STDIN_FILENO,  inerr,   sockev );
77
78    if( NULL == outev || NULL == inev || NULL == sockev )
79    {
80        return EXIT_FAILURE;
81    }
82
83    bufferevent_disable( outev,  EV_READ );
84    bufferevent_enable(  outev,  EV_WRITE );
85    bufferevent_enable(  inev,   EV_READ );
86    bufferevent_disable( inev,   EV_WRITE );
87    bufferevent_enable(  sockev, EV_READ );
88    bufferevent_enable(  sockev, EV_WRITE );
89
90    event_base_dispatch( base );
91
92    return EXIT_FAILURE;
93}
94
95void
96usage( const char * msg, ... )
97{
98    va_list ap;
99
100    if( NULL != msg )
101    {
102        printf( "%s: ", getmyname() );
103        va_start( ap, msg );
104        vprintf( msg, ap );
105        va_end( ap );
106        printf( "\n" );
107    }
108
109    printf(
110  "usage: %s [options] [files]...\n"
111  "\n"
112  "Transmission %s (r%d) http://transmission.m0k.org/\n"
113  "A free, lightweight BitTorrent client with a simple, intuitive interface.\n"
114  "\n"
115  "  -h --help                 Display this message and exit\n"
116  "  -t --type daemon          Use the daemon frontend, transmission-daemon\n"
117  "  -t --type gtk             Use the GTK+ frontend, transmission-gtk\n",
118            getmyname(), VERSION_STRING, VERSION_REVISION );
119    exit( EXIT_SUCCESS );
120}
121
122enum confpathtype
123readargs( int argc, char ** argv )
124{
125    char optstr[] = "ht:";
126    struct option longopts[] =
127    {
128        { "help",               no_argument,       NULL, 'h' },
129        { "type",               required_argument, NULL, 't' },
130        { NULL, 0, NULL, 0 }
131    };
132    enum confpathtype type;
133    int opt;
134
135    type = CONF_PATH_TYPE_DAEMON;
136
137    while( 0 <= ( opt = getopt_long( argc, argv, optstr, longopts, NULL ) ) )
138    {
139        switch( opt )
140        {
141            case 't':
142                if( 0 == strcasecmp( "daemon", optarg ) )
143                {
144                    type = CONF_PATH_TYPE_DAEMON;
145                }
146                else if( 0 == strcasecmp( "gtk", optarg ) )
147                {
148                    type = CONF_PATH_TYPE_GTK;
149                }
150                else
151                {
152                    usage( "invalid type: %s", optarg );
153                }
154                break;
155            default:
156                usage( NULL );
157                break;
158        }
159    }
160
161    return type;
162}
163
164int
165makesock( enum confpathtype type )
166{
167    struct sockaddr_un sun;
168    int                fd;
169
170    bzero( &sun, sizeof sun );
171    sun.sun_family = AF_LOCAL;
172    confpath( sun.sun_path, sizeof sun.sun_path, CONF_FILE_SOCKET, type );
173
174    fd = socket( AF_UNIX, SOCK_STREAM, 0 );
175    if( 0 > fd )
176    {
177        errnomsg( "failed to create socket" );
178        return -1;
179    }
180
181    if( 0 > connect( fd, ( struct sockaddr * )&sun, SUN_LEN( &sun ) ) )
182    {
183        errnomsg( "failed to connect to socket file: %s", sun.sun_path );
184        close( fd );
185        return -1;
186    }
187
188    return fd;
189}
190
191struct bufferevent *
192setupev( struct event_base * base, int fd,
193         void ( * efunc )( struct bufferevent *, short, void * ), void * arg )
194{
195    struct bufferevent * ev;
196
197    ev = bufferevent_new( fd, relay, noop, efunc, arg );
198    if( NULL == ev )
199    {
200        mallocmsg( -1 );
201        return NULL;
202    }
203
204    bufferevent_base_set( base, ev );
205    bufferevent_settimeout( ev, TIMEOUT, TIMEOUT );
206
207    return ev;
208}
209
210void
211noop( struct bufferevent * ev UNUSED, void * arg UNUSED )
212{
213    /* libevent prior to 1.2 couldn't handle a NULL write callback */
214}
215
216void
217relay( struct bufferevent * in, void * arg )
218{
219    struct bufferevent * out = arg;
220
221    if( NULL == arg )
222    {
223        /* this shouldn't happen, but let's drain the buffer anyway */
224        evbuffer_drain( EVBUFFER_INPUT( in ),
225                        EVBUFFER_LENGTH( EVBUFFER_INPUT( in ) ) );
226    }
227    else
228    {
229        bufferevent_write_buffer( out, EVBUFFER_INPUT( in ) );
230    }
231}
232
233void
234outerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
235{
236    if( EVBUFFER_TIMEOUT & what )
237    {
238        errmsg( "timed out writing to stdout" );
239    }
240    else if( EVBUFFER_WRITE & what )
241    {
242        errmsg( "write error on stdout" );
243    }
244    else if( EVBUFFER_ERROR & what )
245    {
246        errmsg( "error on client stdout" );
247    }
248    else
249    {
250        errmsg( "unknown error on stdout connection: 0x%x", what );
251    }
252
253    exit( EXIT_FAILURE );
254}
255
256void
257inerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
258{
259    if( EVBUFFER_EOF & what )
260    {
261        exit( EXIT_SUCCESS );
262    }
263    else if( EVBUFFER_TIMEOUT & what )
264    {
265        errmsg( "timed out reading from stdin" );
266    }
267    else if( EVBUFFER_READ & what )
268    {
269        errmsg( "read error on stdin" );
270    }
271    else if( EVBUFFER_ERROR & what )
272    {
273        errmsg( "error on stdin" );
274    }
275    else
276    {
277        errmsg( "unknown error on stdin: 0x%x", what );
278    }
279
280    exit( EXIT_FAILURE );
281}
282
283void
284sockerr( struct bufferevent * ev UNUSED, short what, void * arg UNUSED )
285{
286    if( EVBUFFER_EOF & what )
287    {
288        errmsg( "server closed connection" );
289    }
290    else if( EVBUFFER_TIMEOUT & what )
291    {
292        errmsg( "server connection timed out" );
293    }
294    else if( EVBUFFER_READ & what )
295    {
296        errmsg( "read error on server connection" );
297    }
298    else if( EVBUFFER_WRITE & what )
299    {
300        errmsg( "write error on server connection" );
301    }
302    else if( EVBUFFER_ERROR & what )
303    {
304        errmsg( "error on server connection" );
305    }
306    else
307    {
308        errmsg( "unknown error on server connection: 0x%x", what );
309    }
310
311    exit( EXIT_FAILURE );
312}
Note: See TracBrowser for help on using the repository browser.