static void Deactivate(vlc_object_t *p_this) { intf_thread_t *p_intf = (intf_thread_t*)p_this; intf_sys_t *p_sys = p_intf->p_sys; net_ListenClose(p_sys->pi_socket); if(p_sys->i_socket != -1) net_Close(p_sys->i_socket); vlc_mutex_destroy(&p_sys->o_write_lock); close(p_sys->i_wakeup[0]); close(p_sys->i_wakeup[1]); free(p_sys); }
/** * Releases resources */ static void Close (vlc_object_t *obj) { demux_t *demux = (demux_t *)obj; demux_sys_t *p_sys = demux->p_sys; if (p_sys->thread_ready) { vlc_cancel (p_sys->thread); vlc_join (p_sys->thread, NULL); } #ifdef HAVE_SRTP if (p_sys->srtp) srtp_destroy (p_sys->srtp); #endif if (p_sys->session) rtp_session_destroy (demux, p_sys->session); if (p_sys->rtcp_fd != -1) net_Close (p_sys->rtcp_fd); net_Close (p_sys->fd); free (p_sys); }
/***************************************************************************** * Close: close the target *****************************************************************************/ static void Close( vlc_object_t * p_this ) { sout_access_out_t *p_access = (sout_access_out_t*)p_this; sout_access_out_sys_t *p_sys = p_access->p_sys; vlc_cancel( p_sys->thread ); vlc_join( p_sys->thread, NULL ); block_FifoRelease( p_sys->p_fifo ); block_FifoRelease( p_sys->p_empty_blocks ); if( p_sys->p_buffer ) block_Release( p_sys->p_buffer ); net_Close( p_sys->i_handle ); free( p_sys ); }
/***************************************************************************** * Close: destroy interface *****************************************************************************/ void Close(vlc_object_t *object) { intf_thread_t *intf = (intf_thread_t*)object; intf_sys_t *sys = intf->p_sys; var_DelCallback(sys->playlist, "input-current", PlaylistEvent, intf); if (sys->input != NULL) { vlc_cancel(sys->thread); vlc_join(sys->thread, NULL); } net_Close(sys->fd); free(sys); }
/** * Destroy the SAP handler * \param p_this the SAP Handler to destroy * \return nothing */ void announce_SAPHandlerDestroy( sap_handler_t *p_sap ) { int i; vlc_mutex_destroy( &p_sap->object_lock ); /* Free the remaining sessions */ for( i = 0 ; i< p_sap->i_sessions ; i++) { sap_session_t *p_session = p_sap->pp_sessions[i]; FREE( p_session->psz_sdp ); FREE( p_session->psz_data ); REMOVE_ELEM( p_sap->pp_sessions, p_sap->i_sessions , i ); FREE( p_session ); } /* Free the remaining addresses */ for( i = 0 ; i< p_sap->i_addresses ; i++) { sap_address_t *p_address = p_sap->pp_addresses[i]; FREE( p_address->psz_address ); if( p_address->i_rfd > -1 ) { net_Close( p_address->i_rfd ); } if( p_address->i_wfd > -1 && p_sap->b_control ) { net_Close( p_address->i_wfd ); } REMOVE_ELEM( p_sap->pp_addresses, p_sap->i_addresses, i ); FREE( p_address ); } /* Free the structure */ vlc_object_destroy( p_sap ); }
static int Open (vlc_object_t *obj) { access_t *access = (access_t *)obj; vlc_url_t url; vlc_UrlParse (&url, access->psz_location, 0); int fd = net_ConnectTCP (obj, url.psz_host, url.i_port ? url.i_port : IPPORT_HTCPCP); if (fd == -1) { vlc_UrlClean (&url); return VLC_EGENERIC; } access_sys_t *sys = malloc (sizeof (*sys)); if (unlikely(sys == NULL)) goto error; sys->fd = fd; net_Printf (obj, fd, NULL, "BREW %s HTTP/1.1\r\n", url.psz_path ? url.psz_path : "/"); if (url.i_port) net_Printf (obj, fd, NULL, "Host: %s:%u\r\n", url.psz_host, url.i_port); else net_Printf (obj, fd, NULL, "Host: %s\r\n", url.psz_host); net_Printf (obj, fd, NULL, "User-Agent: "PACKAGE_NAME"/"PACKAGE_VERSION"\r\n" "Accept-Additions: \r\n" "Content-Type: application/coffee-pot-command\r\n" "Content-Length: 0\r\n" "\r\n"); vlc_UrlClean (&url); access->p_sys = sys; access->pf_read = Read; access->pf_seek = Seek; access->pf_control = Control; return VLC_SUCCESS; error: net_Close (fd); free (sys); vlc_UrlClean (&url); return VLC_EGENERIC; }
/***************************************************************************** * Activate: initialize and create stuff *****************************************************************************/ static int Open(vlc_object_t *object) { intf_thread_t *intf = (intf_thread_t*)object; intf_sys_t *sys; int fd; if (!var_InheritBool(intf, "netsync-master")) { char *psz_master = var_InheritString(intf, "netsync-master-ip"); if (psz_master == NULL) { msg_Err(intf, "master address not specified"); return VLC_EGENERIC; } fd = net_ConnectUDP(VLC_OBJECT(intf), psz_master, NETSYNC_PORT, -1); free(psz_master); } else { fd = net_ListenUDP1(VLC_OBJECT(intf), NULL, NETSYNC_PORT); } if (fd == -1) { msg_Err(intf, "Netsync socket failure"); return VLC_EGENERIC; } intf->pf_run = NULL; intf->p_sys = sys = malloc(sizeof(*sys)); if (!sys) { net_Close(fd); return VLC_ENOMEM; } sys->fd = fd; sys->is_master = var_InheritBool(intf, "netsync-master"); sys->timeout = var_InheritInteger(intf, "netsync-timeout"); if (sys->timeout < 500) sys->timeout = 500; sys->playlist = pl_Get(intf); sys->input = NULL; var_AddCallback(sys->playlist, "input-current", PlaylistEvent, intf); return VLC_SUCCESS; }
/***************************************************************************** * Close: *****************************************************************************/ static void Close( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t*)p_this; intf_sys_t *p_sys = p_intf->p_sys; int i; for( i = 0; i < p_sys->i_clients; i++ ) { telnet_client_t *cl = p_sys->clients[i]; net_Close( cl->fd ); free( cl ); } if( p_sys->clients != NULL ) free( p_sys->clients ); net_ListenClose( p_sys->pi_fd ); vlm_Delete( p_sys->mediatheque ); free( p_sys ); }
void RtspDelId( rtsp_stream_t *rtsp, rtsp_stream_id_t *id ) { vlc_mutex_lock( &rtsp->lock ); for( int i = 0; i < rtsp->sessionc; i++ ) { rtsp_session_t *ses = rtsp->sessionv[i]; for( int j = 0; j < ses->trackc; j++ ) { if( ses->trackv[j].id == id->sout_id ) { rtsp_strack_t *tr = ses->trackv + j; net_Close( tr->fd ); REMOVE_ELEM( ses->trackv, ses->trackc, j ); } } } vlc_mutex_unlock( &rtsp->lock ); httpd_UrlDelete( id->url ); free( id ); }
/***************************************************************************** * DestroyFilter: Make a clean exit of this plugin *****************************************************************************/ static void DestroyFilter( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t*)p_this; filter_sys_t *p_sys = p_filter->p_sys; msg_Dbg( p_filter, "DestroyFilter called." ); if( p_sys->b_vnc_key_events ) var_DelCallback( p_filter->p_libvlc, "key-pressed", KeyEvent, p_this ); vlc_cancel( p_sys->worker_thread ); vlc_join( p_sys->worker_thread, NULL ); if( p_sys->p_pic != NULL ) picture_Release( p_sys->p_pic ); if( p_sys->i_socket >= 0 ) net_Close( p_sys->i_socket ); vlc_mutex_destroy( &p_sys->lock ); free( p_sys->psz_host ); free( p_sys->psz_passwd ); free( p_sys ); }
/** * @brief Connect to the Chromecast * @param p_stream the sout_stream_t structure * @return the opened socket file descriptor or -1 on error */ int intf_sys_t::connectChromecast(char *psz_ipChromecast) { int fd = net_ConnectTCP(p_stream, psz_ipChromecast, CHROMECAST_CONTROL_PORT); if (fd < 0) return -1; p_creds = vlc_tls_ClientCreate(VLC_OBJECT(p_stream)); if (p_creds == NULL) { net_Close(fd); return -1; } p_tls = vlc_tls_ClientSessionCreate(p_creds, fd, psz_ipChromecast, "tcps", NULL, NULL); if (p_tls == NULL) { vlc_tls_Delete(p_creds); return -1; } return fd; }
/***************************************************************************** * Run: main loop *****************************************************************************/ static void Run( intf_thread_t *p_intf ) { intf_sys_t *p_sys = p_intf->p_sys; struct timeval timeout; char *psz_password; psz_password = config_GetPsz( p_intf, "telnet-password" ); while( !p_intf->b_die ) { fd_set fds_read, fds_write; int i_handle_max = 0; int i_ret, i_len, fd, i; /* if a new client wants to communicate */ fd = net_Accept( p_intf, p_sys->pi_fd, p_sys->i_clients > 0 ? 0 : -1 ); if( fd > 0 ) { telnet_client_t *cl; /* to be non blocking */ #if defined( WIN32 ) || defined( UNDER_CE ) { unsigned long i_dummy = 1; ioctlsocket( fd, FIONBIO, &i_dummy ); } #else fcntl( fd, F_SETFL, O_NONBLOCK ); #endif cl = malloc( sizeof( telnet_client_t )); cl->i_tel_cmd = 0; cl->fd = fd; cl->buffer_write = NULL; cl->p_buffer_write = cl->buffer_write; Write_message( cl, NULL, "Password: \xff\xfb\x01", WRITE_MODE_PWD ); TAB_APPEND( p_sys->i_clients, p_sys->clients, cl ); } /* to do a proper select */ FD_ZERO( &fds_read ); FD_ZERO( &fds_write ); for( i = 0 ; i < p_sys->i_clients ; i++ ) { telnet_client_t *cl = p_sys->clients[i]; if( cl->i_mode == WRITE_MODE_PWD || cl->i_mode == WRITE_MODE_CMD ) { FD_SET( cl->fd , &fds_write ); } else { FD_SET( cl->fd , &fds_read ); } i_handle_max = __MAX( i_handle_max, cl->fd ); } timeout.tv_sec = 0; timeout.tv_usec = 500*1000; i_ret = select( i_handle_max + 1, &fds_read, &fds_write, 0, &timeout ); if( i_ret == -1 && errno != EINTR ) { msg_Warn( p_intf, "cannot select sockets" ); msleep( 1000 ); continue; } else if( i_ret <= 0 ) { continue; } /* check if there is something to do with the socket */ for( i = 0 ; i < p_sys->i_clients ; i++ ) { telnet_client_t *cl = p_sys->clients[i]; if( FD_ISSET(cl->fd , &fds_write) && cl->i_buffer_write > 0 ) { i_len = send( cl->fd , cl->p_buffer_write , cl->i_buffer_write , 0 ); if( i_len > 0 ) { cl->p_buffer_write += i_len; cl->i_buffer_write -= i_len; } } else if( FD_ISSET( cl->fd, &fds_read) ) { int i_end = 0; int i_recv; while( (i_recv=recv( cl->fd, cl->p_buffer_read, 1, 0 )) > 0 && cl->p_buffer_read - cl->buffer_read < 999 ) { switch( cl->i_tel_cmd ) { case 0: switch( *(uint8_t *)cl->p_buffer_read ) { case '\r': break; case '\n': *cl->p_buffer_read = '\n'; i_end = 1; break; case TEL_IAC: // telnet specific command cl->i_tel_cmd = 1; cl->p_buffer_read++; break; default: cl->p_buffer_read++; break; } break; case 1: switch( *(uint8_t *)cl->p_buffer_read ) { case TEL_WILL: case TEL_WONT: case TEL_DO: case TEL_DONT: cl->i_tel_cmd++; cl->p_buffer_read++; break; default: cl->i_tel_cmd = 0; cl->p_buffer_read--; break; } break; case 2: cl->i_tel_cmd = 0; cl->p_buffer_read -= 2; break; } if( i_end != 0 ) break; } if( cl->p_buffer_read - cl->buffer_read == 999 ) { Write_message( cl, NULL, "Line too long\r\n", cl->i_mode + 2 ); } if( i_recv == 0 || ( i_recv == -1 && errno != EAGAIN && errno != 0 ) ) { net_Close( cl->fd ); TAB_REMOVE( p_intf->p_sys->i_clients , p_intf->p_sys->clients , cl ); free( cl ); } } } /* and now we should bidouille the data we received / send */ for( i = 0 ; i < p_sys->i_clients ; i++ ) { telnet_client_t *cl = p_sys->clients[i]; if( cl->i_mode >= WRITE_MODE_PWD && cl->i_buffer_write == 0 ) { // we have finished to send cl->i_mode -= 2; // corresponding READ MODE } else if( cl->i_mode == READ_MODE_PWD && *cl->p_buffer_read == '\n' ) { *cl->p_buffer_read = '\0'; if( strcmp( psz_password, cl->buffer_read ) == 0 ) { Write_message( cl, NULL, "\xff\xfc\x01\r\nWelcome, " "Master\r\n> ", WRITE_MODE_CMD ); } else { /* wrong password */ Write_message( cl, NULL, "\r\nWrong password.\r\nPassword: "******"logout", 6 ) || !strncmp( cl->buffer_read, "quit", 4 ) || !strncmp( cl->buffer_read, "exit", 4 ) ) { net_Close( cl->fd ); TAB_REMOVE( p_intf->p_sys->i_clients , p_intf->p_sys->clients , cl ); free( cl ); } else if( !strncmp( cl->buffer_read, "shutdown", 8 ) ) { msg_Err( p_intf, "shutdown requested" ); p_intf->p_vlc->b_die = VLC_TRUE; } else { vlm_message_t *message; /* create a standard string */ *cl->p_buffer_read = '\0'; vlm_ExecuteCommand( p_sys->mediatheque, cl->buffer_read, &message ); Write_message( cl, message, NULL, WRITE_MODE_CMD ); vlm_MessageDelete( message ); } } } } }
/** * Probes and initializes. */ static int Open (vlc_object_t *obj) { demux_t *demux = (demux_t *)obj; int tp; /* transport protocol */ if (!strcmp (demux->psz_access, "dccp")) tp = IPPROTO_DCCP; else if (!strcmp (demux->psz_access, "rtptcp")) tp = IPPROTO_TCP; else if (!strcmp (demux->psz_access, "rtp")) tp = IPPROTO_UDP; else if (!strcmp (demux->psz_access, "udplite")) tp = IPPROTO_UDPLITE; else return VLC_EGENERIC; char *tmp = strdup (demux->psz_location); if (tmp == NULL) return VLC_ENOMEM; char *shost; char *dhost = strchr (tmp, '@'); if (dhost != NULL) { *(dhost++) = '\0'; shost = tmp; } else { dhost = tmp; shost = NULL; } /* Parses the port numbers */ int sport = 0, dport = 0; if (shost != NULL) sport = extract_port (&shost); if (dhost != NULL) dport = extract_port (&dhost); if (dport == 0) dport = 5004; /* avt-profile-1 port */ int rtcp_dport = var_CreateGetInteger (obj, "rtcp-port"); /* Try to connect */ int fd = -1, rtcp_fd = -1; switch (tp) { case IPPROTO_UDP: case IPPROTO_UDPLITE: fd = net_OpenDgram (obj, dhost, dport, shost, sport, tp); if (fd == -1) break; if (rtcp_dport > 0) /* XXX: source port is unknown */ rtcp_fd = net_OpenDgram (obj, dhost, rtcp_dport, shost, 0, tp); break; case IPPROTO_DCCP: #ifndef SOCK_DCCP /* provisional API (FIXME) */ # ifdef __linux__ # define SOCK_DCCP 6 # endif #endif #ifdef SOCK_DCCP var_Create (obj, "dccp-service", VLC_VAR_STRING); var_SetString (obj, "dccp-service", "RTPV"); /* FIXME: RTPA? */ fd = net_Connect (obj, dhost, dport, SOCK_DCCP, tp); #else msg_Err (obj, "DCCP support not included"); #endif break; case IPPROTO_TCP: fd = net_Connect (obj, dhost, dport, SOCK_STREAM, tp); break; } free (tmp); if (fd == -1) return VLC_EGENERIC; net_SetCSCov (fd, -1, 12); /* Initializes demux */ demux_sys_t *p_sys = malloc (sizeof (*p_sys)); if (p_sys == NULL) { net_Close (fd); if (rtcp_fd != -1) net_Close (rtcp_fd); return VLC_EGENERIC; } p_sys->chained_demux = NULL; #ifdef HAVE_SRTP p_sys->srtp = NULL; #endif p_sys->fd = fd; p_sys->rtcp_fd = rtcp_fd; p_sys->max_src = var_CreateGetInteger (obj, "rtp-max-src"); p_sys->timeout = var_CreateGetInteger (obj, "rtp-timeout") * CLOCK_FREQ; p_sys->max_dropout = var_CreateGetInteger (obj, "rtp-max-dropout"); p_sys->max_misorder = var_CreateGetInteger (obj, "rtp-max-misorder"); p_sys->thread_ready = false; p_sys->autodetect = true; demux->pf_demux = NULL; demux->pf_control = Control; demux->p_sys = p_sys; p_sys->session = rtp_session_create (demux); if (p_sys->session == NULL) goto error; #ifdef HAVE_SRTP char *key = var_CreateGetNonEmptyString (demux, "srtp-key"); if (key) { vlc_gcrypt_init (); p_sys->srtp = srtp_create (SRTP_ENCR_AES_CM, SRTP_AUTH_HMAC_SHA1, 10, SRTP_PRF_AES_CM, SRTP_RCC_MODE1); if (p_sys->srtp == NULL) { free (key); goto error; } char *salt = var_CreateGetNonEmptyString (demux, "srtp-salt"); int val = srtp_setkeystring (p_sys->srtp, key, salt ? salt : ""); free (salt); free (key); if (val) { msg_Err (obj, "bad SRTP key/salt combination (%s)", vlc_strerror_c(val)); goto error; } } #endif if (vlc_clone (&p_sys->thread, (tp != IPPROTO_TCP) ? rtp_dgram_thread : rtp_stream_thread, demux, VLC_THREAD_PRIORITY_INPUT)) goto error; p_sys->thread_ready = true; return VLC_SUCCESS; error: Close (obj); return VLC_EGENERIC; }
/***************************************************************************** * Open: open the rtmp connection *****************************************************************************/ static int Open( vlc_object_t *p_this ) { sout_access_out_t *p_access = (sout_access_out_t *) p_this; sout_access_out_sys_t *p_sys; char *psz, *p; int length_path, length_media_name; int i; if( !( p_sys = calloc ( 1, sizeof( sout_access_out_sys_t ) ) ) ) return VLC_ENOMEM; p_access->p_sys = p_sys; p_sys->p_thread = vlc_object_create( p_access, sizeof( rtmp_control_thread_t ) ); if( !p_sys->p_thread ) { free( p_sys ); return VLC_ENOMEM; } vlc_object_attach( p_sys->p_thread, p_access ); /* Parse URI - remove spaces */ p = psz = strdup( p_access->psz_path ); while( ( p = strchr( p, ' ' ) ) != NULL ) *p = '+'; vlc_UrlParse( &p_sys->p_thread->url, psz, 0 ); free( psz ); if( p_sys->p_thread->url.psz_host == NULL || *p_sys->p_thread->url.psz_host == '\0' ) { msg_Warn( p_access, "invalid host" ); goto error; } if( p_sys->p_thread->url.i_port <= 0 ) p_sys->p_thread->url.i_port = 1935; if ( p_sys->p_thread->url.psz_path == NULL ) { msg_Warn( p_access, "invalid path" ); goto error; } length_path = strlen( p_sys->p_thread->url.psz_path ); char* psz_tmp = strrchr( p_sys->p_thread->url.psz_path, '/' ); if( !psz_tmp ) goto error; length_media_name = strlen( psz_tmp ) - 1; p_sys->p_thread->psz_application = strndup( p_sys->p_thread->url.psz_path + 1, length_path - length_media_name - 2 ); p_sys->p_thread->psz_media = strdup( p_sys->p_thread->url.psz_path + ( length_path - length_media_name ) ); msg_Dbg( p_access, "rtmp: host='%s' port=%d path='%s'", p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port, p_sys->p_thread->url.psz_path ); if( p_sys->p_thread->url.psz_username && *p_sys->p_thread->url.psz_username ) { msg_Dbg( p_access, " user='******'", p_sys->p_thread->url.psz_username ); } /* Initialize thread variables */ p_sys->p_thread->b_error= 0; p_sys->p_thread->p_fifo_input = block_FifoNew(); p_sys->p_thread->p_empty_blocks = block_FifoNew(); p_sys->p_thread->has_audio = 0; p_sys->p_thread->has_video = 0; p_sys->p_thread->metadata_received = 0; p_sys->p_thread->first_media_packet = 1; p_sys->p_thread->flv_tag_previous_tag_size = 0x00000000; /* FLV_TAG_FIRST_PREVIOUS_TAG_SIZE */ p_sys->p_thread->flv_body = rtmp_body_new( -1 ); p_sys->p_thread->flv_length_body = 0; p_sys->p_thread->chunk_size_recv = 128; /* RTMP_DEFAULT_CHUNK_SIZE */ p_sys->p_thread->chunk_size_send = 128; /* RTMP_DEFAULT_CHUNK_SIZE */ for(i = 0; i < 64; i++) { memset( &p_sys->p_thread->rtmp_headers_recv[i], 0, sizeof( rtmp_packet_t ) ); p_sys->p_thread->rtmp_headers_send[i].length_header = -1; p_sys->p_thread->rtmp_headers_send[i].stream_index = -1; p_sys->p_thread->rtmp_headers_send[i].timestamp = -1; p_sys->p_thread->rtmp_headers_send[i].timestamp_relative = -1; p_sys->p_thread->rtmp_headers_send[i].length_encoded = -1; p_sys->p_thread->rtmp_headers_send[i].length_body = -1; p_sys->p_thread->rtmp_headers_send[i].content_type = -1; p_sys->p_thread->rtmp_headers_send[i].src_dst = -1; p_sys->p_thread->rtmp_headers_send[i].body = NULL; } vlc_cond_init( &p_sys->p_thread->wait ); vlc_mutex_init( &p_sys->p_thread->lock ); p_sys->p_thread->result_connect = 1; /* p_sys->p_thread->result_publish = only used on access */ p_sys->p_thread->result_play = 1; p_sys->p_thread->result_stop = 0; p_sys->p_thread->fd = -1; /* Open connection */ if( var_CreateGetBool( p_access, "rtmp-connect" ) > 0 ) { #if 0 p_sys->p_thread->fd = net_ConnectTCP( p_access, p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port ); #endif msg_Err( p_access, "to be implemented" ); goto error2; } else { int *p_fd_listen; p_sys->active = 0; p_fd_listen = net_ListenTCP( p_access, p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port ); if( p_fd_listen == NULL ) { msg_Warn( p_access, "cannot listen to %s port %i", p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port ); goto error2; } do p_sys->p_thread->fd = net_Accept( p_access, p_fd_listen ); while( p_sys->p_thread->fd == -1 ); net_ListenClose( p_fd_listen ); if( rtmp_handshake_passive( p_this, p_sys->p_thread->fd ) < 0 ) { msg_Err( p_access, "handshake passive failed"); goto error2; } } if( vlc_clone( &p_sys->p_thread->thread, ThreadControl, p_sys->p_thread, VLC_THREAD_PRIORITY_INPUT ) ) { msg_Err( p_access, "cannot spawn rtmp control thread" ); goto error2; } if( !p_sys->active ) { if( rtmp_connect_passive( p_sys->p_thread ) < 0 ) { msg_Err( p_access, "connect passive failed"); vlc_cancel( p_sys->p_thread->thread ); vlc_join( p_sys->p_thread->thread, NULL ); goto error2; } } p_access->pf_write = Write; p_access->pf_seek = Seek; return VLC_SUCCESS; error2: vlc_cond_destroy( &p_sys->p_thread->wait ); vlc_mutex_destroy( &p_sys->p_thread->lock ); free( p_sys->p_thread->psz_application ); free( p_sys->p_thread->psz_media ); if( p_sys->p_thread->fd != -1 ) net_Close( p_sys->p_thread->fd ); error: vlc_UrlClean( &p_sys->p_thread->url ); vlc_object_release( p_sys->p_thread ); free( p_sys ); return VLC_EGENERIC; }
static void cleanup_fd(void *data) { net_Close((intptr_t)data); }
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; /* data about audioscrobbler session */ mtime_t next_exchange = -1; /**< 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); vlc_mutex_lock(&p_sys->lock); mutex_cleanup_push(&p_sys->lock); do vlc_cond_wait(&p_sys->wait, &p_sys->lock); while (mdate() < next_exchange); vlc_cleanup_run(); 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 */ dialog_Fatal(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 = mdate(); 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; if (asprintf(&psz_submit, "s=%s", p_sys->psz_auth_token) == -1) break; /* forge the HTTP POST request */ vlc_mutex_lock(&p_sys->lock); audioscrobbler_song_t *p_song; for (int i_song = 0 ; i_song < p_sys->i_songs ; i_song++) { char *psz_submit_song, *psz_submit_tmp; 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, i_song, p_song->psz_n, i_song, p_song->psz_m ) == -1) { /* Out of memory */ vlc_mutex_unlock(&p_sys->lock); goto out; } psz_submit_tmp = psz_submit; if (asprintf(&psz_submit, "%s%s", psz_submit_tmp, psz_submit_song) == -1) { /* Out of memory */ free(psz_submit_tmp); free(psz_submit_song); vlc_mutex_unlock(&p_sys->lock); goto out; } free(psz_submit_song); free(psz_submit_tmp); } vlc_mutex_unlock(&p_sys->lock); int i_post_socket = net_ConnectTCP(p_intf, p_sys->p_submit_url.psz_host, p_sys->p_submit_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, NULL, "POST %s HTTP/1.1\n" "Accept-Encoding: identity\n" "Content-length: %zu\n" "Connection: close\n" "Content-type: application/x-www-form-urlencoded\n" "Host: %s\n" "User-agent: VLC media player/"VERSION"\r\n" "\r\n" "%s\r\n" "\r\n", p_sys->p_submit_url.psz_path, strlen(psz_submit), p_sys->p_submit_url.psz_host, 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; continue; } i_net_ret = net_Read(p_intf, i_post_socket, NULL, p_buffer, sizeof(p_buffer) - 1, false); if (i_net_ret <= 0) { /* if we get no answer, something went wrong : try again */ 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")) { 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 = mdate(); 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; }
/***************************************************************************** * Open: open the file *****************************************************************************/ static int Open( vlc_object_t *p_this ) { sout_access_out_t *p_access = (sout_access_out_t*)p_this; sout_access_out_sys_t *p_sys; char *psz_dst_addr = NULL; int i_dst_port; int i_handle; config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg ); config_ChainParse( p_access, "", ppsz_core_options, p_access->p_cfg ); if (var_Create (p_access, "dst-port", VLC_VAR_INTEGER) || var_Create (p_access, "src-port", VLC_VAR_INTEGER) || var_Create (p_access, "dst-addr", VLC_VAR_STRING) || var_Create (p_access, "src-addr", VLC_VAR_STRING)) { return VLC_ENOMEM; } if( !( p_sys = malloc ( sizeof( *p_sys ) ) ) ) return VLC_ENOMEM; p_access->p_sys = p_sys; i_dst_port = DEFAULT_PORT; char *psz_parser = psz_dst_addr = strdup( p_access->psz_path ); if( !psz_dst_addr ) { free( p_sys ); return VLC_ENOMEM; } if (psz_parser[0] == '[') psz_parser = strchr (psz_parser, ']'); psz_parser = strchr (psz_parser ? psz_parser : psz_dst_addr, ':'); if (psz_parser != NULL) { *psz_parser++ = '\0'; i_dst_port = atoi (psz_parser); } i_handle = net_ConnectDgram( p_this, psz_dst_addr, i_dst_port, -1, IPPROTO_UDP ); free (psz_dst_addr); if( i_handle == -1 ) { msg_Err( p_access, "failed to create raw UDP socket" ); free (p_sys); return VLC_EGENERIC; } else { char addr[NI_MAXNUMERICHOST]; int port; if (net_GetSockAddress (i_handle, addr, &port) == 0) { msg_Dbg (p_access, "source: %s port %d", addr, port); var_SetString (p_access, "src-addr", addr); var_SetInteger (p_access, "src-port", port); } if (net_GetPeerAddress (i_handle, addr, &port) == 0) { msg_Dbg (p_access, "destination: %s port %d", addr, port); var_SetString (p_access, "dst-addr", addr); var_SetInteger (p_access, "dst-port", port); } } shutdown( i_handle, SHUT_RD ); p_sys->i_caching = UINT64_C(1000) * var_GetInteger( p_access, SOUT_CFG_PREFIX "caching"); p_sys->i_handle = i_handle; p_sys->i_mtu = var_CreateGetInteger( p_this, "mtu" ); p_sys->b_mtu_warning = false; p_sys->p_fifo = block_FifoNew(); p_sys->p_empty_blocks = block_FifoNew(); p_sys->p_buffer = NULL; if( vlc_clone( &p_sys->thread, ThreadWrite, p_access, VLC_THREAD_PRIORITY_HIGHEST ) ) { msg_Err( p_access, "cannot spawn sout access thread" ); block_FifoRelease( p_sys->p_fifo ); block_FifoRelease( p_sys->p_empty_blocks ); net_Close (i_handle); free (p_sys); return VLC_EGENERIC; } p_access->pf_write = Write; p_access->pf_seek = Seek; p_access->pf_control = Control; return VLC_SUCCESS; }
static int vnc_connect( filter_t *p_filter ) { filter_sys_t *p_sys = p_filter->p_sys; int port = var_InheritInteger( p_filter, RMTOSD_CFG "port" ); int fd = net_ConnectTCP( p_filter, p_sys->psz_host, port ); if( fd == -1 ) { msg_Err( p_filter, "Could not connect to VNC host" ); return -1; } msg_Dbg( p_filter, "Reading protocol version" ); rfbProtocolVersionMsg pv; if ( !read_exact( p_filter, fd, pv, sz_rfbProtocolVersionMsg ) ) { msg_Err( p_filter, "Could not read version message" ); goto error; } pv[sz_rfbProtocolVersionMsg] = '\0'; /* pv size is sz_rfbProtocolVersionMsg+1 */ msg_Dbg( p_filter, "Server version is %s", pv ); strncpy(pv, "RFB 003.003\n", sz_rfbProtocolVersionMsg); if( !write_exact(p_filter, fd, pv, sz_rfbProtocolVersionMsg) ) { msg_Err( p_filter, "Could not write version message" ); goto error; } msg_Dbg( p_filter, "Reading authentication scheme" ); uint32_t i_authScheme; if( !read_exact( p_filter, fd, &i_authScheme, 4 ) ) { msg_Err( p_filter, "Could not read authentication scheme" ); goto error; } i_authScheme = htonl(i_authScheme); msg_Dbg( p_filter, "Authentication scheme = %x", i_authScheme ); if ( i_authScheme == rfbConnFailed ) { msg_Err( p_filter, "Connection rejected by server" ); goto error; } if (i_authScheme == rfbVncAuth) { unsigned char challenge[CHALLENGESIZE]; if ( !read_exact( p_filter, fd, challenge, CHALLENGESIZE ) ) { msg_Err( p_filter, "Could not read password challenge" ); goto error; } vnc_encrypt_bytes( challenge, p_sys->psz_passwd ); if( !write_exact(p_filter, fd, challenge, CHALLENGESIZE ) ) { msg_Err( p_filter, "Could not write password" ); goto error; } uint32_t i_authResult; if( !read_exact( p_filter, fd, &i_authResult, 4 ) ) { msg_Err( p_filter, "Could not read authentication result" ); goto error; } i_authResult = htonl(i_authResult); if (i_authResult != rfbVncAuthOK) { msg_Err( p_filter, "VNC authentication failed" ); goto error; } } msg_Dbg( p_filter, "Writing client init message" ); rfbClientInitMsg ci; ci.shared = 1; if( !write_exact( p_filter, fd, &ci, sz_rfbClientInitMsg ) ) { msg_Err( p_filter, "Could not write client init message" ); goto error; } msg_Dbg( p_filter, "Reading server init message" ); rfbServerInitMsg si; if( !read_exact( p_filter, fd, &si, sz_rfbServerInitMsg ) ) { msg_Err( p_filter, "Could not read server init message" ); goto error; } si.framebufferWidth = htons(si.framebufferWidth); si.framebufferHeight = htons(si.framebufferHeight); si.format.redMax = htons(si.format.redMax); si.format.greenMax = htons(si.format.greenMax); si.format.blueMax = htons(si.format.blueMax); p_sys->i_vnc_width = si.framebufferWidth; p_sys->i_vnc_height = si.framebufferHeight; msg_Dbg( p_filter, "Servers preferred pixelformat: " "%ux%u, R(%u),G(%u),B(%u), %u bit, depht=%u, %s", si.framebufferWidth, si.framebufferHeight, si.format.redMax, si.format.greenMax, si.format.blueMax, si.format.bitsPerPixel, si.format.depth, si.format.trueColour ? "TrueColor" : "Not-TrueColor"); uint32_t i_nameLength = htonl(si.nameLength); if( i_nameLength > MAX_VNC_SERVER_NAME_LENGTH ) { msg_Err( p_filter, "Server name too long" ); goto error; } char s_ServerName[MAX_VNC_SERVER_NAME_LENGTH+1]; msg_Dbg( p_filter, "Reading server name with size = %u", i_nameLength ); if( !read_exact( p_filter, fd, s_ServerName, i_nameLength ) ) { msg_Err( p_filter, "Could not read server name" ); goto error; } s_ServerName[i_nameLength] = '\0'; if( strcmp( s_ServerName, "VDR-OSD") == 0 ) { msg_Dbg( p_filter, "Server is a VDR" ); p_sys->b_alpha_from_vnc = true; } else { msg_Dbg( p_filter, "Server is a normal VNC" ); p_sys->b_alpha_from_vnc = false; } msg_Dbg( p_filter, "Server init message read properly" ); msg_Dbg( p_filter, "Server name is %s", s_ServerName ); msg_Dbg( p_filter, "Writing SetPixelFormat message" ); rfbSetPixelFormatMsg sp; sp.type = rfbSetPixelFormat; sp.pad1 = sp.pad2 = 0; sp.format.bitsPerPixel = 8; sp.format.depth = 8 ; sp.format.bigEndian = 1; sp.format.trueColour = 0; sp.format.redMax = htons(31); sp.format.greenMax = htons(31); sp.format.blueMax = htons(31); sp.format.redShift = 10; sp.format.greenShift = 5; sp.format.blueShift = 0; sp.format.pad1 = sp.format.pad2 = 0; if( !write_exact( p_filter, fd, &sp, sz_rfbSetPixelFormatMsg) ) { msg_Err( p_filter, "Could not write SetPixelFormat message" ); goto error; } msg_Dbg( p_filter, "Writing SetEncodings message" ); rfbSetEncodingsMsg se; se.type = rfbSetEncodings; se.pad = 0; se.nEncodings = htons( p_sys->b_alpha_from_vnc ? 3 : 2 ); if( !write_exact( p_filter, fd, &se, sz_rfbSetEncodingsMsg) ) { msg_Err( p_filter, "Could not write SetEncodings message begin" ); goto error; } uint32_t i_encoding; msg_Dbg( p_filter, "Writing SetEncodings rfbEncodingCopyRect" ); i_encoding = htonl(rfbEncodingCopyRect); if( !write_exact( p_filter, fd, &i_encoding, 4) ) { msg_Err( p_filter, "Could not write encoding type rfbEncodingCopyRect." ); goto error; } msg_Dbg( p_filter, "Writing SetEncodings rfbEncodingRRE" ); i_encoding = htonl(rfbEncodingRRE); if( !write_exact(p_filter, fd, &i_encoding, 4) ) { msg_Err( p_filter, "Could not write encoding type rfbEncodingRRE." ); goto error; } if( p_sys->b_alpha_from_vnc ) { msg_Dbg( p_filter, "Writing SetEncodings rfbEncSpecialUseAlpha" ); i_encoding = 0x00F0FFFF; /* rfbEncSpecialUseAlpha is 0xFFFFF000 * before we swap it */ if( !write_exact(p_filter, fd, &i_encoding, 4) ) { msg_Err( p_filter, "Could not write encoding type rfbEncSpecialUseAlpha." ); goto error; } } return fd; error: net_Close( fd ); return -1; }
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_request_thread_handle; int canc = vlc_savecancel (); msg_Dbg( p_filter, "VNC worker thread started" ); if( !open_vnc_connection ( p_filter ) ) { msg_Err( p_filter, "Could not connect to vnc host" ); goto exit; } if( !handshaking ( p_filter ) ) { msg_Err( p_filter, "Error occured while handshaking vnc host" ); goto exit; } p_sys->b_connection_active = true; /* to enable sending key * and mouse events to host */ /* Create an empty picture for VNC the data */ vlc_mutex_lock( &p_sys->lock ); p_sys->p_pic = picture_New( VLC_CODEC_YUVA, p_sys->i_vnc_width, p_sys->i_vnc_height, 1, 1 ); if( !p_sys->p_pic ) { vlc_mutex_unlock( &p_sys->lock ); goto exit; } p_sys->i_vnc_pixels = p_sys->i_vnc_width * p_sys->i_vnc_height; vlc_mutex_unlock( &p_sys->lock ); /* create the update request thread */ if( vlc_clone( &update_request_thread_handle, update_request_thread, p_filter, VLC_THREAD_PRIORITY_LOW ) ) { msg_Err( p_filter, "cannot spawn vnc update request thread" ); goto exit; } /* connection is initialized, now read and handle server messages */ vlc_restorecancel (canc); for( ;; ) { rfbServerToClientMsg msg; int i_msgSize; memset( &msg, 0, sizeof(msg) ); if( !read_exact(p_filter, p_sys->i_socket, (char*)&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, p_sys->i_socket, ((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_restorecancel (canc); } canc = vlc_savecancel (); msg_Dbg( p_filter, "joining update_request_thread" ); vlc_cancel( update_request_thread_handle ); vlc_join( update_request_thread_handle, NULL ); msg_Dbg( p_filter, "released update_request_thread" ); exit: vlc_mutex_lock( &p_sys->lock ); p_sys->b_connection_active = false; if (p_sys->i_socket >= 0) net_Close(p_sys->i_socket); if( p_sys->p_pic ) picture_Release( p_sys->p_pic ); /* It will hide the subtitle */ p_sys->b_continue = false; p_sys->b_need_update = true; vlc_mutex_unlock( &p_sys->lock ); msg_Dbg( p_filter, "VNC message reader thread ended" ); vlc_restorecancel (canc); return NULL; }
/***************************************************************************** * Run : call Handshake() then submit songs *****************************************************************************/ static void Run( intf_thread_t *p_intf ) { char *psz_submit, *psz_submit_song, *psz_submit_tmp; int i_net_ret; int i_song; uint8_t p_buffer[1024]; char *p_buffer_pos; int i_post_socket; int canc = vlc_savecancel(); intf_sys_t *p_sys = p_intf->p_sys; /* main loop */ for( ;; ) { bool b_wait = false; vlc_restorecancel( canc ); vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); if( mdate() < p_sys->next_exchange ) /* wait until we can resubmit, i.e. */ b_wait = vlc_cond_timedwait( &p_sys->wait, &p_sys->lock, p_sys->next_exchange ) == 0; else /* wait for data to submit */ /* we are signaled each time there is a song to submit */ vlc_cond_wait( &p_sys->wait, &p_sys->lock ); vlc_cleanup_run(); canc = vlc_savecancel(); if( b_wait ) continue; /* holding on until next_exchange */ /* handshake if needed */ if( !p_sys->b_handshaked ) { msg_Dbg( p_intf, "Handshaking with last.fm ..." ); switch( Handshake( p_intf ) ) { case VLC_ENOMEM: return; case VLC_ENOVAR: /* username not set */ dialog_Fatal( 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.") ); return; case VLC_SUCCESS: msg_Dbg( p_intf, "Handshake successfull :)" ); p_sys->b_handshaked = true; p_sys->i_interval = 0; p_sys->next_exchange = mdate(); break; case VLC_AUDIOSCROBBLER_EFATAL: msg_Warn( p_intf, "Exiting..." ); return; case VLC_EGENERIC: default: /* protocol error : we'll try later */ HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); break; } /* if handshake failed let's restart the loop */ if( !p_sys->b_handshaked ) continue; } msg_Dbg( p_intf, "Going to submit some data..." ); /* The session may be invalid if there is a trailing \n */ char *psz_ln = strrchr( p_sys->psz_auth_token, '\n' ); if( psz_ln ) *psz_ln = '\0'; if( !asprintf( &psz_submit, "s=%s", p_sys->psz_auth_token ) ) { /* Out of memory */ return; } /* forge the HTTP POST request */ vlc_mutex_lock( &p_sys->lock ); audioscrobbler_song_t *p_song; for( 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, i_song, p_song->psz_n, i_song, p_song->psz_m ) ) { /* Out of memory */ vlc_mutex_unlock( &p_sys->lock ); return; } psz_submit_tmp = psz_submit; if( !asprintf( &psz_submit, "%s%s", psz_submit_tmp, psz_submit_song ) ) { /* Out of memory */ free( psz_submit_tmp ); free( psz_submit_song ); vlc_mutex_unlock( &p_sys->lock ); return; } free( psz_submit_song ); free( psz_submit_tmp ); } vlc_mutex_unlock( &p_sys->lock ); i_post_socket = net_ConnectTCP( p_intf, p_sys->psz_submit_host, p_sys->i_submit_port ); if ( i_post_socket == -1 ) { /* If connection fails, we assume we must handshake again */ HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); p_sys->b_handshaked = false; free( psz_submit ); continue; } /* we transmit the data */ i_net_ret = net_Printf( p_intf, i_post_socket, NULL, POST_REQUEST, p_sys->psz_submit_file, (unsigned)strlen( psz_submit ), p_sys->psz_submit_host, VERSION, psz_submit ); free( psz_submit ); if ( i_net_ret == -1 ) { /* If connection fails, we assume we must handshake again */ HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); p_sys->b_handshaked = false; continue; } i_net_ret = net_Read( p_intf, i_post_socket, NULL, p_buffer, 1023, false ); if ( i_net_ret <= 0 ) { /* if we get no answer, something went wrong : try again */ continue; } net_Close( i_post_socket ); p_buffer[i_net_ret] = '\0'; p_buffer_pos = strstr( ( char * ) p_buffer, "FAILED" ); if ( p_buffer_pos ) { msg_Warn( p_intf, "%s", p_buffer_pos ); HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); continue; } p_buffer_pos = strstr( ( char * ) p_buffer, "BADSESSION" ); if ( p_buffer_pos ) { msg_Err( p_intf, "Authentication failed (BADSESSION), are you connected to last.fm with another program ?" ); p_sys->b_handshaked = false; HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); continue; } p_buffer_pos = strstr( ( char * ) p_buffer, "OK" ); if ( p_buffer_pos ) { int i; for( i = 0; i < p_sys->i_songs; i++ ) DeleteSong( &p_sys->p_queue[i] ); p_sys->i_songs = 0; p_sys->i_interval = 0; p_sys->next_exchange = mdate(); msg_Dbg( p_intf, "Submission successful!" ); } else { msg_Err( p_intf, "Authentication failed, handshaking again (%s)", p_buffer ); p_sys->b_handshaked = false; HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); continue; } } vlc_restorecancel( canc ); }
HtsMessage ReadMessageEx(vlc_object_t *obj, sys_common_t *sys) { char *buf; uint32_t len; ssize_t readSize; if(sys->queue.size()) { HtsMessage res = sys->queue.front(); sys->queue.pop_front(); return res; } if(sys->netfd < 0) { msg_Dbg(obj, "ReadMessage on closed netfd"); return HtsMessage(); } if((readSize = net_Read(obj, sys->netfd, &len, sizeof(len))) != sizeof(len)) { net_Close(sys->netfd); sys->netfd = -1; if(readSize == 0) { msg_Err(obj, "Size Read EOF!"); return HtsMessage(); } else if(readSize < 0) { msg_Err(obj, "Data Read ERROR!"); return HtsMessage(); } msg_Err(obj, "Error reading size: %m"); return HtsMessage(); } len = ntohl(len); if(len == 0) return HtsMessage(); buf = (char*)malloc(len); if((readSize = net_Read(obj, sys->netfd, buf, len)) != (ssize_t)len) { net_Close(sys->netfd); sys->netfd = -1; if(readSize == 0) { msg_Err(obj, "Data Read EOF!"); return HtsMessage(); } else if(readSize < 0) { msg_Err(obj, "Data Read ERROR!"); return HtsMessage(); } msg_Err(obj, "Error reading data: %m"); return HtsMessage(); } HtsMessage result = HtsMessage::Deserialize(len, buf); free(buf); return result; }
/***************************************************************************** * Run: rtci thread ***************************************************************************** * This part of the interface is in a separate thread so that we can call * exec() from within it without annoying the rest of the program. *****************************************************************************/ static void Run( intf_thread_t *p_intf ) { input_thread_t * p_input; playlist_t * p_playlist; char p_buffer[ MAX_LINE_LENGTH + 1 ]; vlc_bool_t b_showpos = config_GetInt( p_intf, "rtci-show-pos" ); int i_size = 0; int i_oldpos = 0; int i_newpos; p_buffer[0] = 0; p_input = NULL; p_playlist = NULL; p_intf->p_sys->b_extend = config_GetInt( p_intf, "rtci-extend" ); /* Register commands that will be cleaned up upon object destruction */ var_Create( p_intf, "quit", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "quit", Quit, NULL ); var_Create( p_intf, "intf", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "intf", Intf, NULL ); var_Create( p_intf, "add", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "add", Playlist, NULL ); var_Create( p_intf, "playlist", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "playlist", Playlist, NULL ); var_Create( p_intf, "play", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "play", Playlist, NULL ); var_Create( p_intf, "stop", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "stop", Playlist, NULL ); var_Create( p_intf, "prev", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "prev", Playlist, NULL ); var_Create( p_intf, "next", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "next", Playlist, NULL ); var_Create( p_intf, "marq-marquee", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "marq-marquee", Other, NULL ); var_Create( p_intf, "marq-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "marq-x", Other, NULL ); var_Create( p_intf, "marq-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "marq-y", Other, NULL ); var_Create( p_intf, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "marq-timeout", Other, NULL ); var_Create( p_intf, "pause", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "pause", Input, NULL ); var_Create( p_intf, "seek", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "seek", Input, NULL ); var_Create( p_intf, "title", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "title", Input, NULL ); var_Create( p_intf, "title_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "title_n", Input, NULL ); var_Create( p_intf, "title_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "title_p", Input, NULL ); var_Create( p_intf, "chapter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "chapter", Input, NULL ); var_Create( p_intf, "chapter_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "chapter_n", Input, NULL ); var_Create( p_intf, "chapter_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "chapter_p", Input, NULL ); var_Create( p_intf, "volume", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "volume", Volume, NULL ); var_Create( p_intf, "volup", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "volup", VolumeMove, NULL ); var_Create( p_intf, "voldown", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "voldown", VolumeMove, NULL ); var_Create( p_intf, "adev", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "adev", AudioConfig, NULL ); var_Create( p_intf, "achan", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "achan", AudioConfig, NULL ); #ifdef WIN32 /* Get the file descriptor of the console input */ p_intf->p_sys->hConsoleIn = GetStdHandle(STD_INPUT_HANDLE); if( p_intf->p_sys->hConsoleIn == INVALID_HANDLE_VALUE ) { msg_Err( p_intf, "Couldn't open STD_INPUT_HANDLE" ); p_intf->b_die = VLC_TRUE; } #endif while( !p_intf->b_die ) { char *psz_cmd, *psz_arg; vlc_bool_t b_complete; if( p_intf->p_sys->i_socket_listen != - 1 && p_intf->p_sys->i_socket == -1 ) { p_intf->p_sys->i_socket = net_Accept( p_intf, p_intf->p_sys->i_socket_listen, 0 ); } b_complete = ReadCommand( p_intf, p_buffer, &i_size ); /* Manage the input part */ if( p_input == NULL ) { if( p_playlist ) { p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT, FIND_CHILD ); } else { p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE ); if( p_input ) { p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT ); } } } else if( p_input->b_dead ) { vlc_object_release( p_input ); p_input = NULL; } if( p_input && b_showpos ) { i_newpos = 100 * var_GetFloat( p_input, "position" ); if( i_oldpos != i_newpos ) { i_oldpos = i_newpos; msg_rtci( "pos: %d%%\n", i_newpos ); } } /* Is there something to do? */ if( !b_complete ) continue; /* Skip heading spaces */ psz_cmd = p_buffer; while( *psz_cmd == ' ' ) { psz_cmd++; } /* Split psz_cmd at the first space and make sure that * psz_arg is valid */ psz_arg = strchr( psz_cmd, ' ' ); if( psz_arg ) { *psz_arg++ = 0; while( *psz_arg == ' ' ) { psz_arg++; } } else { psz_arg = ""; } /* If the user typed a registered local command, try it */ if( var_Type( p_intf, psz_cmd ) & VLC_VAR_ISCOMMAND ) { vlc_value_t val; int i_ret; val.psz_string = psz_arg; i_ret = var_Set( p_intf, psz_cmd, val ); msg_rtci( "%s: returned %i (%s)\n", psz_cmd, i_ret, vlc_error( i_ret ) ); } /* Or maybe it's a global command */ else if( var_Type( p_intf->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND ) { vlc_value_t val; int i_ret; val.psz_string = psz_arg; /* FIXME: it's a global command, but we should pass the * local object as an argument, not p_intf->p_libvlc. */ i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val ); if( i_ret != 0 ) { msg_rtci( "%s: returned %i (%s)\n", psz_cmd, i_ret, vlc_error( i_ret ) ); } } else if( !strcmp( psz_cmd, "logout" ) ) { /* Close connection */ if( p_intf->p_sys->i_socket != -1 ) { net_Close( p_intf->p_sys->i_socket ); } p_intf->p_sys->i_socket = -1; } else if( !strcmp( psz_cmd, "info" ) ) { if( p_input ) { int i, j; vlc_mutex_lock( &p_input->input.p_item->lock ); for ( i = 0; i < p_input->input.p_item->i_categories; i++ ) { info_category_t *p_category = p_input->input.p_item->pp_categories[i]; msg_rtci( "+----[ %s ]\n", p_category->psz_name ); msg_rtci( "| \n" ); for ( j = 0; j < p_category->i_infos; j++ ) { info_t *p_info = p_category->pp_infos[j]; msg_rtci( "| %s: %s\n", p_info->psz_name, p_info->psz_value ); } msg_rtci( "| \n" ); } msg_rtci( "+----[ end of stream info ]\n" ); vlc_mutex_unlock( &p_input->input.p_item->lock ); } else { msg_rtci( "no input\n" ); } } else if( !strcmp( psz_cmd, "is_playing" ) ) { if( ! p_input ) { msg_rtci( "0\n" ); } else { msg_rtci( "1\n" ); } } else if( !strcmp( psz_cmd, "get_time" ) ) { if( ! p_input ) { msg_rtci("0\n"); } else { vlc_value_t time; var_Get( p_input, "time", &time ); msg_rtci( "%i\n", time.i_time / 1000000); } } else if( !strcmp( psz_cmd, "get_length" ) ) { if( ! p_input ) { msg_rtci("0\n"); } else { vlc_value_t time; var_Get( p_input, "length", &time ); msg_rtci( "%i\n", time.i_time / 1000000); } } else if( !strcmp( psz_cmd, "get_title" ) ) { if( ! p_input ) { msg_rtci("\n"); } else { msg_rtci( "%s\n", p_input->input.p_item->psz_name ); } } else switch( psz_cmd[0] ) { case 'f': case 'F': if( p_input ) { vout_thread_t *p_vout; p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD ); if( p_vout ) { p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; vlc_object_release( p_vout ); } } break; case 's': case 'S': ; break; case '?': case 'h': case 'H': msg_rtci(_("+----[ Remote control commands ]\n")); msg_rtci("| \n"); msg_rtci(_("| add XYZ . . . . . . . . . . add XYZ to playlist\n")); msg_rtci(_("| playlist . . . show items currently in playlist\n")); msg_rtci(_("| play . . . . . . . . . . . . . . . . play stream\n")); msg_rtci(_("| stop . . . . . . . . . . . . . . . . stop stream\n")); msg_rtci(_("| next . . . . . . . . . . . . next playlist item\n")); msg_rtci(_("| prev . . . . . . . . . . previous playlist item\n")); msg_rtci(_("| title [X] . . . . set/get title in current item\n")); msg_rtci(_("| title_n . . . . . . next title in current item\n")); msg_rtci(_("| title_p . . . . previous title in current item\n")); msg_rtci(_("| chapter [X] . . set/get chapter in current item\n")); msg_rtci(_("| chapter_n . . . . next chapter in current item\n")); msg_rtci(_("| chapter_p . . previous chapter in current item\n")); msg_rtci("| \n"); msg_rtci(_("| seek X . seek in seconds, for instance `seek 12'\n")); msg_rtci(_("| pause . . . . . . . . . . . . . . toggle pause\n")); msg_rtci(_("| f . . . . . . . . . . . . . . toggle fullscreen\n")); msg_rtci(_("| info . . . information about the current stream\n")); msg_rtci("| \n"); msg_rtci(_("| volume [X] . . . . . . . . set/get audio volume\n")); msg_rtci(_("| volup [X] . . . . . raise audio volume X steps\n")); msg_rtci(_("| voldown [X] . . . . lower audio volume X steps\n")); msg_rtci(_("| adev [X] . . . . . . . . . set/get audio device\n")); msg_rtci(_("| achan [X]. . . . . . . . set/get audio channels\n")); msg_rtci("| \n"); if (p_intf->p_sys->b_extend) { msg_rtci(_("| marq-marquee STRING . . overlay STRING in video\n")); msg_rtci(_("| marq-x X . . . . . .offset of marquee, from left\n")); msg_rtci(_("| marq-y Y . . . . . . offset of marquee, from top\n")); msg_rtci(_("| marq-timeout T. . . . .timeout of marquee, in ms\n")); msg_rtci("| \n"); } msg_rtci(_("| help . . . . . . . . . . . . . this help message\n")); msg_rtci(_("| logout . . . . . .exit (if in socket connection)\n")); msg_rtci(_("| quit . . . . . . . . . . . . . . . . . quit vlc\n")); msg_rtci("| \n"); msg_rtci(_("+----[ end of help ]\n")); break; case '\0': /* Ignore empty lines */ break; default: msg_rtci(_("unknown command `%s', type `help' for help\n"), psz_cmd); break; } /* Command processed */ i_size = 0; p_buffer[0] = 0; } if( p_input ) { vlc_object_release( p_input ); p_input = NULL; } if( p_playlist ) { vlc_object_release( p_playlist ); p_playlist = NULL; } }
/***************************************************************************** * Run: interface thread *****************************************************************************/ static void Run( intf_thread_t *p_intf ) { #define MAX_MSG_LENGTH (2 * sizeof(int64_t)) vlc_bool_t b_master = config_GetInt( p_intf, "netsync-master" ); char *psz_master = NULL; char p_data[MAX_MSG_LENGTH]; int i_socket; if( !b_master ) { psz_master = config_GetPsz( p_intf, "netsync-master-ip" ); if( psz_master == NULL ) { msg_Err( p_intf, "master address not specified" ); return; } } i_socket = net_OpenUDP( p_intf, NULL, b_master ? NETSYNC_PORT_MASTER : NETSYNC_PORT_SLAVE, b_master ? NULL : psz_master, b_master ? 0 : NETSYNC_PORT_MASTER ); if( psz_master ) free( psz_master ); if( i_socket < 0 ) { msg_Err( p_intf, "failed opening UDP socket." ); return; } /* High priority thread */ vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_INPUT ); while( !p_intf->b_die ) { struct timeval timeout; fd_set fds_r; /* Update the input */ if( p_intf->p_sys->p_input == NULL ) { p_intf->p_sys->p_input = (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE ); } else if( p_intf->p_sys->p_input->b_dead ) { vlc_object_release( p_intf->p_sys->p_input ); p_intf->p_sys->p_input = NULL; } if( p_intf->p_sys->p_input == NULL ) { /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); continue; } /* * We now have an input */ /* Initialize file descriptor set and timeout (0.5s) */ FD_ZERO( &fds_r ); FD_SET( i_socket, &fds_r ); timeout.tv_sec = 0; timeout.tv_usec = 500000; if( b_master ) { struct sockaddr_storage from; mtime_t i_date, i_clockref, i_master_clockref; int i_struct_size, i_read, i_ret; /* Don't block */ i_ret = select( i_socket + 1, &fds_r, 0, 0, &timeout ); if( i_ret == 0 ) continue; if( i_ret < 0 ) { /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); continue; } /* We received something */ i_struct_size = sizeof( from ); i_read = recvfrom( i_socket, p_data, MAX_MSG_LENGTH, 0, (struct sockaddr*)&from, &i_struct_size ); i_clockref = ntoh64(*(int64_t *)p_data); i_date = mdate(); *(int64_t *)p_data = hton64( i_date ); i_master_clockref = GetClockRef( p_intf, i_clockref ); *(((int64_t *)p_data)+1) = hton64( i_master_clockref ); /* Reply to the sender */ sendto( i_socket, p_data, 2 * sizeof(int64_t), 0, (struct sockaddr *)&from, i_struct_size ); #if 0 msg_Dbg( p_intf, "Master clockref: "I64Fd" -> "I64Fd", from %s " "(date: "I64Fd")", i_clockref, i_master_clockref, from.ss_family == AF_INET ? inet_ntoa(((struct sockaddr_in *)&from)->sin_addr) : "non-IPv4", i_date ); #endif } else { mtime_t i_send_date, i_receive_date, i_master_date, i_diff_date; mtime_t i_master_clockref, i_client_clockref, i_drift; mtime_t i_clockref = 0; int i_sent, i_read, i_ret; /* Send clock request to the master */ *(int64_t *)p_data = hton64( i_clockref ); i_send_date = mdate(); i_sent = send( i_socket, p_data, sizeof(int64_t), 0 ); if( i_sent <= 0 ) { /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); continue; } /* Don't block */ i_ret = select(i_socket + 1, &fds_r, 0, 0, &timeout); if( i_ret == 0 ) continue; if( i_ret < 0 ) { /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); continue; } i_receive_date = mdate(); i_read = recv( i_socket, p_data, MAX_MSG_LENGTH, 0 ); if( i_read <= 0 ) { /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); continue; } i_master_date = ntoh64(*(int64_t *)p_data); i_master_clockref = ntoh64(*(((int64_t *)p_data)+1)); i_diff_date = i_receive_date - ((i_receive_date - i_send_date) / 2 + i_master_date); i_client_clockref = i_drift = 0; if( p_intf->p_sys->p_input && i_master_clockref ) { i_client_clockref = GetClockRef( p_intf, i_clockref ); i_drift = i_client_clockref - i_master_clockref - i_diff_date; /* Update our clock to match the master's one */ if( i_client_clockref ) p_intf->p_sys->p_input->i_pts_delay -= i_drift; } #if 0 msg_Dbg( p_intf, "Slave clockref: "I64Fd" -> "I64Fd" -> "I64Fd", " "clock diff: "I64Fd" drift: "I64Fd, i_clockref, i_master_clockref, i_client_clockref, i_diff_date, i_drift ); #endif /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); } } if( p_intf->p_sys->p_input ) vlc_object_release( p_intf->p_sys->p_input ); net_Close( i_socket ); }
/***************************************************************************** * Run : call Handshake() then submit items *****************************************************************************/ static void Run(intf_thread_t *p_intf) { msg_Dbg(p_intf, "Entering Run()"); uint8_t p_buffer[1024]; int parse_url_ret; int canc = vlc_savecancel(); char *psz_scrobbler_url; mtime_t next_exchange; /**< when can we send data */ unsigned int i_interval; /**< waiting interval (secs)*/ intf_sys_t *p_sys = p_intf->p_sys; psz_scrobbler_url = var_InheritString(p_intf, "mediascrobbler-url"); if(!psz_scrobbler_url) return; msg_Dbg(p_intf, "Scrobbler URL: %s", psz_scrobbler_url); /* main loop */ for (;;) { vlc_restorecancel(canc); vlc_mutex_lock(&p_sys->lock); mutex_cleanup_push(&p_sys->lock); msg_Dbg(p_intf, "Next exchange %lld (current: %lld)", next_exchange, mdate()); do { vlc_cond_wait(&p_sys->wait, &p_sys->lock); } while (mdate() < next_exchange); vlc_cleanup_run(); canc = vlc_savecancel(); msg_Dbg(p_intf, "Going to submit some data..."); char *psz_submit; if (asprintf(&psz_submit, "s=%s", psz_scrobbler_url) == -1) return; msg_Dbg(p_intf, "Going to parse URL (%s)", psz_scrobbler_url); parse_url_ret = ParseURL(psz_scrobbler_url, &p_sys->psz_submit_host, &p_sys->psz_submit_file, &p_sys->i_submit_port); if(parse_url_ret != VLC_SUCCESS) { msg_Err(p_intf, "Couldn't process URL, can't continue"); return; } msg_Dbg(p_intf, "Submit Host: %s", p_sys->psz_submit_host); msg_Dbg(p_intf, "Preparing to submit %d items", p_sys->i_items); /* forge the HTTP POST request */ vlc_mutex_lock(&p_sys->lock); mediascrobbler_item_t *p_item; for (int i_item = 0 ; i_item < p_sys->i_items ; i_item++) { char *psz_submit_item, *psz_submit_tmp; p_item = &p_sys->p_queue[i_item]; if (asprintf(&psz_submit_item, "&n%%5B%d%%5D=%s" "&u%%5B%d%%5D=%s" "&d%%5B%d%%5D=%ju" "&l%%5B%d%%5D=%d", i_item, p_item->psz_n, i_item, p_item->psz_u, i_item, p_item->date, i_item, p_item->i_l ) == -1) { /* Out of memory */ vlc_mutex_unlock(&p_sys->lock); return; } psz_submit_tmp = psz_submit; if (asprintf(&psz_submit, "%s%s", psz_submit_tmp, psz_submit_item) == -1) { /* Out of memory */ free(psz_submit_tmp); free(psz_submit_item); vlc_mutex_unlock(&p_sys->lock); return; } free(psz_submit_item); free(psz_submit_tmp); } vlc_mutex_unlock(&p_sys->lock); int i_post_socket = net_ConnectTCP(p_intf, p_sys->psz_submit_host, p_sys->i_submit_port); if (i_post_socket == -1) { msg_Warn(p_intf, "Couldn't talk to the API, waiting to try again. (%d)", i_interval); HandleInterval(&next_exchange, &i_interval); free(psz_submit); continue; } /* we transmit the data */ int i_net_ret = net_Printf(p_intf, i_post_socket, NULL, "POST %s HTTP/1.1\r\n" "Accept-Encoding: identity\r\n" "Content-length: %zu\r\n" "Connection: close\r\n" "Content-type: application/x-www-form-urlencoded\r\n" "Host: %s\r\n" "User-agent: VLC media player/"VERSION"\r\n" "\r\n" "%s\r\n" "\r\n", p_sys->psz_submit_file, strlen(psz_submit), p_sys->psz_submit_host, psz_submit ); free(psz_submit); if (i_net_ret == -1) { /* If connection fails, back off the timer, and try again */ HandleInterval(&next_exchange, &i_interval); continue; } i_net_ret = net_Read(p_intf, i_post_socket, NULL, p_buffer, sizeof(p_buffer) - 1, false); if (i_net_ret <= 0) { /* if we get no answer, something went wrong : try again */ 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, "BADAPIKEY")) { msg_Err(p_intf, "Authentication failed (BADAPIKEY), are you sure your API key is valid?"); HandleInterval(&next_exchange, &i_interval); continue; } if (strstr((char *) p_buffer, "OK")) { for (int i = 0; i < p_sys->i_items; i++) DeleteItem(&p_sys->p_queue[i]); p_sys->i_items = 0; i_interval = 0; next_exchange = mdate(); msg_Dbg(p_intf, "Submission successful!"); } else { msg_Err(p_intf, "Authentication failed, trying again (%s)", p_buffer); HandleInterval(&next_exchange, &i_interval); } } vlc_restorecancel(canc); }
/***************************************************************************** * 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; }
/***************************************************************************** * Activate: initialize and create stuff *****************************************************************************/ static int Activate( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t*)p_this; char *psz_host, *psz_unix_path; int i_socket = -1; #if defined(HAVE_ISATTY) && !defined(WIN32) /* Check that stdin is a TTY */ if( !config_GetInt( p_intf, "rtci-fake-tty" ) && !isatty( 0 ) ) { msg_Warn( p_intf, "fd 0 is not a TTY" ); return VLC_EGENERIC; } #endif psz_unix_path = config_GetPsz( p_intf, "rtci-unix" ); if( psz_unix_path ) { #ifndef PF_LOCAL msg_Warn( p_intf, "your OS doesn't support filesystem sockets" ); free( psz_unix_path ); return VLC_EGENERIC; #else struct sockaddr_un addr; int i_ret; memset( &addr, 0, sizeof(struct sockaddr_un) ); msg_Dbg( p_intf, "trying UNIX socket" ); if( (i_socket = socket( PF_LOCAL, SOCK_STREAM, 0 ) ) < 0 ) { msg_Warn( p_intf, "can't open socket: %s", strerror(errno) ); free( psz_unix_path ); return VLC_EGENERIC; } addr.sun_family = AF_LOCAL; strncpy( addr.sun_path, psz_unix_path, sizeof( addr.sun_path ) ); addr.sun_path[sizeof( addr.sun_path ) - 1] = '\0'; if( (i_ret = bind( i_socket, (struct sockaddr*)&addr, sizeof(struct sockaddr_un) ) ) < 0 ) { msg_Warn( p_intf, "couldn't bind socket to address: %s", strerror(errno) ); free( psz_unix_path ); net_Close( i_socket ); return VLC_EGENERIC; } if( ( i_ret = listen( i_socket, 1 ) ) < 0 ) { msg_Warn( p_intf, "can't listen on socket: %s", strerror(errno)); free( psz_unix_path ); net_Close( i_socket ); return VLC_EGENERIC; } #endif } if( ( i_socket == -1) && ( psz_host = config_GetPsz( p_intf, "rtci-host" ) ) != NULL ) { vlc_url_t url; vlc_UrlParse( &url, psz_host, 0 ); msg_Dbg( p_intf, "base %s port %d", url.psz_host, url.i_port ); if( (i_socket = net_ListenTCP(p_this, url.psz_host, url.i_port)) == -1) { msg_Warn( p_intf, "can't listen to %s port %i", url.psz_host, url.i_port ); vlc_UrlClean( &url ); free( psz_host ); return VLC_EGENERIC; } vlc_UrlClean( &url ); free( psz_host ); } p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); if( !p_intf->p_sys ) { msg_Err( p_intf, "no memory" ); return VLC_ENOMEM; } p_intf->p_sys->i_socket_listen = i_socket; p_intf->p_sys->i_socket = -1; p_intf->p_sys->psz_unix_path = psz_unix_path; /* Non-buffered stdout */ setvbuf( stdout, (char *)NULL, _IOLBF, 0 ); p_intf->pf_run = Run; #ifdef WIN32 if( !config_GetInt( p_intf, "rtci-quiet" ) ) { CONSOLE_INTRO_MSG; } #else CONSOLE_INTRO_MSG; #endif msg_rtci( _("Real time control interface initialized, `h' for help\n") ); return VLC_SUCCESS; }
static void Run(intf_thread_t *p_intf) { intf_sys_t *p_sys = p_intf->p_sys; input_thread_t *p_input = NULL; playlist_t *p_playlist = pl_Get(p_intf); int *pi_fd, i_listen = 0, i_err; p_intf->p_sys->p_playlist = p_playlist; for (pi_fd = p_sys->pi_socket; *pi_fd != -1; pi_fd++) i_listen++; for (; vlc_object_alive(p_intf);) { vlc_value_t val; struct pollfd fd[i_listen + 2]; vlc_testcancel(); if (p_input == NULL) { p_input = playlist_CurrentInput(p_playlist); if (p_input) { var_AddCallback(p_input, "intf-event", InputEvent, p_intf); } } else { if (p_input->b_dead || !vlc_object_alive(p_input)) { var_DelCallback(p_input, "intf-event", InputEvent, p_intf); vlc_object_release(p_input); p_input = NULL; } } memset(&fd, 0, sizeof(fd[0]) * (i_listen + 1)); if (p_sys->i_socket == -1) { for (int i = 0; i < i_listen; i++) { fd[i].fd = p_sys->pi_socket[i]; fd[i].events = POLLIN; fd[i].revents = 0; } } else { fd[0].fd = p_sys->i_wakeup[0]; fd[0].events = POLLIN; fd[0].revents = 0; fd[1].fd = p_sys->i_socket; fd[1].events = POLLIN | (p_sys->i_write_length > 0 ? POLLOUT : 0); fd[1].revents = 0; } i_err = poll(fd, (p_sys->i_socket != -1) ? 2 : i_listen, -1); if (i_err < 0) { msg_Dbg(p_intf, "poll() failed"); vlc_object_kill(p_intf); break; } if (i_err == 0) continue; if (p_sys->i_socket == -1) { for (int i = 0; i < i_listen; i++) { if (fd[i].revents & POLLIN) { int client = net_AcceptSingle(VLC_OBJECT(p_intf), fd[i].fd); if (client == -1) continue; p_sys->i_socket = client; break; } } } else { if (fd[0].revents & POLLIN) { char ch; read(fd[0].fd, &ch, 1); } if (fd[1].revents & (POLLERR|POLLHUP|POLLNVAL)) { net_Close(fd[0].fd); p_sys->i_socket = -1; msg_Dbg(VLC_OBJECT(p_intf), "connection error"); continue; } ssize_t i_len, i_test; if (fd[1].revents & POLLIN) { //msg_Dbg(VLC_OBJECT(p_intf), "poll in"); bool b_line = false; while ((i_len = recv(fd[1].fd, p_sys->p_read_buffer + p_sys->i_read_offset, 1, 0)) > 0) { char ch; ch = p_sys->p_read_buffer[p_sys->i_read_offset]; switch (ch) { case '\r': case '\n': p_sys->p_read_buffer[p_sys->i_read_offset] = '\0'; b_line = true; break; case '\0': b_line = true; break; default: break; } p_sys->i_read_offset++; if (p_sys->i_read_offset == sizeof(p_sys->p_read_buffer) && !b_line) { net_Close(p_sys->i_socket); p_sys->i_socket = -1; msg_Dbg(VLC_OBJECT(p_intf), "input is too long, close connection"); break; } } if (b_line && strlen(p_sys->p_read_buffer)) { p_sys->i_read_offset = 0; //msg_Dbg(VLC_OBJECT(p_intf), "%s\n", p_sys->p_read_buffer); ProcessCommand(p_intf, p_sys->p_read_buffer); } if(i_len == 0) { net_Close(p_sys->i_socket); p_sys->i_socket = -1; msg_Dbg(VLC_OBJECT(p_intf), "connection is closed by client"); } } if (fd[1].revents & POLLOUT) { vlc_mutex_lock(&p_sys->o_write_lock); if (p_sys->i_write_length) { int i_first, i_second; i_first = sizeof(p_sys->p_write_buffer) - p_sys->i_write_offset; i_second = (p_sys->i_write_offset + p_sys->i_write_length) % sizeof(p_sys->p_write_buffer); i_test = 0; if (i_first >= p_sys->i_write_length) i_len = send(fd[1].fd, p_sys->p_write_buffer + p_sys->i_write_offset, p_sys->i_write_length, 0); else { i_len = send(fd[1].fd, p_sys->p_write_buffer + p_sys->i_write_offset, i_first, 0); if (i_len == i_first) i_test = send(fd[1].fd, p_sys->p_write_buffer, i_second, 0); if (i_test > 0) i_len += i_test; } if (i_len > 0) { p_sys->i_write_offset += i_len; p_sys->i_write_offset %= sizeof(p_sys->p_write_buffer); p_sys->i_write_length -= i_len; if (p_sys->i_write_length == 0) p_sys->i_write_offset = 0; } } vlc_mutex_unlock(&p_sys->o_write_lock); } } } }
int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype, int i_protocol ) { int fd, i_val; fd = socket( i_family, i_socktype, i_protocol ); if( fd == -1 ) { #if defined(WIN32) || defined(UNDER_CE) if( WSAGetLastError ( ) != WSAEAFNOSUPPORT ) msg_Warn( p_this, "cannot create socket (%i)", WSAGetLastError() ); #else if( errno != EAFNOSUPPORT ) msg_Warn( p_this, "cannot create socket (%s)", strerror( errno ) ); #endif return -1; } #if defined( WIN32 ) || defined( UNDER_CE ) { unsigned long i_dummy = 1; if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 ) msg_Err( p_this, "cannot set socket to non-blocking mode" ); } #else if( fd >= FD_SETSIZE ) { /* We don't want to overflow select() fd_set */ msg_Err( p_this, "cannot create socket (too many already in use)" ); net_Close( fd ); return -1; } fcntl( fd, F_SETFD, FD_CLOEXEC ); i_val = fcntl( fd, F_GETFL, 0 ); fcntl( fd, F_SETFL, ((i_val != -1) ? i_val : 0) | O_NONBLOCK ); #endif i_val = 1; setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val, sizeof( i_val ) ); #ifdef IPV6_V6ONLY /* * Accepts only IPv6 connections on IPv6 sockets * (and open an IPv4 socket later as well if needed). * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets, * so this allows for more uniform handling across platforms. Besides, * it makes sure that IPv4 addresses will be printed as w.x.y.z rather * than ::ffff:w.x.y.z */ if( i_family == AF_INET6 ) setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val, sizeof( i_val ) ); #endif #if defined( WIN32 ) || defined( UNDER_CE ) # ifndef IPV6_PROTECTION_LEVEL # define IPV6_PROTECTION_LEVEL 23 # endif if( i_family == AF_INET6 ) { i_val = 10 /*PROTECTION_LEVEL_UNRESTRICTED*/; setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&i_val, sizeof( i_val ) ); } #endif return fd; }
static void ProcessCommand(intf_thread_t *p_intf, const char *p_string) { intf_sys_t *p_sys = p_intf->p_sys; playlist_t *p_playlist = p_sys->p_playlist; char *p_line = strdup(p_string); int i_argc; char** p_argv = NULL; i_argc = ParseLineCommand(p_line, &p_argv); if (i_argc == 0 || !p_argv) goto msg; if (i_argc == 1) { if (!strcmp(p_argv[0], "help")) { Notify(p_intf, "woshenmedoubuzhidao\n"); } else if (!strcmp(p_argv[0], "play")) { playlist_Play(p_playlist); } else if (!strcmp(p_argv[0], "pause")) { playlist_Pause(p_playlist); } else if (!strcmp(p_argv[0], "stop")) { playlist_Stop(p_playlist); } else if (!strcmp(p_argv[0], "close")) { playlist_Clear(p_playlist, pl_Unlocked); } else if (!strcmp(p_argv[0], "ff")) { } else if (!strcmp(p_argv[0], "fb")) { } else if (!strcmp(p_argv[0], "quit")) { net_Close(p_sys->i_socket); p_sys->i_socket = -1; } else if (!strcmp(p_argv[0], "shutdown")) { } else goto msg; } else if (i_argc == 2) { if (!strcmp(p_argv[0], "open")) { char *path = p_argv[1]; int len = strlen(path); char *uri = malloc(len * 3 + 1); if (!uri) { Notify(p_intf, "oops\n"); goto out; } int i, j; for (i = 0, j = 0; i < len; i++) { uint8_t ch = path[i]; if (ch < 32 || ch > 127) { uri[j] = '%'; uri[j + 1] = ch >> 4; uri[j + 1] += (uri[j + 1] > 9 ? 0x37 : 0x30); uri[j + 2] = ch & 15; uri[j + 2] += (uri[j + 2] > 9 ? 0x37 : 0x30); j += 3; } else { uri[j] = path[i]; j++; } }