Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

gtask-connection.c

Go to the documentation of this file.
00001 #include <sys/types.h>
00002 #include <sys/socket.h>
00003 #include <sys/un.h>
00004 
00005 #include <unistd.h>
00006 #include <fcntl.h>
00007 
00008 #include <gtask/gtask-connection.h>
00009 
00010 #include "gtask-internals.h"
00011 
00014 /* @{ */
00015 
00016 enum {
00017     PROP_0,
00018     PROP_NAME,
00019     PROP_ROLE,
00020     PROP_STREAM_PARSER,
00021     PROP_EVENT_PARSER
00022 };
00023 
00024 static gpointer parent_class;
00025 
00026 static gboolean
00027 gtask_connection_write( GTaskConnection *conn, char *buff );
00028 
00029 static void
00030 gtask_connection_class_init( GTaskConnectionClass *klass );
00031 
00032 static void
00033 gtask_connection_init( GTaskConnection *connection, gpointer g_class );
00034 
00035 static void
00036 gtask_connection_finalize( GObject *obj );
00037 
00038 static gboolean
00039 gtask_connection_init_xml_buffers( GTaskConnection *conn );
00040 
00041 static gboolean
00042 gtask_connection_init_gio_channels( GTaskConnection *conn );
00043 
00044 static void
00045 gtask_connection_set_property( GObject *object,
00046                                guint param_id,
00047                                const GValue *value,
00048                                GParamSpec *pspec  );
00049 
00050 static void
00051 gtask_connection_get_property( GObject *object,
00052                                guint param_id,
00053                                GValue *value,
00054                                GParamSpec *pspec  );
00055 
00056 GType gtask_role_get_type( ) {
00057     static GType type = 0;
00058 
00059     if( type == 0 ) {
00060         static const GEnumValue values[] = {
00061             { GTASK_ROLE_NONE, "GTASK_ROLE_NONE", "none" },
00062             { GTASK_ROLE_NONE, "GTASK_ROLE_PROXY", "proxy" },
00063             { GTASK_ROLE_NONE, "GTASK_ROLE_REPORTER", "reporter" },
00064             { GTASK_ROLE_NONE, "GTASK_ROLE_PROVIDER", "provider" },
00065             { 0, NULL, NULL }
00066         };
00067 
00068         type = g_enum_register_static( "GTaskRole", values );
00069     }
00070 
00071     return type;
00072 }
00073 
00083 GType gtask_connection_get_type( void ) {
00084     static GType type = 0;
00085 
00086     if( type == 0 ) {
00087         static const GTypeInfo info = {
00088             sizeof( GTaskConnectionClass ),
00089             NULL,   /* base init */
00090             NULL,   /* base_finalize */
00091             (GClassInitFunc) gtask_connection_class_init,   /* class_init */
00092             NULL,   /* class_finalize */
00093             NULL,   /* class_data */
00094             sizeof( GTaskConnection ),
00095             0,      /* n_preallocs */
00096             (GInstanceInitFunc) gtask_connection_init
00097         };
00098 
00099         type = g_type_register_static( G_TYPE_OBJECT,
00100                                        "GTaskConnection",
00101                                        &info,
00102                                        0 );
00103     }
00104 
00105     return type;
00106 }
00107 
00108 static void
00109 gtask_connection_class_init( GTaskConnectionClass *klass ) {
00110     GObjectClass *gobject_class = G_OBJECT_CLASS( klass );
00111 
00112     parent_class = g_type_class_peek_parent( klass );
00113 
00114     gobject_class->finalize = gtask_connection_finalize;
00115     gobject_class->set_property = gtask_connection_set_property;
00116     gobject_class->get_property = gtask_connection_get_property;
00117 
00118     klass->connected_signal_id = g_signal_newv( "connected",
00119                                                 G_TYPE_FROM_CLASS( klass ),
00120                                                 G_SIGNAL_RUN_LAST |
00121                                                   G_SIGNAL_NO_RECURSE |
00122                                                   G_SIGNAL_NO_HOOKS,
00123                                                 NULL,
00124                                                 NULL,
00125                                                 NULL,
00126                                                 g_cclosure_marshal_VOID__VOID,
00127                                                 G_TYPE_NONE,
00128                                                 0,
00129                                                 NULL );
00130 
00131     klass->disconnected_signal_id = g_signal_newv( "disconnected",
00132                                                 G_TYPE_FROM_CLASS( klass ),
00133                                                 G_SIGNAL_RUN_LAST |
00134                                                   G_SIGNAL_NO_RECURSE |
00135                                                   G_SIGNAL_NO_HOOKS,
00136                                                 NULL,
00137                                                 NULL,
00138                                                 NULL,
00139                                                 g_cclosure_marshal_VOID__VOID,
00140                                                 G_TYPE_NONE,
00141                                                 0,
00142                                                 NULL );
00143 
00144     g_object_class_install_property( gobject_class,
00145                                      PROP_NAME,
00146                                      g_param_spec_string( "name",
00147                                                           "Name",
00148                                                           "The name of the connection.",
00149                                                           "-unamed-",
00150                                                           G_PARAM_READWRITE ) );
00151 
00152     g_object_class_install_property( gobject_class,
00153                                      PROP_ROLE,
00154                                      g_param_spec_enum( "role",
00155                                                         "Role",
00156                                                         "The GTaskRole of the connection. This item should be set before a connection is connected.",
00157                                                         GTASK_ROLE_TYPE,
00158                                                         GTASK_ROLE_NONE,
00159                                                         G_PARAM_READWRITE ) );
00160 }
00161 
00162 static void
00163 gtask_connection_set_property( GObject *object,
00164                                guint param_id,
00165                                const GValue *value,
00166                                GParamSpec *pspec  )
00167 {
00168     GTaskConnection *conn = GTASK_CONNECTION( object );
00169 
00170     switch( param_id ) {
00171         case PROP_NAME:
00172             gtask_connection_set_name( conn, g_value_get_string( value ) );
00173             break;
00174         case PROP_ROLE:
00175             gtask_connection_set_role( conn, g_value_get_enum( value ) );
00176             break;
00177         default:
00178             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, param_id, pspec );
00179     }
00180 }
00181 
00182 static void
00183 gtask_connection_get_property( GObject *object,
00184                                guint param_id,
00185                                GValue *value,
00186                                GParamSpec *pspec  )
00187 {
00188     GTaskConnection *conn = GTASK_CONNECTION( object );
00189 
00190     switch( param_id ) {
00191         case PROP_NAME:
00192             g_value_set_string( value, gtask_connection_get_name( conn ) );
00193             break;
00194         case PROP_ROLE:
00195             g_value_set_enum( value, gtask_connection_get_role( conn ) );
00196             break;
00197         default:
00198             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, param_id, pspec );
00199     }
00200 }
00201 
00214 static gboolean
00215 gtask_connection_write( GTaskConnection *conn, char *buff ) {
00216     int fd = gtask_connection_get_output_fd( conn );
00217 
00218     int len = strlen( buff );
00219 
00220     while( len ) {
00221         int ret = write( fd, buff, len );
00222 
00223         if( ret < 1 )
00224             return FALSE;
00225         
00226         len -= ret;
00227     }
00228 
00229     return TRUE;
00230 }
00231 
00237 static void
00238 gtask_connection_init( GTaskConnection *connection, gpointer g_class ) {
00239     GTaskConnectionPrivate *private;
00240 
00241     private = g_new0( GTaskConnectionPrivate, 1 );
00242 
00243     private->inp_fd = -1;
00244     private->out_fd = -1;
00245     private->name = g_string_new( "-unamed-" );
00246 
00247     private->role = GTASK_ROLE_NONE;
00248     private->parser = gtask_stream_parser_new( );
00249     private->dispatcher = gtask_event_dispatcher_new_with_parser( private->parser );
00250 
00251     private->conn_method = GTASK_CONNECTION_METHOD_UNKNOWN;
00252     private->socket_uri = NULL;
00253 
00254     private->auto_reconnect = TRUE;
00255     private->auto_parse = TRUE;
00256 
00257     connection->private = private;
00258 }
00259 
00267 GTaskConnection *
00268 gtask_connection_new( ) {
00269     return g_object_new( GTASK_CONNECTION_TYPE, NULL );
00270 }
00271 
00272 GTaskConnection *
00273 gtask_connection_new_with_properties( const gchar *name, GTaskRole role ) {
00274     GTaskConnection *conn = gtask_connection_new( );
00275 
00276     if( name )
00277         gtask_connection_set_name( conn, name );
00278 
00279     gtask_connection_set_role( conn, role );
00280 
00281     return conn;
00282 }
00283 
00294 gchar *
00295 gtask_connection_default_server_bind_path( ) {
00296     return g_strdup_printf( "%s/.gtaskd/server/socket", g_get_home_dir( ) );
00297 }
00298 
00309 gboolean
00310 gtask_connection_connect_domain_socket_default( GTaskConnection *conn ) {
00311     char     *location;
00312     gboolean  ret;
00313 
00314     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), FALSE );
00315     g_return_val_if_fail( !gtask_connection_is_connected( conn ), FALSE );
00316 
00317     location = gtask_connection_default_server_bind_path( );
00318 
00319     ret = gtask_connection_connect_domain_socket( conn, location );
00320 
00321     g_free( location );
00322 
00323     return ret;
00324 }
00325 
00337 gboolean
00338 gtask_connection_connect_domain_socket( GTaskConnection *conn,
00339                                         const char *file )
00340 {
00341     GTaskConnectionPrivate *private;
00342     struct sockaddr_un      sock_un;
00343     int                     fd;
00344 
00345     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), FALSE );
00346     g_return_val_if_fail( !gtask_connection_is_connected( conn ), FALSE );
00347 
00348     private = conn->private;
00349 
00350     fd = socket( AF_LOCAL, SOCK_STREAM, 0 );
00351 
00353     if( fd < 0 ) {
00354         g_warning( "Error creating socket" );
00355         return FALSE;
00356     }
00357 
00358     bzero( &sock_un, sizeof( sock_un ) );
00359     sock_un.sun_family = AF_LOCAL;
00360     strncpy( sock_un.sun_path, file, sizeof( sock_un.sun_path ) - 1 );
00361 
00362     if( connect( fd, (struct sockaddr *) &sock_un, sizeof( sock_un ) ) < 0 ) {
00363         g_warning( "Error on connect" );
00364         close( fd );
00365         return FALSE;
00366     }
00367 
00368     private->conn_method = GTASK_CONNECTION_METHOD_SOCKET;
00369     
00370     g_free( private->socket_uri );
00371     private->socket_uri = g_strdup( file );
00372 
00373     if( !gtask_connection_connect_fd( conn, fd, fd ) ) {
00374         close( fd );
00375         return FALSE;
00376     }
00377 
00378     return TRUE;
00379 }
00380 
00381 gboolean
00382 gtask_connection_connect_loopback( GTaskConnection *conn ) {
00383     int      fd[2];
00384 
00385     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), FALSE );
00386     g_return_val_if_fail( !gtask_connection_is_connected( conn ), FALSE );
00387 
00388     if( pipe( fd ) < 0 ) {
00389         g_warning( "error creating pipe" );
00390 
00391         return FALSE;
00392     }
00393 
00394     conn->private->conn_method = GTASK_CONNECTION_METHOD_LOOPBACK;
00395 
00397     shutdown( fd[0], 0 );
00398     shutdown( fd[1], 1 );
00399 
00400     if( !gtask_connection_connect_fd( conn, fd[0], fd[1] ) ) {
00401         close( fd[0] );
00402         close( fd[1] );
00403 
00404         return FALSE;
00405     }
00406 
00407     return TRUE;
00408 }
00409 
00419 static gboolean
00420 gtask_connection_init_xml_buffers( GTaskConnection *conn ) {
00421     GTaskConnectionPrivate *private = conn->private;
00422 
00423     g_return_val_if_fail( private->inp_fd >= 0, FALSE );
00424     g_return_val_if_fail( private->out_fd >= 0, FALSE );
00425     g_return_val_if_fail( !private->xml_output, FALSE );
00426 
00427     private->xml_output = xmlOutputBufferCreateFd( private->out_fd,
00428                                                    XML_CHAR_ENCODING_NONE );
00429 
00430     if( !private->xml_output )
00431         return FALSE;
00432 
00433     return TRUE;
00434 }
00435 
00445 static gboolean
00446 gtask_connection_init_gio_channels( GTaskConnection *conn ) {
00447     GTaskConnectionPrivate *private = conn->private;
00448     int                     status;
00449     int                     flags;
00450 
00451     g_return_val_if_fail( private->inp_fd >= 0, FALSE );
00452     g_return_val_if_fail( !private->g_input, FALSE );
00453 
00454     private->g_input = g_io_channel_unix_new( private->inp_fd );
00455 
00456     g_io_channel_set_encoding( private->g_input, NULL, NULL );
00457     g_io_channel_set_buffered( private->g_input, FALSE );
00458 
00459     flags = g_io_channel_get_flags( private->g_input );
00460 
00461     status = g_io_channel_set_flags( private->g_input,
00462                                      flags & G_IO_FLAG_NONBLOCK,
00463                                      NULL );
00464 
00465     if( status != G_IO_STATUS_NORMAL ) {
00466         g_io_channel_unref( private->g_input );
00467         private->g_input = NULL;
00468 
00469         return FALSE;
00470     }
00471 
00472     return TRUE;
00473 }
00474 
00475 /*
00476  * this is called if the input source is disconnected
00477  */
00478 static gboolean
00479 gtask_connection_connection_broken( GIOChannel *source,
00480                                     GIOCondition cond,
00481                                     gpointer data )
00482 {
00483     if( cond == G_IO_HUP ) {
00484         GTaskConnection *conn = GTASK_CONNECTION( data );
00485 
00486         conn->private->g_hup_source_id = 0;
00487 
00491         gtask_connection_close( conn );
00492 
00493         g_warning( "connection to server broken, closing it down" );
00494 
00495         if( conn->private->auto_parse )
00496             gtask_stream_parser_reset_state( conn->private->parser );
00497 
00498         g_signal_emit( conn,
00499                      GTASK_CONNECTION_GET_CLASS( conn )->disconnected_signal_id,
00500                      0,
00501                      NULL );
00502         
00504         g_warning( "we would attempt to reconnect here" );
00505     } else {
00506         g_warning( "gtask_connection_connection_broken called, but the GIOCondition != G_IO_HUP" );
00507     }
00508 
00509     return FALSE;
00510 }
00511 
00523 gboolean
00524 gtask_connection_connect_fd( GTaskConnection *conn, int inp_fd, int out_fd ) {
00525     GTaskConnectionPrivate *private = conn->private;
00526 
00528     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), FALSE );
00529     g_return_val_if_fail( !gtask_connection_is_connected( conn ), FALSE );
00530 
00531     private->inp_fd = inp_fd;
00532     private->out_fd = out_fd;
00533 
00534     if( !gtask_connection_init_xml_buffers( conn ) ) {
00535         private->inp_fd = -1;
00536         private->out_fd = -1;
00537 
00538         return FALSE;
00539     }
00540 
00541     if( !gtask_connection_init_gio_channels( conn ) ) {
00542         xmlOutputBufferClose( private->xml_output );
00543         private->inp_fd = -1;
00544         private->out_fd = -1;
00545         private->xml_output = NULL;
00546 
00547         return FALSE;
00548     }
00549 
00550     if( !gtask_connection_write( conn, "<gtask-stream>" ) ) {
00551         xmlOutputBufferClose( private->xml_output );
00552         private->xml_output = NULL;
00553 
00554         g_io_channel_unref( private->g_input );
00555         private->g_input = NULL;
00556 
00557         private->inp_fd = -1;
00558         private->out_fd = -1;
00559         
00560         return FALSE;
00561     }
00562 
00563     if( private->conn_method == GTASK_CONNECTION_METHOD_UNKNOWN )
00564         private->conn_method = GTASK_CONNECTION_METHOD_FD;
00565 
00566     g_debug( "==> Emitting connected signal" );
00567 
00568     g_signal_emit( conn,
00569                    GTASK_CONNECTION_GET_CLASS( conn )->connected_signal_id,
00570                    0,
00571                    NULL );
00572 
00573     if( private->auto_parse ) {
00574         private->g_in_source_id = g_io_add_watch( private->g_input,
00575                                   G_IO_IN,
00576                                   gtask_event_dispatcher_private_parse_callback,
00577                                   private->dispatcher ); 
00578     }
00579 
00580     /* @todo watch output for disconnects too? */
00581     private->g_hup_source_id = g_io_add_watch( private->g_input,
00582                                              G_IO_HUP,
00583                                              gtask_connection_connection_broken,
00584                                              conn );
00585     return TRUE;
00586 }
00587 
00597 gboolean
00598 gtask_connection_is_connected( GTaskConnection *conn ) {
00599     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), FALSE );
00600 
00601     return ( conn->private->inp_fd >= 0 && conn->private->out_fd >= 0 );
00602 }
00603 
00604 
00612 static void
00613 gtask_connection_finalize( GObject *obj ) {
00614     GTaskConnection *conn = GTASK_CONNECTION( obj );
00615 
00616     gtask_connection_close( conn );
00617 
00618     g_free( conn->private );
00619 
00620     if( G_OBJECT_CLASS( parent_class )->finalize )
00621         G_OBJECT_CLASS( parent_class )->finalize( obj );
00622 }
00623 
00634 gint
00635 gtask_connection_get_input_fd( GTaskConnection *conn ) {
00636     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), -1 );
00637 
00638     return conn->private->inp_fd;
00639 }
00640 
00651 gint
00652 gtask_connection_get_output_fd( GTaskConnection *conn ) {
00653     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), -1 );
00654 
00655     return conn->private->out_fd;
00656 }
00657 
00667 gboolean
00668 gtask_connection_close( GTaskConnection *conn ) {
00669     GTaskConnectionPrivate *private;
00670     gboolean                same;
00671 
00672     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), FALSE );
00673 
00674     private = conn->private;
00675 
00676     same = ( private->inp_fd == private->out_fd );
00677 
00678     if( private->g_hup_source_id ) {
00679         g_source_remove( private->g_hup_source_id );
00680         private->g_hup_source_id = 0;
00681     }
00682 
00683     if( private->g_in_source_id ) {
00684         g_source_remove( private->g_in_source_id );
00685         private->g_in_source_id = 0;
00686     }
00687 
00688     if( private->xml_output ) {
00689         xmlOutputBufferClose( private->xml_output );
00690         private->xml_output = NULL;
00691     }
00692 
00693     if( private->g_input ) {
00694         g_io_channel_unref( private->g_input );
00695         private->g_input = NULL;
00696     }
00697 
00698     if( private->inp_fd > -1 ) {
00699         close( private->inp_fd );
00700 
00701         private->inp_fd = -1;
00702     }
00703 
00704     if( !same && private->out_fd > -1 ) {
00705         close( private->out_fd );
00706 
00707         private->out_fd = -1;
00708     }
00709 
00710     return TRUE;
00711 }
00712 
00725 GIOChannel *
00726 gtask_connection_get_gio_input_channel( GTaskConnection *conn ) {
00727     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), NULL );
00728 
00729     return conn->private->g_input;
00730 }
00731 
00739 xmlOutputBufferPtr
00740 gtask_connection_get_xml_output_buffer( GTaskConnection *conn ) {
00741     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), NULL );
00742 
00743     return conn->private->xml_output;
00744 }
00745 
00746 
00756 const gchar *
00757 gtask_connection_get_name( GTaskConnection *conn ) {
00758     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), "" );
00759 
00760     return conn->private->name->str;
00761 }
00762 
00769 void
00770 gtask_connection_set_name( GTaskConnection *conn, const gchar *name ) {
00771     g_return_if_fail( GTASK_IS_CONNECTION( conn ) );
00772     g_return_if_fail( name != NULL );
00773 
00774     g_string_assign( conn->private->name, name );
00775 
00776     g_object_notify( (GObject *) conn, "name" );
00777 }
00778 
00786 GTaskRole
00787 gtask_connection_get_role( GTaskConnection *conn ) {
00788     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), GTASK_ROLE_NONE );
00789 
00790     return conn->private->role;
00791 }
00792 
00799 void
00800 gtask_connection_set_role( GTaskConnection *conn, GTaskRole role ) {
00801     g_return_if_fail( GTASK_IS_CONNECTION( conn ) );
00802 
00803     conn->private->role = role;
00804 
00805     g_object_notify( (GObject *) conn, "role" );
00806 }
00807 
00819 GTaskStreamParser *
00820 gtask_connection_get_stream_parser( GTaskConnection *conn ) {
00821     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), NULL );
00822 
00823     return conn->private->parser;
00824 }
00825 
00836 GTaskEventDispatcher *
00837 gtask_connection_get_event_dispatcher( GTaskConnection *conn ) {
00838     g_return_val_if_fail( GTASK_IS_CONNECTION( conn ), NULL );
00839 
00840     return conn->private->dispatcher;
00841 }
00842 
00843 /* @} */

Generated on Mon Feb 2 21:26:14 2004 for libgtask by doxygen 1.3.4