/** * Waits until the variable is inactive (i.e. not executing a callback) */ static void WaitUnused( vlc_object_t *p_this, variable_t *p_var ) { vlc_object_internals_t *p_priv = vlc_internals( p_this ); mutex_cleanup_push( &p_priv->var_lock ); while( p_var->b_incallback ) vlc_cond_wait( &p_priv->var_wait, &p_priv->var_lock ); vlc_cleanup_pop( ); }
/***************************************************************************** * Run: Thread entry-point ****************************************************************************/ static void* Run( void *data ) { services_discovery_t *p_sd = ( services_discovery_t * )data; services_discovery_sys_t *p_sys = p_sd->p_sys; lua_State *L = p_sys->L; int cancel = vlc_savecancel(); lua_getglobal( L, "main" ); if( !lua_isfunction( L, lua_gettop( L ) ) || lua_pcall( L, 0, 1, 0 ) ) { msg_Err( p_sd, "Error while running script %s, " "function main(): %s", p_sys->psz_filename, lua_tostring( L, lua_gettop( L ) ) ); lua_pop( L, 1 ); vlc_restorecancel( cancel ); return NULL; } msg_Dbg( p_sd, "LuaSD script loaded: %s", p_sys->psz_filename ); /* Force garbage collection, because the core will keep the SD * open, but lua will never gc until lua_close(). */ lua_gc( L, LUA_GCCOLLECT, 0 ); vlc_restorecancel( cancel ); /* Main loop to handle search requests */ vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { /* Wait for a request */ if( !p_sys->i_query ) { vlc_cond_wait( &p_sys->cond, &p_sys->lock ); continue; } /* Execute one query (protected against cancellation) */ char *psz_query = p_sys->ppsz_query[p_sys->i_query - 1]; TAB_ERASE(p_sys->i_query, p_sys->ppsz_query, p_sys->i_query - 1); vlc_mutex_unlock( &p_sys->lock ); cancel = vlc_savecancel(); DoSearch( p_sd, psz_query ); free( psz_query ); /* Force garbage collection, because the core will keep the SD * open, but lua will never gc until lua_close(). */ lua_gc( L, LUA_GCCOLLECT, 0 ); vlc_restorecancel( cancel ); vlc_mutex_lock( &p_sys->lock ); } vlc_cleanup_pop(); vlc_assert_unreachable(); }
static void Run( fingerprinter_thread_t *p_fingerprinter ) { fingerprinter_sys_t *p_sys = p_fingerprinter->p_sys; /* main loop */ for (;;) { vlc_mutex_lock( &p_sys->processing.lock ); mutex_cleanup_push( &p_sys->processing.lock ); vlc_cond_timedwait( &p_sys->incoming_queue_filled, &p_sys->processing.lock, mdate() + 1000000 ); vlc_cleanup_run(); QueueIncomingRequests( p_sys ); vlc_mutex_lock( &p_sys->processing.lock ); // L0 mutex_cleanup_push( &p_sys->processing.lock ); vlc_cleanup_push( cancelRun, p_sys ); // C1 //** for ( p_sys->i = 0 ; p_sys->i < vlc_array_count( p_sys->processing.queue ); p_sys->i++ ) { fingerprint_request_t *p_data = vlc_array_item_at_index( p_sys->processing.queue, p_sys->i ); acoustid_fingerprint_t acoustid_print; memset( &acoustid_print , 0, sizeof(acoustid_fingerprint_t) ); vlc_cleanup_push( clearPrint, &acoustid_print ); // C2 p_sys->psz_uri = input_item_GetURI( p_data->p_item ); if ( p_sys->psz_uri ) { /* overwrite with hint, as in this case, fingerprint's session will be truncated */ if ( p_data->i_duration ) acoustid_print.i_duration = p_data->i_duration; DoFingerprint( VLC_OBJECT(p_fingerprinter), p_sys, &acoustid_print ); DoAcoustIdWebRequest( VLC_OBJECT(p_fingerprinter), &acoustid_print ); fill_metas_with_results( p_data, &acoustid_print ); FREENULL( p_sys->psz_uri ); } vlc_cleanup_run( ); // C2 /* copy results */ vlc_mutex_lock( &p_sys->results.lock ); vlc_array_append( p_sys->results.queue, p_data ); vlc_mutex_unlock( &p_sys->results.lock ); vlc_testcancel(); } if ( vlc_array_count( p_sys->processing.queue ) ) { var_TriggerCallback( p_fingerprinter, "results-available" ); vlc_array_clear( p_sys->processing.queue ); } vlc_cleanup_pop( ); // C1 //** vlc_cleanup_run(); // L0 } }
/** * Receives stream data. * * Dequeues pending incoming data for an HTTP/2 stream. If there is currently * no data block, wait for one. * * \return a VLC data block, or NULL on stream error or end of stream */ static block_t *vlc_h2_stream_read(struct vlc_http_stream *stream) { struct vlc_h2_stream *s = (struct vlc_h2_stream *)stream; struct vlc_h2_conn *conn = s->conn; struct vlc_h2_frame *f; vlc_h2_stream_lock(s); while ((f = s->recv_head) == NULL && !s->recv_end && !s->interrupted) { mutex_cleanup_push(&conn->lock); vlc_cond_wait(&s->recv_wait, &conn->lock); vlc_cleanup_pop(); } if (f == NULL) { vlc_h2_stream_unlock(s); return NULL; } s->recv_head = f->next; if (f->next == NULL) { assert(s->recv_tailp == &f->next); s->recv_tailp = &s->recv_head; } /* Credit the receive window if missing credit exceeds 50%. */ uint_fast32_t credit = VLC_H2_INIT_WINDOW - s->recv_cwnd; if (credit >= (VLC_H2_INIT_WINDOW / 2) && !vlc_h2_output_send(conn->out, vlc_h2_frame_window_update(s->id, credit))) s->recv_cwnd += credit; vlc_h2_stream_unlock(s); /* This, err, unconventional code to avoid copying data. */ block_t *block = block_heap_Alloc(f, sizeof (*f) + vlc_h2_frame_size(f)); if (unlikely(block == NULL)) { free(f); vlc_h2_stream_error(conn, s->id, VLC_H2_INTERNAL_ERROR); return NULL; } size_t len; uint8_t *buf = vlc_h2_frame_data_get(f, &len); assert(block->i_buffer >= len); assert(block->p_buffer <= buf); assert(block->p_buffer + block->i_buffer >= buf + len); block->p_buffer = buf; block->i_buffer = len; return block; }
static void* update_request_thread( void *obj ) { filter_t* p_filter = (filter_t*)obj; filter_sys_t *p_sys = p_filter->p_sys; msg_Dbg( p_filter, "VNC update request thread started" ); rfbFramebufferUpdateRequestMsg udr; udr.type = rfbFramebufferUpdateRequest; udr.incremental = 0; udr.x = 0; udr.y = 0; udr.w = htons(p_sys->i_vnc_width); udr.h = htons(p_sys->i_vnc_height); int w; vlc_cleanup_push( update_request_thread_cleanup, p_filter ); w = write_exact(p_filter, p_sys->i_socket, (char*)&udr, sz_rfbFramebufferUpdateRequestMsg); vlc_cleanup_pop(); if( !w ) { msg_Err( p_filter, "Could not write rfbFramebufferUpdateRequestMsg." ); update_request_thread_cleanup( p_filter ); return NULL; } udr.incremental = 1; mtime_t i_poll_interval_microsec = p_sys->i_vnc_poll_interval * 1000; if( p_sys->b_vnc_poll) { vlc_cleanup_push( update_request_thread_cleanup, p_filter ); for( ;; ) { msleep( i_poll_interval_microsec ); if( !write_exact(p_filter, p_sys->i_socket, (char*)&udr, sz_rfbFramebufferUpdateRequestMsg)) { msg_Err( p_filter, "Could not write rfbFramebufferUpdateRequestMsg." ); break; } } vlc_cleanup_run(); } else { msg_Dbg( p_filter, "VNC polling disabled." ); } msg_Dbg( p_filter, "VNC update request thread ended" ); return NULL; }
/** * Sends one HTTP/2 frame through TLS. * * This function sends a whole HTTP/2 frame through a TLS session, then * releases the memory used by the frame. * * The caller must "own" the write side of the TLS session. * * @note This is a blocking function and may be a thread cancellation point. * * @return 0 on success, -1 if the connection failed */ static int vlc_h2_frame_send(struct vlc_tls *tls, struct vlc_h2_frame *f) { size_t len = vlc_h2_frame_size(f); ssize_t val; vlc_cleanup_push(free, f); val = vlc_https_send(tls, f->data, len); vlc_cleanup_pop(); free(f); return ((size_t)val == len) ? 0 : -1; }
static void *detached_thread(void *data) { vlc_thread_t th = data; thread = th; vlc_cleanup_push(clean_detached_thread, th); th->entry(th->data); vlc_cleanup_pop(); clean_detached_thread(th); return NULL; }
vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd, const char *host, const char *service, const char *const *alpn, char **alp) { vlc_tls_t *session; int canc, val; canc = vlc_savecancel(); session = vlc_tls_SessionCreate (crd, fd, host, alpn); if (session == NULL) { vlc_restorecancel(canc); return NULL; } mtime_t deadline = mdate (); deadline += var_InheritInteger (crd, "ipv4-timeout") * 1000; struct pollfd ufd[1]; ufd[0].fd = fd; vlc_cleanup_push (cleanup_tls, session); while ((val = crd->handshake(crd, session, host, service, alp)) != 0) { if (val < 0) { msg_Err(crd, "TLS session handshake error"); error: vlc_tls_SessionDelete (session); session = NULL; break; } mtime_t now = mdate (); if (now > deadline) now = deadline; assert (val <= 2); ufd[0] .events = (val == 1) ? POLLIN : POLLOUT; vlc_restorecancel(canc); val = poll (ufd, 1, (deadline - now) / 1000); canc = vlc_savecancel(); if (val == 0) { msg_Err(crd, "TLS session handshake timeout"); goto error; } } vlc_cleanup_pop(); vlc_restorecancel(canc); return session; }
static void *joinable_thread(void *data) { vlc_thread_t th = data; void *ret; vlc_cleanup_push(finish_joinable_thread, th); thread = th; ret = th->entry(th->data); vlc_cleanup_pop(); vlc_sem_post(&th->finished); return ret; }
int vlc_sem_wait_i11e(vlc_sem_t *sem) { vlc_interrupt_t *ctx = vlc_interrupt_get(); if (ctx == NULL) return vlc_sem_wait(sem), 0; vlc_interrupt_prepare(ctx, vlc_interrupt_sem, sem); vlc_cleanup_push(vlc_interrupt_cleanup, ctx); vlc_sem_wait(sem); vlc_cleanup_pop(); return vlc_interrupt_finish(ctx); }
VLC_NORETURN static void *vlc_timer_thread (void *data) { struct vlc_timer *timer = data; vlc_mutex_lock (&timer->lock); mutex_cleanup_push (&timer->lock); for (;;) { while (timer->value == 0) vlc_cond_wait (&timer->reschedule, &timer->lock); if (vlc_cond_timedwait (&timer->reschedule, &timer->lock, timer->value) == 0) continue; if (timer->interval == 0) timer->value = 0; /* disarm */ vlc_mutex_unlock (&timer->lock); int canc = vlc_savecancel (); timer->func (timer->data); vlc_restorecancel (canc); mtime_t now = mdate (); unsigned misses; vlc_mutex_lock (&timer->lock); if (timer->interval == 0) continue; misses = (now - timer->value) / timer->interval; timer->value += timer->interval; /* Try to compensate for one miss (mwait() will return immediately) * but no more. Otherwise, we might busy loop, after extended periods * without scheduling (suspend, SIGSTOP, RT preemption, ...). */ if (misses > 1) { misses--; timer->value += misses * timer->interval; atomic_fetch_add_explicit (&timer->overruns, misses, memory_order_relaxed); } } vlc_cleanup_pop (); vlc_assert_unreachable (); }
/***************************************************************************** * Run: main thread *****************************************************************************/ static void *Run( void *data ) { services_discovery_t *p_sd = data; services_discovery_sys_t *p_sys = p_sd->p_sys; vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { while( !p_sys->b_update ) vlc_cond_wait( &p_sys->wait, &p_sys->lock ); int canc = vlc_savecancel (); msg_Dbg( p_sd, "Update required" ); if( p_sys->update_type == UPDATE_URLS ) { char* psz_urls = var_GetNonEmptyString( p_sd, "podcast-urls" ); ParseUrls( p_sd, psz_urls ); free( psz_urls ); } else if( p_sys->update_type == UPDATE_REQUEST ) { ParseRequest( p_sd ); } p_sys->b_update = false; for( int i = 0; i < p_sd->p_sys->i_input; i++ ) { input_thread_t *p_input = p_sd->p_sys->pp_input[i]; if( p_input->b_eof || p_input->b_error ) { input_Stop( p_input, false ); vlc_thread_join( p_input ); vlc_object_release( p_input ); p_sd->p_sys->pp_input[i] = NULL; REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i ); i--; } } vlc_restorecancel (canc); } vlc_cleanup_pop(); assert(0); /* dead code */ }
/***************************************************************************** * Run: main thread *****************************************************************************/ VLC_NORETURN static void *Run( void *data ) { services_discovery_t *p_sd = data; services_discovery_sys_t *p_sys = p_sd->p_sys; vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { while( !p_sys->b_update ) vlc_cond_wait( &p_sys->wait, &p_sys->lock ); int canc = vlc_savecancel (); msg_Dbg( p_sd, "Update required" ); if( p_sys->update_type == UPDATE_URLS ) { char *psz_urls = var_GetNonEmptyString( p_sd->p_parent, "podcast-urls" ); ParseUrls( p_sd, psz_urls ); free( psz_urls ); } else if( p_sys->update_type == UPDATE_REQUEST ) ParseRequest( p_sd ); p_sys->b_update = false; for( int i = 0; i < p_sd->p_sys->i_input; i++ ) { input_thread_t *p_input = p_sd->p_sys->pp_input[i]; int state = var_GetInteger( p_input, "state" ); if( state == END_S || state == ERROR_S ) { input_Stop( p_input ); input_Close( p_input ); p_sd->p_sys->pp_input[i] = NULL; REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i ); i--; } } vlc_restorecancel (canc); } vlc_cleanup_pop(); vlc_assert_unreachable(); /* dead code */ }
/***************************************************************************** * ALSAThread: asynchronous thread used to DMA the data to the device *****************************************************************************/ static void* ALSAThread( void *data ) { aout_instance_t * p_aout = data; struct aout_sys_t * p_sys = p_aout->output.p_sys; /* Wait for the exact time to start playing (avoids resampling) */ vlc_sem_wait( &p_sys->wait ); mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 ); vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm ); for(;;) ALSAFill( p_aout ); assert(0); vlc_cleanup_pop(); }
int vlc_sem_wait_i11e(vlc_sem_t *sem) { vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var); if (ctx == NULL) return vlc_sem_wait(sem), 0; int ret = vlc_interrupt_prepare(ctx, vlc_interrupt_sem, sem); if (ret) { vlc_testcancel(); return ret; } vlc_cleanup_push(vlc_interrupt_cleanup, ctx); vlc_sem_wait(sem); vlc_cleanup_pop(); return vlc_interrupt_finish(ctx); }
/** * @brief Thread writing frames to the subprocess */ static void* inputThread(void* userData) { filter_t* intf = (filter_t*)userData; filter_sys_t* sys = intf->p_sys; msg_Info(intf, "inputThread: enter"); while (true) { picture_t* pic; // acquire a frame pushed from y4m_filter() vlc_mutex_lock(&sys->inputMutex); mutex_cleanup_push(&sys->inputMutex); while (NULL == (pic = picture_fifo_Pop(sys->inputFifo))) { //msg_Info(intf, "inputThread: wait picture"); vlc_cond_wait(&sys->inputCond, &sys->inputMutex); } sys->bufferedIn--; vlc_mutex_unlock(&sys->inputMutex); vlc_cleanup_pop(); //msg_Info(intf, "inputThread: write picture"); if (1 != writeY4mFrame(intf, pic, sys->stdin)) { msg_Err(intf, "inputThread: Failed to write y4m frame"); break; } picture_Release(pic); } msg_Info(intf, "inputThread: exit"); sys->threadExit = true; return userData; }
static void *Thread(void *data) { demux_t *demux = data; demux_sys_t *sys = demux->p_sys; struct wl_display *display = sys->display; struct pollfd ufd[1]; unsigned interval = lroundf(CLOCK_FREQ / (sys->rate * 1000.f)); int canc = vlc_savecancel(); vlc_cleanup_push(cleanup_wl_display_read, display); ufd[0].fd = wl_display_get_fd(display); ufd[0].events = POLLIN; for (;;) { if (DisplayError(demux, display)) break; if (sys->es != NULL) { block_t *block = Shoot(demux); block->i_pts = block->i_dts = vlc_tick_now(); es_out_SetPCR(demux->out, block->i_pts); es_out_Send(demux->out, sys->es, block); } while (wl_display_prepare_read(display) != 0) wl_display_dispatch_pending(display); wl_display_flush(display); vlc_restorecancel(canc); while (poll(ufd, 1, interval) < 0); canc = vlc_savecancel(); wl_display_read_events(display); wl_display_dispatch_pending(display); } vlc_cleanup_pop(); vlc_restorecancel(canc); return NULL; }
static struct vlc_http_msg *vlc_h2_stream_wait(struct vlc_http_stream *stream) { struct vlc_h2_stream *s = (struct vlc_h2_stream *)stream; struct vlc_h2_conn *conn = s->conn; struct vlc_http_msg *m; vlc_h2_stream_lock(s); while ((m = s->recv_hdr) == NULL && !s->recv_end && !s->interrupted) { mutex_cleanup_push(&conn->lock); vlc_cond_wait(&s->recv_wait, &conn->lock); vlc_cleanup_pop(); } s->recv_hdr = NULL; vlc_h2_stream_unlock(s); /* TODO? distinguish failed/unknown/ignored */ if (m != NULL) vlc_http_msg_attach(m, stream); return m; }
/** * RTP/RTCP session thread for stream sockets (framed RTP) */ void *rtp_stream_thread (void *opaque) { #ifndef WIN32 demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; int fd = sys->fd; for (;;) { /* There is no reordering on stream sockets, so no timeout. */ ssize_t val; uint16_t frame_len; if (recv (fd, &frame_len, 2, MSG_WAITALL) != 2) break; block_t *block = block_Alloc (ntohs (frame_len)); if (unlikely(block == NULL)) break; block_cleanup_push (block); val = recv (fd, block->p_buffer, block->i_buffer, MSG_WAITALL); vlc_cleanup_pop (); if (val != (ssize_t)block->i_buffer) { block_Release (block); break; } int canc = vlc_savecancel (); rtp_process (demux, block); rtp_dequeue_force (demux, sys->session); vlc_restorecancel (canc); } #else (void) opaque; #endif return NULL; }
int vlc_mwait_i11e(mtime_t deadline) { vlc_interrupt_t *ctx = vlc_interrupt_get(); if (ctx == NULL) return mwait(deadline), 0; vlc_cond_t wait; vlc_cond_init(&wait); vlc_interrupt_prepare(ctx, vlc_mwait_i11e_wake, &wait); vlc_mutex_lock(&ctx->lock); vlc_cleanup_push(vlc_mwait_i11e_cleanup, ctx); while (!ctx->interrupted && vlc_cond_timedwait(&wait, &ctx->lock, deadline) == 0); vlc_cleanup_pop(); vlc_mutex_unlock(&ctx->lock); int ret = vlc_interrupt_finish(ctx); vlc_cond_destroy(&wait); return ret; }
static void *playlist_thread(void *data) { libvlc_media_list_player_t *mlp = data; vlc_mutex_lock(&mlp->mp_callback_lock); mutex_cleanup_push(&mlp->mp_callback_lock); for (;;) { int canc; while (mlp->seek_offset == 0) vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock); canc = vlc_savecancel(); set_relative_playlist_position_and_play(mlp, mlp->seek_offset); mlp->seek_offset = 0; vlc_restorecancel(canc); } vlc_cleanup_pop(); vlc_assert_unreachable(); }
/** * Gets a datagram from the network. * @param fd datagram file descriptor * @return a block or NULL on fatal error (socket dead) */ static block_t *rtp_dgram_recv (vlc_object_t *obj, int fd) { block_t *block = block_Alloc (0xffff); ssize_t len; block_cleanup_push (block); do { len = net_Read (obj, fd, NULL, block->p_buffer, block->i_buffer, false); if (((len <= 0) && fd_dead (fd)) || !vlc_object_alive (obj)) { /* POLLHUP -> permanent (DCCP) socket error */ block_Release (block); block = NULL; break; } } while (len == -1); vlc_cleanup_pop (); return block ? block_Realloc (block, 0, len) : NULL; }
/** * Gets a framed RTP packet. * @param fd stream file descriptor * @return a block or NULL in case of fatal error */ static block_t *rtp_stream_recv (vlc_object_t *obj, int fd) { ssize_t len = 0; uint8_t hdr[2]; /* frame header */ /* Receives the RTP frame header */ do { ssize_t val = net_Read (obj, fd, NULL, hdr + len, 2 - len, false); if (val <= 0) return NULL; len += val; } while (len < 2); block_t *block = block_Alloc (GetWBE (hdr)); /* Receives the RTP packet */ for (ssize_t i = 0; i < len;) { ssize_t val; block_cleanup_push (block); val = net_Read (obj, fd, NULL, block->p_buffer + i, block->i_buffer - i, false); vlc_cleanup_pop (); if (val <= 0) { block_Release (block); return NULL; } i += val; } return block; }
/***************************************************************************** * Run : *****************************************************************************/ static void *Run( void *opaque ) { fingerprinter_thread_t *p_fingerprinter = opaque; fingerprinter_sys_t *p_sys = p_fingerprinter->p_sys; vlc_mutex_lock( &p_sys->processing.lock ); mutex_cleanup_push( &p_sys->processing.lock ); /* main loop */ for (;;) { msleep( CLOCK_FREQ ); QueueIncomingRequests( p_sys ); vlc_testcancel(); for ( size_t i = 0 ; i < vlc_array_count( &p_sys->processing.queue ); i++ ) { int canc = vlc_savecancel(); fingerprint_request_t *p_data = vlc_array_item_at_index( &p_sys->processing.queue, i ); char *psz_uri = input_item_GetURI( p_data->p_item ); if ( psz_uri != NULL ) { acoustid_fingerprint_t acoustid_print; memset( &acoustid_print , 0, sizeof (acoustid_print) ); /* overwrite with hint, as in this case, fingerprint's session will be truncated */ if ( p_data->i_duration ) acoustid_print.i_duration = p_data->i_duration; DoFingerprint( p_fingerprinter, &acoustid_print, psz_uri ); free( psz_uri ); DoAcoustIdWebRequest( VLC_OBJECT(p_fingerprinter), &acoustid_print ); fill_metas_with_results( p_data, &acoustid_print ); for( unsigned j = 0; j < acoustid_print.results.count; j++ ) free_acoustid_result_t( &acoustid_print.results.p_results[j] ); if( acoustid_print.results.count ) free( acoustid_print.results.p_results ); free( acoustid_print.psz_fingerprint ); } vlc_restorecancel(canc); /* copy results */ vlc_mutex_lock( &p_sys->results.lock ); vlc_array_append( &p_sys->results.queue, p_data ); vlc_mutex_unlock( &p_sys->results.lock ); vlc_testcancel(); } if ( vlc_array_count( &p_sys->processing.queue ) ) { var_TriggerCallback( p_fingerprinter, "results-available" ); vlc_array_clear( &p_sys->processing.queue ); } } vlc_cleanup_pop(); vlc_assert_unreachable(); }
static void* vnc_worker_thread( void *obj ) { filter_t* p_filter = (filter_t*)obj; filter_sys_t *p_sys = p_filter->p_sys; vlc_thread_t update_thread; int canc = vlc_savecancel (); msg_Dbg( p_filter, "VNC worker thread started" ); int fd = vnc_connect( p_filter ); if( fd == -1 ) { msg_Err( p_filter, "Error occurred while handshaking VNC host" ); return NULL; } /* Create an empty picture for VNC the data */ picture_t *pic = picture_New( VLC_CODEC_YUVA, p_sys->i_vnc_width, p_sys->i_vnc_height, 1, 1 ); if( likely(pic != NULL) ) { vlc_mutex_lock( &p_sys->lock ); p_sys->i_socket = fd; p_sys->p_pic = pic; vlc_mutex_unlock( &p_sys->lock ); } else { net_Close( fd ); return NULL; } write_update_request( p_filter, false ); /* create the update request thread */ bool polling = var_InheritBool( p_filter, RMTOSD_CFG "vnc-polling" ); if( polling && vlc_clone( &update_thread, update_request_thread, p_filter, VLC_THREAD_PRIORITY_LOW ) ) { msg_Err( p_filter, "cannot spawn VNC update request thread" ); polling = false; } vlc_cleanup_push( polling ? update_thread_cleanup : dummy_cleanup, &update_thread ); /* connection is initialized, now read and handle server messages */ for( ;; ) { rfbServerToClientMsg msg; int i_msgSize; memset( &msg, 0, sizeof(msg) ); vlc_restorecancel (canc); if( !read_exact(p_filter, fd, &msg, 1 ) ) { msg_Err( p_filter, "Error while waiting for next server message"); break; } switch (msg.type) { case rfbFramebufferUpdate: i_msgSize = sz_rfbFramebufferUpdateMsg; break; case rfbSetColourMapEntries: i_msgSize = sz_rfbSetColourMapEntriesMsg; break; case rfbBell: i_msgSize = sz_rfbBellMsg; break; case rfbServerCutText: i_msgSize = sz_rfbServerCutTextMsg; break; case rfbReSizeFrameBuffer: i_msgSize = sz_rfbReSizeFrameBufferMsg; break; default: i_msgSize = 0; msg_Err( p_filter, "Invalid message %u received", msg.type ); break; } if( i_msgSize <= 0 ) break; if( --i_msgSize > 0 ) { if ( !read_exact( p_filter, fd, ((char *)&msg) + 1, i_msgSize ) ) { msg_Err( p_filter, "Error while reading message of type %u", msg.type ); break; } } canc = vlc_savecancel (); process_server_message( p_filter, &msg); } vlc_cleanup_pop(); if( polling ) update_thread_cleanup( &update_thread ); msg_Dbg( p_filter, "VNC message reader thread ended" ); vlc_restorecancel (canc); return NULL; }
/***************************************************************************** * Run : call Handshake() then submit songs *****************************************************************************/ static void *Run(void *data) { intf_thread_t *p_intf = data; uint8_t p_buffer[1024]; int canc = vlc_savecancel(); bool b_handshaked = false; bool b_nowp_submission_ongoing = false; /* data about audioscrobbler session */ mtime_t next_exchange = 0; /**< when can we send data */ unsigned int i_interval = 0; /**< waiting interval (secs)*/ intf_sys_t *p_sys = p_intf->p_sys; /* main loop */ for (;;) { vlc_restorecancel(canc); mwait(next_exchange); vlc_mutex_lock(&p_sys->lock); mutex_cleanup_push(&p_sys->lock); while (p_sys->i_songs == 0 && p_sys->b_submit_nowp == false) vlc_cond_wait(&p_sys->wait, &p_sys->lock); vlc_cleanup_pop(); vlc_mutex_unlock(&p_sys->lock); canc = vlc_savecancel(); /* handshake if needed */ if (!b_handshaked) { msg_Dbg(p_intf, "Handshaking with last.fm ..."); switch(Handshake(p_intf)) { case VLC_ENOMEM: goto out; case VLC_ENOVAR: /* username not set */ vlc_dialog_display_error(p_intf, _("Last.fm username not set"), "%s", _("Please set a username or disable the " "audioscrobbler plugin, and restart VLC.\n" "Visit http://www.last.fm/join/ to get an account.")); goto out; case VLC_SUCCESS: msg_Dbg(p_intf, "Handshake successful :)"); b_handshaked = true; i_interval = 0; next_exchange = 0; break; case VLC_AUDIOSCROBBLER_EFATAL: msg_Warn(p_intf, "Exiting..."); goto out; case VLC_EGENERIC: default: /* protocol error : we'll try later */ HandleInterval(&next_exchange, &i_interval); break; } /* if handshake failed let's restart the loop */ if (!b_handshaked) continue; } msg_Dbg(p_intf, "Going to submit some data..."); char *psz_submit; vlc_url_t *url; char *psz_submit_song, *psz_submit_tmp; if (asprintf(&psz_submit, "s=%s", p_sys->psz_auth_token) == -1) break; /* forge the HTTP POST request */ vlc_mutex_lock(&p_sys->lock); if (p_sys->b_submit_nowp) { b_nowp_submission_ongoing = true; url = &p_sys->p_nowp_url; if (asprintf(&psz_submit_song, "&a=%s" "&t=%s" "&b=%s" "&l=%d" "&n=%s" "&m=%s", p_sys->p_current_song.psz_a, p_sys->p_current_song.psz_t, p_sys->p_current_song.psz_b ? p_sys->p_current_song.psz_b : "", p_sys->p_current_song.i_l, p_sys->p_current_song.psz_n ? p_sys->p_current_song.psz_n : "", p_sys->p_current_song.psz_m ? p_sys->p_current_song.psz_m : "" ) == -1) { /* Out of memory */ vlc_mutex_unlock(&p_sys->lock); goto out; } } else { url = &p_sys->p_submit_url; audioscrobbler_song_t *p_song; for (int i_song = 0 ; i_song < p_sys->i_songs ; i_song++) { p_song = &p_sys->p_queue[i_song]; if (asprintf(&psz_submit_song, "&a%%5B%d%%5D=%s" "&t%%5B%d%%5D=%s" "&i%%5B%d%%5D=%u" "&o%%5B%d%%5D=P" "&r%%5B%d%%5D=" "&l%%5B%d%%5D=%d" "&b%%5B%d%%5D=%s" "&n%%5B%d%%5D=%s" "&m%%5B%d%%5D=%s", i_song, p_song->psz_a, i_song, p_song->psz_t, i_song, (unsigned)p_song->date, /* HACK: %ju (uintmax_t) unsupported on Windows */ i_song, i_song, i_song, p_song->i_l, i_song, p_song->psz_b ? p_song->psz_b : "", i_song, p_song->psz_n ? p_song->psz_n : "", i_song, p_song->psz_m ? p_song->psz_m : "" ) == -1) { /* Out of memory */ vlc_mutex_unlock(&p_sys->lock); goto out; } } } psz_submit_tmp = psz_submit; int print_ret = asprintf(&psz_submit, "%s%s", psz_submit_tmp, psz_submit_song); free(psz_submit_tmp); free(psz_submit_song); vlc_mutex_unlock(&p_sys->lock); if (print_ret == -1) { /* Out of memory */ goto out; } int i_post_socket = net_ConnectTCP(p_intf, url->psz_host, url->i_port); if (i_post_socket == -1) { /* If connection fails, we assume we must handshake again */ HandleInterval(&next_exchange, &i_interval); b_handshaked = false; free(psz_submit); continue; } /* we transmit the data */ int i_net_ret = net_Printf(p_intf, i_post_socket, "POST %s HTTP/1.1\r\n" "Host: %s\r\n" "User-Agent: "PACKAGE_NAME"/"PACKAGE_VERSION"\r\n" "Connection: close\r\n" "Accept-Encoding: identity\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %zu\r\n" "\r\n" "%s\r\n" "\r\n", url->psz_path, url->psz_host, strlen(psz_submit), psz_submit); free(psz_submit); if (i_net_ret == -1) { /* If connection fails, we assume we must handshake again */ HandleInterval(&next_exchange, &i_interval); b_handshaked = false; net_Close(i_post_socket); continue; } /* FIXME: this might wait forever */ struct pollfd ufd = { .fd = i_post_socket, .events = POLLIN }; while( poll( &ufd, 1, -1 ) == -1 ); /* FIXME: With TCP, you should never assume that a single read will * return the entire response... */ i_net_ret = recv(i_post_socket, p_buffer, sizeof(p_buffer) - 1, 0); if (i_net_ret <= 0) { /* if we get no answer, something went wrong : try again */ net_Close(i_post_socket); continue; } net_Close(i_post_socket); p_buffer[i_net_ret] = '\0'; char *failed = strstr((char *) p_buffer, "FAILED"); if (failed) { msg_Warn(p_intf, "%s", failed); HandleInterval(&next_exchange, &i_interval); continue; } if (strstr((char *) p_buffer, "BADSESSION")) { msg_Err(p_intf, "Authentication failed (BADSESSION), are you connected to last.fm with another program ?"); b_handshaked = false; HandleInterval(&next_exchange, &i_interval); continue; } if (strstr((char *) p_buffer, "OK")) { if (b_nowp_submission_ongoing) { b_nowp_submission_ongoing = false; p_sys->b_submit_nowp = false; } else { for (int i = 0; i < p_sys->i_songs; i++) DeleteSong(&p_sys->p_queue[i]); p_sys->i_songs = 0; } i_interval = 0; next_exchange = 0; msg_Dbg(p_intf, "Submission successful!"); } else { msg_Err(p_intf, "Authentication failed, handshaking again (%s)", p_buffer); b_handshaked = false; HandleInterval(&next_exchange, &i_interval); } } out: vlc_restorecancel(canc); return NULL; }
/***************************************************************************** * ThreadWrite: Write a packet on the network at the good time. *****************************************************************************/ static void* ThreadWrite( void *data ) { sout_access_out_t *p_access = data; sout_access_out_sys_t *p_sys = p_access->p_sys; mtime_t i_date_last = -1; const unsigned i_group = var_GetInteger( p_access, SOUT_CFG_PREFIX "group" ); mtime_t i_to_send = i_group; unsigned i_dropped_packets = 0; for (;;) { block_t *p_pk = block_FifoGet( p_sys->p_fifo ); mtime_t i_date, i_sent; i_date = p_sys->i_caching + p_pk->i_dts; if( i_date_last > 0 ) { if( i_date - i_date_last > 2000000 ) { if( !i_dropped_packets ) msg_Dbg( p_access, "mmh, hole (%"PRId64" > 2s) -> drop", i_date - i_date_last ); block_FifoPut( p_sys->p_empty_blocks, p_pk ); i_date_last = i_date; i_dropped_packets++; continue; } else if( i_date - i_date_last < -1000 ) { if( !i_dropped_packets ) msg_Dbg( p_access, "mmh, packets in the past (%"PRId64")", i_date_last - i_date ); } } block_cleanup_push( p_pk ); i_to_send--; if( !i_to_send || (p_pk->i_flags & BLOCK_FLAG_CLOCK) ) { mwait( i_date ); i_to_send = i_group; } if ( send( p_sys->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 ) == -1 ) msg_Warn( p_access, "send error: %s", vlc_strerror_c(errno) ); vlc_cleanup_pop(); if( i_dropped_packets ) { msg_Dbg( p_access, "dropped %i packets", i_dropped_packets ); i_dropped_packets = 0; } #if 1 i_sent = mdate(); if ( i_sent > i_date + 20000 ) { msg_Dbg( p_access, "packet has been sent too late (%"PRId64 ")", i_sent - i_date ); } #endif block_FifoPut( p_sys->p_empty_blocks, p_pk ); i_date_last = i_date; } return NULL; }
static void *Thread (void *data) { stream_t *stream = data; stream_sys_t *p_sys = stream->p_sys; #ifdef HAVE_VMSPLICE const ssize_t page_mask = sysconf (_SC_PAGE_SIZE) - 1; #endif int fd = p_sys->write_fd; bool error = false; sigset_t set; sigemptyset(&set); sigaddset(&set, SIGPIPE); pthread_sigmask(SIG_BLOCK, &set, NULL); do { ssize_t len; int canc = vlc_savecancel (); #ifdef HAVE_VMSPLICE unsigned char *buf = mmap (NULL, bufsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (unlikely(buf == MAP_FAILED)) break; vlc_cleanup_push (cleanup_mmap, buf); #else unsigned char *buf = malloc (bufsize); if (unlikely(buf == NULL)) break; vlc_cleanup_push (free, buf); #endif vlc_mutex_lock (&p_sys->lock); while (p_sys->paused) /* practically always false, but... */ vlc_cond_wait (&p_sys->wait, &p_sys->lock); len = stream_Read (stream->p_source, buf, bufsize); vlc_mutex_unlock (&p_sys->lock); vlc_restorecancel (canc); error = len <= 0; for (ssize_t i = 0, j; i < len; i += j) { #ifdef HAVE_VMSPLICE if ((len - i) <= page_mask) /* incomplete last page */ j = write (fd, buf + i, len - i); else { struct iovec iov = { buf + i, (len - i) & ~page_mask, }; j = vmsplice (fd, &iov, 1, SPLICE_F_GIFT); } if (j == -1 && errno == ENOSYS) /* vmsplice() not supported */ #endif j = write (fd, buf + i, len - i); if (j <= 0) { if (j == 0) errno = EPIPE; msg_Err (stream, "cannot write data: %s", vlc_strerror_c(errno)); error = true; break; } } vlc_cleanup_pop (); #ifdef HAVE_VMSPLICE munmap (buf, bufsize); #else free (buf); #endif } while (!error); msg_Dbg (stream, "compressed stream at EOF"); /* Let child process know about EOF */ p_sys->write_fd = -1; close (fd); return NULL; }
/** * RTP/RTCP session thread for datagram sockets */ void *rtp_dgram_thread (void *opaque) { demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; mtime_t deadline = VLC_TS_INVALID; int rtp_fd = sys->fd; struct iovec iov = { .iov_len = DEFAULT_MRU, }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, }; struct pollfd ufd[1]; ufd[0].fd = rtp_fd; ufd[0].events = POLLIN; for (;;) { int n = poll (ufd, 1, rtp_timeout (deadline)); if (n == -1) continue; int canc = vlc_savecancel (); if (n == 0) goto dequeue; if (ufd[0].revents) { n--; if (unlikely(ufd[0].revents & POLLHUP)) break; /* RTP socket dead (DCCP only) */ block_t *block = block_Alloc (iov.iov_len); if (unlikely(block == NULL)) { if (iov.iov_len == DEFAULT_MRU) break; /* we are totallly screwed */ iov.iov_len = DEFAULT_MRU; continue; /* retry with shrunk MRU */ } iov.iov_base = block->p_buffer; #ifdef __linux__ msg.msg_flags = MSG_TRUNC; #else msg.msg_flags = 0; #endif ssize_t len = recvmsg (rtp_fd, &msg, 0); if (len != -1) { #ifdef MSG_TRUNC if (msg.msg_flags & MSG_TRUNC) { msg_Err(demux, "%zd bytes packet truncated (MRU was %zu)", len, iov.iov_len); block->i_flags |= BLOCK_FLAG_CORRUPTED; iov.iov_len = len; } else #endif block->i_buffer = len; rtp_process (demux, block); } else { msg_Warn (demux, "RTP network error: %s", vlc_strerror_c(errno)); block_Release (block); } } dequeue: if (!rtp_dequeue (demux, sys->session, &deadline)) deadline = VLC_TS_INVALID; vlc_restorecancel (canc); } return NULL; } /** * RTP/RTCP session thread for stream sockets (framed RTP) */ void *rtp_stream_thread (void *opaque) { #ifndef _WIN32 demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; int fd = sys->fd; for (;;) { /* There is no reordering on stream sockets, so no timeout. */ ssize_t val; uint16_t frame_len; if (recv (fd, &frame_len, 2, MSG_WAITALL) != 2) break; block_t *block = block_Alloc (ntohs (frame_len)); if (unlikely(block == NULL)) break; block_cleanup_push (block); val = recv (fd, block->p_buffer, block->i_buffer, MSG_WAITALL); vlc_cleanup_pop (); if (val != (ssize_t)block->i_buffer) { block_Release (block); break; } int canc = vlc_savecancel (); rtp_process (demux, block); rtp_dequeue_force (demux, sys->session); vlc_restorecancel (canc); } #else (void) opaque; #endif return NULL; }
/***************************************************************************** * Run : call Handshake() then submit songs *****************************************************************************/ static void *Run(void *data) { intf_thread_t *p_intf = data; uint8_t p_buffer[1024]; int canc = vlc_savecancel(); bool b_handshaked = false; bool b_nowp_submission_ongoing = false; /* data about audioscrobbler session */ vlc_tick_t next_exchange = VLC_TICK_INVALID; /**< when can we send data */ unsigned int i_interval = 0; /**< waiting interval (secs)*/ intf_sys_t *p_sys = p_intf->p_sys; /* main loop */ for (;;) { vlc_restorecancel(canc); if (next_exchange != VLC_TICK_INVALID) vlc_tick_wait(next_exchange); vlc_mutex_lock(&p_sys->lock); mutex_cleanup_push(&p_sys->lock); while (p_sys->i_songs == 0 && p_sys->b_submit_nowp == false) vlc_cond_wait(&p_sys->wait, &p_sys->lock); vlc_cleanup_pop(); vlc_mutex_unlock(&p_sys->lock); canc = vlc_savecancel(); /* handshake if needed */ if (!b_handshaked) { msg_Dbg(p_intf, "Handshaking with last.fm ..."); switch(Handshake(p_intf)) { case VLC_ENOMEM: goto out; case VLC_ENOVAR: /* username not set */ vlc_dialog_display_error(p_intf, _("Last.fm username not set"), "%s", _("Please set a username or disable the " "audioscrobbler plugin, and restart VLC.\n" "Visit http://www.last.fm/join/ to get an account.")); goto out; case VLC_SUCCESS: msg_Dbg(p_intf, "Handshake successful :)"); b_handshaked = true; i_interval = 0; next_exchange = VLC_TICK_INVALID; break; case VLC_AUDIOSCROBBLER_EFATAL: msg_Warn(p_intf, "Exiting..."); goto out; case VLC_EGENERIC: default: /* protocol error : we'll try later */ HandleInterval(&next_exchange, &i_interval); break; } /* if handshake failed let's restart the loop */ if (!b_handshaked) continue; } msg_Dbg(p_intf, "Going to submit some data..."); vlc_url_t *url; struct vlc_memstream req, payload; vlc_memstream_open(&payload); vlc_memstream_printf(&payload, "s=%s", p_sys->psz_auth_token); /* forge the HTTP POST request */ vlc_mutex_lock(&p_sys->lock); if (p_sys->b_submit_nowp) { audioscrobbler_song_t *p_song = &p_sys->p_current_song; b_nowp_submission_ongoing = true; url = &p_sys->p_nowp_url; vlc_memstream_printf(&payload, "&a=%s", p_song->psz_a); vlc_memstream_printf(&payload, "&t=%s", p_song->psz_t); vlc_memstream_puts(&payload, "&b="); if (p_song->psz_b != NULL) vlc_memstream_puts(&payload, p_song->psz_b); vlc_memstream_printf(&payload, "&l=%d", p_song->i_l); vlc_memstream_puts(&payload, "&n="); if (p_song->psz_n != NULL) vlc_memstream_puts(&payload, p_song->psz_n); vlc_memstream_puts(&payload, "&m="); if (p_song->psz_m != NULL) vlc_memstream_puts(&payload, p_song->psz_m); } else { url = &p_sys->p_submit_url; for (int i_song = 0 ; i_song < p_sys->i_songs ; i_song++) { audioscrobbler_song_t *p_song = &p_sys->p_queue[i_song]; vlc_memstream_printf(&payload, "&a%%5B%d%%5D=%s", i_song, p_song->psz_a); vlc_memstream_printf(&payload, "&t%%5B%d%%5D=%s", i_song, p_song->psz_t); vlc_memstream_printf(&payload, "&i%%5B%d%%5D=%"PRIu64, i_song, (uint64_t)p_song->date); vlc_memstream_printf(&payload, "&o%%5B%d%%5D=P", i_song); vlc_memstream_printf(&payload, "&r%%5B%d%%5D=", i_song); vlc_memstream_printf(&payload, "&l%%5B%d%%5D=%d", i_song, p_song->i_l); vlc_memstream_printf(&payload, "&b=%%5B%d%%5D=", i_song); if (p_song->psz_b != NULL) vlc_memstream_puts(&payload, p_song->psz_b); vlc_memstream_printf(&payload, "&n=%%5B%d%%5D=", i_song); if (p_song->psz_n != NULL) vlc_memstream_puts(&payload, p_song->psz_n); vlc_memstream_printf(&payload, "&m=%%5B%d%%5D=", i_song); if (p_song->psz_m != NULL) vlc_memstream_puts(&payload, p_song->psz_m); } } vlc_mutex_unlock(&p_sys->lock); if (vlc_memstream_close(&payload)) goto out; vlc_memstream_open(&req); vlc_memstream_printf(&req, "POST %s HTTP/1.1\r\n", url->psz_path); vlc_memstream_printf(&req, "Host: %s\r\n", url->psz_host); vlc_memstream_puts(&req, "User-Agent:" " "PACKAGE_NAME"/"PACKAGE_VERSION"\r\n"); vlc_memstream_puts(&req, "Connection: close\r\n"); vlc_memstream_puts(&req, "Accept-Encoding: identity\r\n"); vlc_memstream_puts(&req, "Content-Type:" " application/x-www-form-urlencoded\r\n"); vlc_memstream_printf(&req, "Content-Length: %zu\r\n", payload.length); vlc_memstream_puts(&req, "\r\n"); /* Could avoid copying payload with iovec... but efforts */ vlc_memstream_write(&req, payload.ptr, payload.length); vlc_memstream_puts(&req, "\r\n\r\n"); free(payload.ptr); if (vlc_memstream_close(&req)) /* Out of memory */ goto out; vlc_tls_t *sock = vlc_tls_SocketOpenTCP(VLC_OBJECT(p_intf), url->psz_host, url->i_port); if (sock == NULL) { /* If connection fails, we assume we must handshake again */ HandleInterval(&next_exchange, &i_interval); b_handshaked = false; free(req.ptr); continue; } /* we transmit the data */ int i_net_ret = vlc_tls_Write(sock, req.ptr, req.length); free(req.ptr); if (i_net_ret == -1) { /* If connection fails, we assume we must handshake again */ HandleInterval(&next_exchange, &i_interval); b_handshaked = false; vlc_tls_Close(sock); continue; } /* FIXME: this might wait forever */ /* FIXME: With TCP, you should never assume that a single read will * return the entire response... */ i_net_ret = vlc_tls_Read(sock, p_buffer, sizeof(p_buffer) - 1, false); vlc_tls_Close(sock); if (i_net_ret <= 0) { /* if we get no answer, something went wrong : try again */ continue; } p_buffer[i_net_ret] = '\0'; char *failed = strstr((char *) p_buffer, "FAILED"); if (failed) { msg_Warn(p_intf, "%s", failed); HandleInterval(&next_exchange, &i_interval); continue; } if (strstr((char *) p_buffer, "BADSESSION")) { msg_Err(p_intf, "Authentication failed (BADSESSION), are you connected to last.fm with another program ?"); b_handshaked = false; HandleInterval(&next_exchange, &i_interval); continue; } if (strstr((char *) p_buffer, "OK")) { if (b_nowp_submission_ongoing) { b_nowp_submission_ongoing = false; p_sys->b_submit_nowp = false; } else { for (int i = 0; i < p_sys->i_songs; i++) DeleteSong(&p_sys->p_queue[i]); p_sys->i_songs = 0; } i_interval = 0; next_exchange = VLC_TICK_INVALID; msg_Dbg(p_intf, "Submission successful!"); } else { msg_Err(p_intf, "Authentication failed, handshaking again (%s)", p_buffer); b_handshaked = false; HandleInterval(&next_exchange, &i_interval); } } out: vlc_restorecancel(canc); return NULL; }