memory leak cleanups (valgrind) in airplay_video + http_handlers

This commit is contained in:
F. Duncanh
2025-11-14 18:38:07 -05:00
parent 47da1e03db
commit 372b0ab789
5 changed files with 114 additions and 76 deletions

View File

@@ -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,

View File

@@ -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);

View File

@@ -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");

View File

@@ -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;

View File

@@ -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);
}