/** * Returns the readable end of a pipe that becomes readable once termination * of the object is requested (vlc_object_kill()). * This can be used to wake-up out of a select() or poll() event loop, such * typically when doing network I/O. * * Note that the pipe will remain the same for the lifetime of the object. * DO NOT read the pipe nor close it yourself. Ever. * * @param obj object that would be "killed" * @return a readable pipe descriptor, or -1 on error. */ int vlc_object_waitpipe( vlc_object_t *obj ) { vlc_object_internals_t *internals = vlc_internals( obj ); vlc_mutex_lock (&pipe_lock); if (internals->pipes[0] == -1) { /* This can only ever happen if someone killed us without locking: */ assert (internals->pipes[1] == -1); /* pipe() is not a cancellation point, but write() is and eventfd() is * unspecified (not in POSIX). */ int canc = vlc_savecancel (); #if defined (HAVE_SYS_EVENTFD_H) internals->pipes[0] = internals->pipes[1] = eventfd (0, EFD_CLOEXEC); if (internals->pipes[0] == -1) #endif { if (vlc_pipe (internals->pipes)) internals->pipes[0] = internals->pipes[1] = -1; } if (internals->pipes[0] != -1 && obj->b_die) { /* Race condition: vlc_object_kill() already invoked! */ msg_Dbg (obj, "waitpipe: object already dying"); write (internals->pipes[1], &(uint64_t){ 1 }, sizeof (uint64_t)); } vlc_restorecancel (canc); } vlc_mutex_unlock (&pipe_lock); return internals->pipes[0]; }
int vlclua_fd_init( lua_State *L, vlclua_dtable_t *dt ) { #ifndef _WIN32 if( vlc_pipe( dt->fd ) ) return -1; #endif dt->fdv = NULL; dt->fdc = 0; vlclua_set_object( L, vlclua_get_dtable, dt ); luaopen_net_intf( L ); return 0; }
/** * Pipe data through an external executable. * @param stream the stream filter object. * @param path path to the executable. */ static int Open (stream_t *stream, const char *path) { stream_sys_t *p_sys = stream->p_sys = malloc (sizeof (*p_sys)); if (p_sys == NULL) return VLC_ENOMEM; stream->pf_read = Read; stream->pf_peek = Peek; stream->pf_control = Control; vlc_cond_init (&p_sys->wait); vlc_mutex_init (&p_sys->lock); p_sys->paused = false; p_sys->pid = -1; p_sys->offset = 0; p_sys->peeked = NULL; stream_Control (stream->p_source, STREAM_CAN_PAUSE, &p_sys->can_pause); stream_Control (stream->p_source, STREAM_CAN_CONTROL_PACE, &p_sys->can_pace); stream_Control (stream->p_source, STREAM_GET_PTS_DELAY, &p_sys->pts_delay); /* I am not a big fan of the pyramid style, but I cannot think of anything * better here. There are too many failure cases. */ int ret = VLC_EGENERIC; int comp[2]; /* We use two pipes rather than one stream socket pair, so that we can * use vmsplice() on Linux. */ if (vlc_pipe (comp) == 0) { p_sys->write_fd = comp[1]; int uncomp[2]; if (vlc_pipe (uncomp) == 0) { p_sys->read_fd = uncomp[0]; #if (_POSIX_SPAWN >= 0) posix_spawn_file_actions_t actions; if (posix_spawn_file_actions_init (&actions) == 0) { char *const argv[] = { (char *)path, NULL }; if (!posix_spawn_file_actions_adddup2 (&actions, comp[0], 0) && !posix_spawn_file_actions_adddup2 (&actions, uncomp[1], 1) && !posix_spawnp (&p_sys->pid, path, &actions, NULL, argv, environ)) { if (vlc_clone (&p_sys->thread, Thread, stream, VLC_THREAD_PRIORITY_INPUT) == 0) ret = VLC_SUCCESS; } else { msg_Err (stream, "cannot execute %s", path); p_sys->pid = -1; } posix_spawn_file_actions_destroy (&actions); } #else /* _POSIX_SPAWN */ switch (p_sys->pid = fork ()) { case -1: msg_Err (stream, "cannot fork: %s", vlc_strerror_c(errno)); break; case 0: dup2 (comp[0], 0); dup2 (uncomp[1], 1); execlp (path, path, (char *)NULL); exit (1); /* if we get, execlp() failed! */ default: if (vlc_clone (&p_sys->thread, Thread, stream, VLC_THREAD_PRIORITY_INPUT) == 0) ret = VLC_SUCCESS; } #endif /* _POSIX_SPAWN < 0 */ close (uncomp[1]); if (ret != VLC_SUCCESS) close (uncomp[0]); } close (comp[0]); if (ret != VLC_SUCCESS) close (comp[1]); } if (ret == VLC_SUCCESS) return VLC_SUCCESS; if (p_sys->pid != -1) while (waitpid (p_sys->pid, &(int){ 0 }, 0) == -1);
static int Start_LuaIntf( vlc_object_t *p_this, const char *name ) { intf_thread_t *p_intf = (intf_thread_t*)p_this; lua_State *L; config_ChainParse( p_intf, "lua-", ppsz_intf_options, p_intf->p_cfg ); if( name == NULL ) { char *n = var_InheritString( p_this, "lua-intf" ); if( unlikely(n == NULL) ) return VLC_EGENERIC; name = p_intf->psz_header = n; } else /* Cleaned up by vlc_object_release() */ p_intf->psz_header = strdup( name ); intf_sys_t *p_sys = malloc( sizeof(*p_sys) ); if( unlikely(p_sys == NULL) ) { free( p_intf->psz_header ); p_intf->psz_header = NULL; return VLC_ENOMEM; } p_intf->p_sys = p_sys; vlclua_fd_init( p_sys ); p_sys->psz_filename = vlclua_find_file( "intf", name ); if( !p_sys->psz_filename ) { msg_Err( p_intf, "Couldn't find lua interface script \"%s\".", name ); goto error; } msg_Dbg( p_intf, "Found lua interface script: %s", p_sys->psz_filename ); L = luaL_newstate(); if( !L ) { msg_Err( p_intf, "Could not create new Lua State" ); goto error; } vlclua_set_this( L, p_intf ); vlclua_set_playlist_internal( L, pl_Get(p_intf) ); luaL_openlibs( L ); /* register our functions */ luaL_register( L, "vlc", p_reg ); /* register submodules */ luaopen_config( L ); luaopen_httpd( L ); luaopen_input( L ); luaopen_msg( L ); luaopen_misc( L ); luaopen_net_intf( L ); luaopen_object( L ); luaopen_osd( L ); luaopen_playlist( L ); luaopen_sd( L ); luaopen_stream( L ); luaopen_strings( L ); luaopen_variables( L ); luaopen_video( L ); luaopen_vlm( L ); luaopen_volume( L ); luaopen_gettext( L ); luaopen_xml( L ); luaopen_equalizer( L ); #if defined(_WIN32) && !VLC_WINSTORE_APP luaopen_win( L ); #endif /* clean up */ lua_pop( L, 1 ); /* Setup the module search path */ if( vlclua_add_modules_path( L, p_sys->psz_filename ) ) { msg_Warn( p_intf, "Error while setting the module search path for %s", p_sys->psz_filename ); lua_close( L ); goto error; } /* * Get the lua-config string. * If the string is empty, try with the old http-* or telnet-* options * and build the right configuration line */ bool b_config_set = false; char *psz_config = var_InheritString( p_intf, "lua-config" ); if( !psz_config ) psz_config = MakeConfig( p_intf, name ); if( psz_config ) { char *psz_buffer; if( asprintf( &psz_buffer, "config={%s}", psz_config ) != -1 ) { char *psz_log = StripPasswords( psz_buffer ); if( psz_log != NULL ) { msg_Dbg( p_intf, "Setting config variable: %s", psz_log ); free( psz_log ); } if( luaL_dostring( L, psz_buffer ) == 1 ) msg_Err( p_intf, "Error while parsing \"lua-config\"." ); free( psz_buffer ); lua_getglobal( L, "config" ); if( lua_istable( L, -1 ) ) { if( !strcmp( name, "cli" ) ) { lua_getfield( L, -1, "rc" ); if( lua_istable( L, -1 ) ) { /* msg_Warn( p_intf, "The `rc' lua interface script " "was renamed `cli', please update " "your configuration!" ); */ lua_setfield( L, -2, "cli" ); } else lua_pop( L, 1 ); } lua_getfield( L, -1, name ); if( lua_istable( L, -1 ) ) { lua_setglobal( L, "config" ); b_config_set = true; } } } free( psz_config ); } if( !b_config_set ) { lua_newtable( L ); lua_setglobal( L, "config" ); } /* Wrapper for legacy telnet config */ if ( !strcmp( name, "telnet" ) ) { /* msg_Warn( p_intf, "The `telnet' lua interface script was replaced " "by `cli', please update your configuration!" ); */ char *wrapped_file = vlclua_find_file( "intf", "cli" ); if( !wrapped_file ) { msg_Err( p_intf, "Couldn't find lua interface script \"cli\", " "needed by telnet wrapper" ); lua_close( p_sys->L ); goto error; } lua_pushstring( L, wrapped_file ); lua_setglobal( L, "wrapped_file" ); free( wrapped_file ); } p_sys->L = L; #ifndef _WIN32 if( vlc_pipe( p_sys->fd ) ) { lua_close( p_sys->L ); goto error; } #else # define close(fd) (void)0 #endif if( vlc_clone( &p_sys->thread, Run, p_intf, VLC_THREAD_PRIORITY_LOW ) ) { close( p_sys->fd[1] ); close( p_sys->fd[0] ); lua_close( p_sys->L ); goto error; } return VLC_SUCCESS; error: free( p_sys->psz_filename ); free( p_sys ); free( p_intf->psz_header ); p_intf->psz_header = NULL; return VLC_EGENERIC; }
static int Open( vlc_object_t *p_this ) { /* initialisation of the connection */ intf_thread_t *p_intf = (intf_thread_t*)p_this; intf_sys_t *p_sys = malloc( sizeof( intf_sys_t ) ); playlist_t *p_playlist; DBusConnection *p_conn; DBusError error; char *psz_service_name = NULL; if( !p_sys || !dbus_threads_init_default()) return VLC_ENOMEM; p_sys->b_meta_read = false; p_sys->i_caps = CAPS_NONE; p_sys->b_dead = false; p_sys->p_input = NULL; p_sys->i_playing_state = -1; if( vlc_pipe( p_sys->p_pipe_fds ) ) { free( p_sys ); msg_Err( p_intf, "Could not create pipe" ); return VLC_EGENERIC; } p_sys->b_unique = var_CreateGetBool( p_intf, "dbus-unique-service-id" ); if( p_sys->b_unique ) { if( asprintf( &psz_service_name, "%s-%d", DBUS_MPRIS_BUS_NAME, getpid() ) < 0 ) { free( p_sys ); return VLC_ENOMEM; } } else { psz_service_name = strdup(DBUS_MPRIS_BUS_NAME); } dbus_error_init( &error ); /* connect privately to the session bus * the connection will not be shared with other vlc modules which use dbus, * thus avoiding a whole class of concurrency issues */ p_conn = dbus_bus_get_private( DBUS_BUS_SESSION, &error ); if( !p_conn ) { msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s", error.message ); dbus_error_free( &error ); free( psz_service_name ); free( p_sys ); return VLC_EGENERIC; } dbus_connection_set_exit_on_disconnect( p_conn, FALSE ); /* register a well-known name on the bus */ dbus_bus_request_name( p_conn, psz_service_name, 0, &error ); if( dbus_error_is_set( &error ) ) { msg_Err( p_this, "Error requesting service %s: %s", psz_service_name, error.message ); dbus_error_free( &error ); free( psz_service_name ); free( p_sys ); return VLC_EGENERIC; } msg_Info( p_intf, "listening on dbus as: %s", psz_service_name ); free( psz_service_name ); /* we register the objects */ dbus_connection_register_object_path( p_conn, DBUS_MPRIS_ROOT_PATH, &dbus_mpris_root_vtable, p_this ); dbus_connection_register_object_path( p_conn, DBUS_MPRIS_PLAYER_PATH, &dbus_mpris_player_vtable, p_this ); dbus_connection_register_object_path( p_conn, DBUS_MPRIS_TRACKLIST_PATH, &dbus_mpris_tracklist_vtable, p_this ); dbus_connection_flush( p_conn ); p_intf->pf_run = Run; p_intf->p_sys = p_sys; p_sys->p_conn = p_conn; p_sys->p_events = vlc_array_new(); p_sys->p_timeouts = vlc_array_new(); p_sys->p_watches = vlc_array_new(); vlc_mutex_init( &p_sys->lock ); p_playlist = pl_Get( p_intf ); p_sys->p_playlist = p_playlist; var_AddCallback( p_playlist, "item-current", AllCallback, p_intf ); var_AddCallback( p_playlist, "intf-change", AllCallback, p_intf ); var_AddCallback( p_playlist, "playlist-item-append", AllCallback, p_intf ); var_AddCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf ); var_AddCallback( p_playlist, "random", AllCallback, p_intf ); var_AddCallback( p_playlist, "repeat", AllCallback, p_intf ); var_AddCallback( p_playlist, "loop", AllCallback, p_intf ); dbus_connection_set_dispatch_status_function( p_conn, dispatch_status_cb, p_intf, NULL ); if( !dbus_connection_set_timeout_functions( p_conn, add_timeout, remove_timeout, timeout_toggled, p_intf, NULL ) ) { dbus_connection_unref( p_conn ); free( psz_service_name ); free( p_sys ); return VLC_ENOMEM; } if( !dbus_connection_set_watch_functions( p_conn, add_watch, remove_watch, watch_toggled, p_intf, NULL ) ) { dbus_connection_unref( p_conn ); free( psz_service_name ); free( p_sys ); return VLC_ENOMEM; } /* dbus_connection_set_wakeup_main_function( p_conn, wakeup_main_loop, p_intf, NULL); */ UpdateCaps( p_intf ); return VLC_SUCCESS; }
static int Open( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t*)p_this; /* initialisation of the connection */ if( !dbus_threads_init_default() ) return VLC_EGENERIC; intf_sys_t *p_sys = calloc( 1, sizeof( intf_sys_t ) ); if( unlikely(!p_sys) ) return VLC_ENOMEM; playlist_t *p_playlist; DBusConnection *p_conn; p_sys->i_player_caps = PLAYER_CAPS_NONE; p_sys->i_playing_state = PLAYBACK_STATE_INVALID; if( vlc_pipe( p_sys->p_pipe_fds ) ) { free( p_sys ); msg_Err( p_intf, "Could not create pipe" ); return VLC_EGENERIC; } char psz_service_name[sizeof(DBUS_MPRIS_BUS_NAME) + 12]; if( var_InheritBool( p_intf, "dbus-unique-service-id" ) ) snprintf( psz_service_name, sizeof( psz_service_name ), DBUS_MPRIS_BUS_NAME"-%d", getpid() ); else strcpy( psz_service_name, DBUS_MPRIS_BUS_NAME ); DBusError error; dbus_error_init( &error ); /* connect privately to the session bus * the connection will not be shared with other vlc modules which use dbus, * thus avoiding a whole class of concurrency issues */ p_conn = dbus_bus_get_private( DBUS_BUS_SESSION, &error ); if( !p_conn ) { msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s", error.message ); dbus_error_free( &error ); free( p_sys ); return VLC_EGENERIC; } dbus_connection_set_exit_on_disconnect( p_conn, FALSE ); /* register a well-known name on the bus */ dbus_bus_request_name( p_conn, psz_service_name, 0, &error ); if( dbus_error_is_set( &error ) ) { msg_Err( p_this, "Error requesting service %s: %s", psz_service_name, error.message ); dbus_error_free( &error ); free( p_sys ); return VLC_EGENERIC; } msg_Info( p_intf, "listening on dbus as: %s", psz_service_name ); /* Register the entry point object path */ dbus_connection_register_object_path( p_conn, DBUS_MPRIS_OBJECT_PATH, &dbus_mpris_vtable, p_this ); dbus_connection_flush( p_conn ); p_intf->pf_run = Run; p_intf->p_sys = p_sys; p_sys->p_conn = p_conn; p_sys->p_events = vlc_array_new(); p_sys->p_timeouts = vlc_array_new(); p_sys->p_watches = vlc_array_new(); vlc_mutex_init( &p_sys->lock ); p_playlist = pl_Get( p_intf ); p_sys->p_playlist = p_playlist; var_AddCallback( p_playlist, "item-current", AllCallback, p_intf ); var_AddCallback( p_playlist, "intf-change", AllCallback, p_intf ); var_AddCallback( p_playlist, "volume", AllCallback, p_intf ); var_AddCallback( p_playlist, "mute", AllCallback, p_intf ); var_AddCallback( p_playlist, "playlist-item-append", AllCallback, p_intf ); var_AddCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf ); var_AddCallback( p_playlist, "random", AllCallback, p_intf ); var_AddCallback( p_playlist, "repeat", AllCallback, p_intf ); var_AddCallback( p_playlist, "loop", AllCallback, p_intf ); dbus_connection_set_dispatch_status_function( p_conn, dispatch_status_cb, p_intf, NULL ); if( !dbus_connection_set_timeout_functions( p_conn, add_timeout, remove_timeout, timeout_toggled, p_intf, NULL ) ) { dbus_connection_unref( p_conn ); free( p_sys ); return VLC_ENOMEM; } if( !dbus_connection_set_watch_functions( p_conn, add_watch, remove_watch, watch_toggled, p_intf, NULL ) ) { dbus_connection_unref( p_conn ); free( p_sys ); return VLC_ENOMEM; } /* dbus_connection_set_wakeup_main_function( p_conn, wakeup_main_loop, p_intf, NULL); */ return VLC_SUCCESS; }
static int Open( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t*)p_this; /* initialisation of the connection */ if( !dbus_threads_init_default() ) return VLC_EGENERIC; intf_sys_t *p_sys = calloc( 1, sizeof( intf_sys_t ) ); if( unlikely(!p_sys) ) return VLC_ENOMEM; playlist_t *p_playlist; DBusConnection *p_conn; p_sys->i_player_caps = PLAYER_CAPS_NONE; p_sys->i_playing_state = PLAYBACK_STATE_INVALID; if( vlc_pipe( p_sys->p_pipe_fds ) ) { free( p_sys ); msg_Err( p_intf, "Could not create pipe" ); return VLC_EGENERIC; } DBusError error; dbus_error_init( &error ); /* connect privately to the session bus * the connection will not be shared with other vlc modules which use dbus, * thus avoiding a whole class of concurrency issues */ p_conn = dbus_bus_get_private( DBUS_BUS_SESSION, &error ); if( !p_conn ) { msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s", error.message ); dbus_error_free( &error ); vlc_close( p_sys->p_pipe_fds[1] ); vlc_close( p_sys->p_pipe_fds[0] ); free( p_sys ); return VLC_EGENERIC; } dbus_connection_set_exit_on_disconnect( p_conn, FALSE ); /* Register the entry point object path */ dbus_connection_register_object_path( p_conn, DBUS_MPRIS_OBJECT_PATH, &dbus_mpris_vtable, p_this ); /* Try to register org.mpris.MediaPlayer2.vlc */ dbus_bus_request_name( p_conn, DBUS_MPRIS_BUS_NAME, 0, &error ); if( dbus_error_is_set( &error ) ) { msg_Dbg( p_this, "Failed to get service name %s: %s", DBUS_MPRIS_BUS_NAME, error.message ); dbus_error_free( &error ); /* Register an instance-specific well known name of the form * org.mpris.MediaPlayer2.vlc.instanceXXXX where XXXX is the * current Process ID */ char unique_service[sizeof( DBUS_MPRIS_BUS_NAME ) + sizeof( DBUS_INSTANCE_ID_PREFIX ) + 10]; snprintf( unique_service, sizeof (unique_service), DBUS_MPRIS_BUS_NAME"."DBUS_INSTANCE_ID_PREFIX"%"PRIu32, (uint32_t)getpid() ); dbus_bus_request_name( p_conn, unique_service, 0, &error ); if( dbus_error_is_set( &error ) ) { msg_Err( p_this, "Failed to get service name %s: %s", DBUS_MPRIS_BUS_NAME, error.message ); dbus_error_free( &error ); } else msg_Dbg( p_intf, "listening on dbus as: %s", unique_service ); } else msg_Dbg( p_intf, "listening on dbus as: %s", DBUS_MPRIS_BUS_NAME ); dbus_connection_flush( p_conn ); p_intf->p_sys = p_sys; p_sys->p_conn = p_conn; p_sys->p_events = vlc_array_new(); p_sys->p_timeouts = vlc_array_new(); p_sys->p_watches = vlc_array_new(); vlc_mutex_init( &p_sys->lock ); p_playlist = pl_Get( p_intf ); p_sys->p_playlist = p_playlist; var_AddCallback( p_playlist, "input-current", AllCallback, p_intf ); var_AddCallback( p_playlist, "volume", AllCallback, p_intf ); var_AddCallback( p_playlist, "mute", AllCallback, p_intf ); var_AddCallback( p_playlist, "playlist-item-append", AllCallback, p_intf ); var_AddCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf ); var_AddCallback( p_playlist, "random", AllCallback, p_intf ); var_AddCallback( p_playlist, "repeat", AllCallback, p_intf ); var_AddCallback( p_playlist, "loop", AllCallback, p_intf ); var_AddCallback( p_playlist, "fullscreen", AllCallback, p_intf ); if( !dbus_connection_set_timeout_functions( p_conn, add_timeout, remove_timeout, toggle_timeout, p_intf, NULL ) ) goto error; if( !dbus_connection_set_watch_functions( p_conn, add_watch, remove_watch, watch_toggled, p_intf, NULL ) ) goto error; if( vlc_clone( &p_sys->thread, Run, p_intf, VLC_THREAD_PRIORITY_LOW ) ) goto error; return VLC_SUCCESS; error: /* The dbus connection is private, * so we are responsible for closing it * XXX: Does this make sense when OOM ? */ dbus_connection_close( p_sys->p_conn ); dbus_connection_unref( p_conn ); vlc_array_destroy( p_sys->p_events ); vlc_array_destroy( p_sys->p_timeouts ); vlc_array_destroy( p_sys->p_watches ); vlc_mutex_destroy( &p_sys->lock ); vlc_close( p_sys->p_pipe_fds[1] ); vlc_close( p_sys->p_pipe_fds[0] ); free( p_sys ); return VLC_ENOMEM; }