mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
memory leak cleanups (valgrind) in airplay_video + http_handlers
This commit is contained in:
@@ -30,6 +30,8 @@ struct media_item_s {
|
||||
char *uri;
|
||||
char *playlist;
|
||||
int num;
|
||||
int count;
|
||||
float duration;
|
||||
};
|
||||
|
||||
struct airplay_video_s {
|
||||
@@ -170,6 +172,13 @@ int get_next_media_uri_id(airplay_video_t *airplay_video) {
|
||||
return airplay_video->next_uri;
|
||||
}
|
||||
|
||||
void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist) {
|
||||
if (airplay_video->master_playlist) {
|
||||
free (airplay_video->master_playlist);
|
||||
}
|
||||
airplay_video->master_playlist = master_playlist;
|
||||
}
|
||||
|
||||
typedef struct language_s {
|
||||
char *start;
|
||||
int len;
|
||||
@@ -277,16 +286,12 @@ language_t* master_playlist_process_language(char * data, int *slices, int *lang
|
||||
return languages;
|
||||
}
|
||||
|
||||
void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist) {
|
||||
char * select_master_playlist_language(airplay_video_t *airplay_video, char *master_playlist) {
|
||||
int language_count, slices;
|
||||
if (airplay_video->master_playlist) {
|
||||
free (airplay_video->master_playlist);
|
||||
}
|
||||
airplay_video->master_playlist = master_playlist;
|
||||
language_t *languages;
|
||||
if (!(languages = master_playlist_process_language(airplay_video->master_playlist,
|
||||
if (!(languages = master_playlist_process_language(master_playlist,
|
||||
&slices, &language_count))) {
|
||||
return;
|
||||
return master_playlist;
|
||||
}
|
||||
/* audio is offered in multiple languages */
|
||||
char *str = calloc(6 * language_count, sizeof(char));
|
||||
@@ -342,8 +347,8 @@ void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist
|
||||
len += languages[i].len;
|
||||
}
|
||||
}
|
||||
airplay_video->master_playlist = (char *) calloc(len + 1, sizeof(char));
|
||||
ptr = airplay_video->master_playlist;
|
||||
char *new_master_playlist = (char *) calloc(len + 1, sizeof(char));
|
||||
ptr = new_master_playlist;
|
||||
for (int i = 0; i < slices; i++) {
|
||||
if (strlen(languages[i].code) == 0 || !strcmp(languages[i].code, lang)) {
|
||||
strncpy(ptr, languages[i].start, languages[i].len);
|
||||
@@ -352,6 +357,7 @@ void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist
|
||||
}
|
||||
free (languages);
|
||||
free(master_playlist);
|
||||
return new_master_playlist;
|
||||
}
|
||||
|
||||
char *get_master_playlist(airplay_video_t *airplay_video) {
|
||||
@@ -392,13 +398,14 @@ void create_media_data_store(airplay_video_t * airplay_video, char ** uri_list,
|
||||
airplay_video->num_uri = num_uri;
|
||||
}
|
||||
|
||||
int store_media_playlist(airplay_video_t *airplay_video, char * media_playlist, int num) {
|
||||
int store_media_playlist(airplay_video_t *airplay_video, char * media_playlist, int *count, float *duration, int num) {
|
||||
media_item_t *media_data_store = airplay_video->media_data_store;
|
||||
if ( num < 0 || num >= airplay_video->num_uri) {
|
||||
return -1;
|
||||
} else if (media_data_store[num].playlist) {
|
||||
return -2;
|
||||
}
|
||||
/* dont store duplicate media paylists */
|
||||
for (int i = 0; i < num ; i++) {
|
||||
if (strcmp(media_data_store[i].uri, media_data_store[num].uri) == 0) {
|
||||
assert(strcmp(media_data_store[i].playlist, media_playlist) == 0);
|
||||
@@ -408,16 +415,20 @@ int store_media_playlist(airplay_video_t *airplay_video, char * media_playlist,
|
||||
}
|
||||
}
|
||||
media_data_store[num].playlist = media_playlist;
|
||||
media_data_store[num].count = *count;
|
||||
media_data_store[num].duration = *duration;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * get_media_playlist(airplay_video_t *airplay_video, const char *uri) {
|
||||
char * get_media_playlist(airplay_video_t *airplay_video, int *count, float *duration, const char *uri) {
|
||||
media_item_t *media_data_store = airplay_video->media_data_store;
|
||||
if (media_data_store == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (int i = 0; i < airplay_video->num_uri; i++) {
|
||||
if (strstr(media_data_store[i].uri, uri)) {
|
||||
*count = media_data_store[media_data_store[i].num].count;
|
||||
*duration = media_data_store[media_data_store[i].num].duration;
|
||||
return media_data_store[media_data_store[i].num].playlist;
|
||||
}
|
||||
}
|
||||
@@ -432,7 +443,8 @@ char * get_media_uri_by_num(airplay_video_t *airplay_video, int num) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int analyze_media_playlist(char *playlist, float *duration) {
|
||||
#if 0
|
||||
int analyze_media_playlist_old(char *playlist, float *duration) {
|
||||
float next;
|
||||
int count = 0;
|
||||
char *ptr = strstr(playlist, "#EXTINF:");
|
||||
@@ -447,6 +459,34 @@ int analyze_media_playlist(char *playlist, float *duration) {
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
int analyze_media_playlist(char *playlist, float *duration) {
|
||||
*duration = 0.0f;;
|
||||
int count = 0;
|
||||
int len_playlist = strlen(playlist);
|
||||
char target[] = "#EXTINF:";
|
||||
int len_target = strlen(target);
|
||||
int len = len_playlist - len_target;
|
||||
char *ptr = playlist;
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
char *endptr;
|
||||
float next;
|
||||
if (strncmp(ptr, target, len_target)) {
|
||||
i++;
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
i += len_target;
|
||||
ptr += len_target;
|
||||
next = strtof(ptr, &endptr);
|
||||
assert(endptr > ptr);
|
||||
*duration += next;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* parse Master Playlist, make table of Media Playlist uri's that it lists */
|
||||
int create_media_uri_table(const char *url_prefix, const char *master_playlist_data,
|
||||
|
||||
@@ -45,9 +45,10 @@ int analyze_media_playlist(char *playlist, float *duration);
|
||||
int create_media_uri_table(const char *url_prefix, const char *master_playlist_data,
|
||||
int datalen, char ***media_uri_table, int *num_uri);
|
||||
void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist);
|
||||
int store_media_playlist(airplay_video_t *airplay_video, char *media_playlist, int num);
|
||||
char *select_master_playlist_language(airplay_video_t *airplay_video, char *master_playlist);
|
||||
int store_media_playlist(airplay_video_t *airplay_video, char *media_playlist, int *count, float *duration, int num);
|
||||
char *get_master_playlist(airplay_video_t *airplay_video);
|
||||
char *get_media_playlist(airplay_video_t *airplay_video, const char *uri);
|
||||
char *get_media_playlist(airplay_video_t *airplay_video, int *count, float *duration, const char *uri);
|
||||
|
||||
void destroy_media_data_store(airplay_video_t *airplay_video);
|
||||
void create_media_data_store(airplay_video_t * airplay_video, char ** media_data_store, int num_uri);
|
||||
|
||||
@@ -376,19 +376,6 @@ http_handler_reverse(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
listed in the Master Playlist. The POST /action request contains the playlist requested by the Server in
|
||||
the preceding "FCUP Request". The FCUP Request sequence continues until all Media Playlists have been obtained by the Server */
|
||||
|
||||
|
||||
static void
|
||||
plist_mem_free_wrapper(char * plist_ptr) {
|
||||
/* wrapper for plist_mem_free, only available since libplist 2.3.0 */
|
||||
if (plist_ptr) {
|
||||
#ifdef PLIST_230
|
||||
plist_mem_free (plst_ptr);
|
||||
#else
|
||||
free (plist_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen) {
|
||||
@@ -504,7 +491,7 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
}
|
||||
if (plist_xml) {
|
||||
#ifdef PLIST_230
|
||||
plist_mem_free(plist_xml);
|
||||
plist_mem_free_wrapper(plist_xml);
|
||||
#else
|
||||
plist_to_xml_free(plist_xml);
|
||||
#endif
|
||||
@@ -570,52 +557,55 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
plist_get_data_val(req_params_fcup_response_data_node, &fcup_response_data, &uint_val);
|
||||
fcup_response_datalen = (int) uint_val;
|
||||
|
||||
char *playlist = NULL;
|
||||
if (!fcup_response_data) {
|
||||
goto post_action_error;
|
||||
} else {
|
||||
playlist = (char *) malloc(fcup_response_datalen + 1);
|
||||
playlist[fcup_response_datalen] = '\0';
|
||||
memcpy(playlist, fcup_response_data, fcup_response_datalen);
|
||||
plist_mem_free_wrapper(fcup_response_data);
|
||||
}
|
||||
assert(playlist);
|
||||
int playlist_len = strlen(playlist);
|
||||
|
||||
if (logger_debug) {
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response datalen = %d", fcup_response_datalen);
|
||||
char *data = malloc(fcup_response_datalen + 1);
|
||||
memcpy(data, fcup_response_data, fcup_response_datalen);
|
||||
data[fcup_response_datalen] = '\0';
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "begin FCUP Response data:\n%s\nend FCUP Response data",data);
|
||||
free (data);
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "begin FCUP Response data:\n%s\nend FCUP Response data", playlist);
|
||||
}
|
||||
|
||||
|
||||
char *ptr = strstr(fcup_response_url, "/master.m3u8");
|
||||
if (ptr) {
|
||||
/* this is a master playlist */
|
||||
char *uri_prefix = get_uri_prefix(airplay_video);
|
||||
char ** media_data_store = NULL;
|
||||
char ** uri_list = NULL;
|
||||
int num_uri = 0;
|
||||
|
||||
char *uri_local_prefix = get_uri_local_prefix(airplay_video);
|
||||
char *new_master = adjust_master_playlist (fcup_response_data, fcup_response_datalen, uri_prefix, uri_local_prefix);
|
||||
playlist = select_master_playlist_language(airplay_video, playlist);
|
||||
playlist_len = strlen(playlist);
|
||||
create_media_uri_table(uri_prefix, playlist, playlist_len, &uri_list, &num_uri);
|
||||
char *new_master = adjust_master_playlist (playlist, playlist_len, uri_prefix, uri_local_prefix);
|
||||
free(playlist);
|
||||
store_master_playlist(airplay_video, new_master);
|
||||
create_media_uri_table(uri_prefix, fcup_response_data, fcup_response_datalen, &media_data_store, &num_uri);
|
||||
create_media_data_store(airplay_video, media_data_store, num_uri);
|
||||
create_media_data_store(airplay_video, uri_list, num_uri);
|
||||
free (uri_list);
|
||||
num_uri = get_num_media_uri(airplay_video);
|
||||
set_next_media_uri_id(airplay_video, 0);
|
||||
} else {
|
||||
/* this is a media playlist */
|
||||
assert(fcup_response_data);
|
||||
char *playlist = (char *) calloc(fcup_response_datalen + 1, sizeof(char));
|
||||
memcpy(playlist, fcup_response_data, fcup_response_datalen);
|
||||
int uri_num = get_next_media_uri_id(airplay_video);
|
||||
--uri_num; // (next num is current num + 1)
|
||||
store_media_playlist(airplay_video, playlist, uri_num);
|
||||
float duration = 0.0f;
|
||||
int count = analyze_media_playlist(playlist, &duration);
|
||||
if (count) {
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG,
|
||||
"\n%s:\nreceived media playlist has %5d chunks, total duration %9.3f secs\n",
|
||||
fcup_response_url, count, duration);
|
||||
int uri_num = get_next_media_uri_id(airplay_video);
|
||||
--uri_num; // (next num is current num + 1)
|
||||
int ret = store_media_playlist(airplay_video, playlist, &count, &duration, uri_num);
|
||||
if (ret == 1) {
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG,"media_playlist is a duplicate: do not store");
|
||||
} else if (count) {
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG,
|
||||
"\n%s:\nreceived media playlist has %5d chunks, total duration %9.3f secs\n",
|
||||
fcup_response_url, count, duration);
|
||||
}
|
||||
}
|
||||
|
||||
plist_mem_free_wrapper(fcup_response_data);
|
||||
plist_mem_free_wrapper(fcup_response_url);
|
||||
|
||||
int num_uri = get_num_media_uri(airplay_video);
|
||||
@@ -715,7 +705,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
char* playback_uuid = NULL;
|
||||
plist_get_string_val(req_uuid_node, &playback_uuid);
|
||||
set_playback_uuid(airplay_video, playback_uuid);
|
||||
plist_mem_free (playback_uuid);
|
||||
plist_mem_free_wrapper (playback_uuid);
|
||||
}
|
||||
|
||||
plist_t req_content_location_node = plist_dict_get_item(req_root_node, "Content-Location");
|
||||
@@ -734,7 +724,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
logger_log(conn->raop->logger, LOGGER_WARNING, "Unsupported HLS streaming format: clientProcName %s not found in supported list: %s",
|
||||
client_proc_name, supported_hls_proc_names);
|
||||
}
|
||||
plist_mem_free(client_proc_name);
|
||||
plist_mem_free_wrapper(client_proc_name);
|
||||
}
|
||||
|
||||
plist_t req_start_position_seconds_node = plist_dict_get_item(req_root_node, "Start-Position-Seconds");
|
||||
@@ -758,7 +748,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
set_next_media_uri_id(airplay_video, 0);
|
||||
fcup_request((void *) conn, playback_location, apple_session_id, get_next_FCUP_RequestID(airplay_video));
|
||||
|
||||
plist_mem_free(playback_location);
|
||||
plist_mem_free_wrapper(playback_location);
|
||||
|
||||
if (req_root_node) {
|
||||
plist_free(req_root_node);
|
||||
@@ -766,7 +756,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
return;
|
||||
|
||||
play_error:;
|
||||
plist_mem_free(playback_location);
|
||||
plist_mem_free_wrapper(playback_location);
|
||||
if (req_root_node) {
|
||||
plist_free(req_root_node);
|
||||
}
|
||||
@@ -817,19 +807,20 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
}
|
||||
|
||||
} else {
|
||||
char *media_playlist = get_media_playlist(airplay_video, url);
|
||||
int chunks;
|
||||
float duration;
|
||||
char *media_playlist = get_media_playlist(airplay_video, &chunks, &duration, url);
|
||||
if (media_playlist) {
|
||||
char *data = adjust_yt_condensed_playlist(media_playlist);
|
||||
*response_data = data;
|
||||
*response_datalen = strlen(data);
|
||||
float duration = 0.0f;
|
||||
int chunks = analyze_media_playlist(data, &duration);
|
||||
logger_log(conn->raop->logger, LOGGER_INFO,
|
||||
"Requested media_playlist %s has %5d chunks, total duration %9.3f secs", url, chunks, duration);
|
||||
} else {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR,"requested media playlist %s not found", url);
|
||||
*response_datalen = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
http_response_add_header(response, "Access-Control-Allow-Headers", "Content-type");
|
||||
|
||||
12
lib/raop.c
12
lib/raop.c
@@ -33,6 +33,18 @@
|
||||
#include "raop_rtp_mirror.h"
|
||||
#include "raop_ntp.h"
|
||||
|
||||
static void
|
||||
plist_mem_free_wrapper(char * plist_ptr) {
|
||||
/* wrapper for plist_mem_free, only available since libplist 2.3.0 */
|
||||
if (plist_ptr) {
|
||||
#ifdef PLIST_230
|
||||
plist_mem_free (plst_ptr);
|
||||
#else
|
||||
free (plist_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct raop_s {
|
||||
/* Callbacks for audio and video */
|
||||
raop_callbacks_t callbacks;
|
||||
|
||||
@@ -32,13 +32,6 @@
|
||||
typedef void (*raop_handler_t)(raop_conn_t *, http_request_t *,
|
||||
http_response_t *, char **, int *);
|
||||
|
||||
#ifndef PLIST_230
|
||||
void plist_mem_free(void* ptr) {
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
raop_handler_info(raop_conn_t *conn,
|
||||
@@ -87,8 +80,9 @@ raop_handler_info(raop_conn_t *conn,
|
||||
} else if (!strcmp(qualifier_string, txtRAOP)) {
|
||||
add_txt_raop = true;
|
||||
}
|
||||
plist_mem_free(qualifier_string);
|
||||
plist_mem_free_wrapper(qualifier_string);
|
||||
}
|
||||
plist_free(req_root_node);
|
||||
}
|
||||
|
||||
|
||||
@@ -327,7 +321,7 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
|
||||
plist_free (req_root_node);
|
||||
return;
|
||||
}
|
||||
plist_mem_free(method);
|
||||
plist_mem_free_wrapper(method);
|
||||
method = NULL;
|
||||
plist_get_string_val(req_user_node, &user);
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "pair-setup-pin: device_id = %s", user);
|
||||
@@ -337,7 +331,7 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
|
||||
}
|
||||
int ret = srp_new_user(conn->session, conn->raop->pairing, (const char *) user,
|
||||
(const char *) pin, &salt, &len_salt, &pk, &len_pk);
|
||||
plist_mem_free(user);
|
||||
plist_mem_free_wrapper(user);
|
||||
user = NULL;
|
||||
plist_free(req_root_node);
|
||||
if (ret < 0) {
|
||||
@@ -760,11 +754,11 @@ raop_handler_setup(raop_conn_t *conn,
|
||||
free (client_pk);
|
||||
}
|
||||
}
|
||||
plist_mem_free(deviceID);
|
||||
plist_mem_free_wrapper(deviceID);
|
||||
deviceID = NULL;
|
||||
plist_mem_free(model);
|
||||
plist_mem_free_wrapper(model);
|
||||
model = NULL;
|
||||
plist_mem_free(name);
|
||||
plist_mem_free_wrapper(name);
|
||||
name = NULL;
|
||||
if (admit_client == false) {
|
||||
/* client is not authorized to connect */
|
||||
@@ -877,7 +871,7 @@ raop_handler_setup(raop_conn_t *conn,
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Client specified timingProtocol=%s,"
|
||||
" but timingProtocol= NTP is required here", timing_protocol);
|
||||
}
|
||||
plist_mem_free (timing_protocol);
|
||||
plist_mem_free_wrapper (timing_protocol);
|
||||
timing_protocol = NULL;
|
||||
} else {
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "Client did not specify timingProtocol,"
|
||||
@@ -1176,7 +1170,7 @@ raop_handler_audiomode(raop_conn_t *conn,
|
||||
/* not sure what should be done with this request: usually audioMode requested is "default" */
|
||||
int log_level = (strstr(audiomode, "default") ? LOGGER_DEBUG : LOGGER_INFO);
|
||||
logger_log(conn->raop->logger, log_level, "Unhandled RTSP request \"audioMode: %s\"", audiomode);
|
||||
plist_mem_free(audiomode);
|
||||
plist_mem_free_wrapper(audiomode);
|
||||
plist_free(req_root_node);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user