From e7f64192643f5783e19482a11697de9ec3eea033 Mon Sep 17 00:00:00 2001 From: Jens Georg <mail@jensge.org> Date: Thu, 2 Jun 2022 22:36:05 +0200 Subject: [PATCH 2/2] Port to GUPnP 1.6 --- libdleyna/server/device.c | 111 +++++++++++++++++++++-------------- libdleyna/server/device.h | 3 +- libdleyna/server/meson.build | 2 +- meson.build | 10 ++-- 4 files changed, 75 insertions(+), 51 deletions(-) diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c index c05c77f..daa30fd 100644 --- a/libdleyna/server/device.c +++ b/libdleyna/server/device.c @@ -92,6 +92,7 @@ typedef struct dls_device_upload_t_ dls_device_upload_t; struct dls_device_upload_t_ { SoupSession *soup_session; SoupMessage *msg; + GCancellable *cancellable; GMappedFile *mapped_file; gchar *body; gsize body_length; @@ -110,6 +111,7 @@ struct dls_device_upload_job_t_ { typedef struct dls_device_download_t_ dls_device_download_t; struct dls_device_download_t_ { SoupSession *session; + GCancellable *cancellable; SoupMessage *msg; dls_async_task_t *task; }; @@ -376,7 +378,7 @@ void dls_device_delete(void *device) g_variant_unref(dev->sort_ext_caps); g_variant_unref(dev->feature_list); g_free(dev->icon.mime_type); - g_free(dev->icon.bytes); + g_bytes_unref(dev->icon.bytes); g_free(dev); } } @@ -4335,18 +4337,25 @@ static void prv_generate_upload_update(dls_device_upload_job_t *upload_job, NULL); } -static void prv_post_finished(SoupSession *session, SoupMessage *msg, +static void prv_post_finished(GObject *source, GAsyncResult *res, gpointer user_data) { dls_device_upload_job_t *upload_job = user_data; dls_device_upload_t *upload; gint *upload_id; + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) data = NULL; + SoupMessage *msg = soup_session_get_async_result_message( + SOUP_SESSION(source), res); DLEYNA_LOG_DEBUG("Enter"); DLEYNA_LOG_DEBUG("Upload %u finished. Code %u Message %s", - upload_job->upload_id, msg->status_code, - msg->reason_phrase); + upload_job->upload_id, soup_message_get_status(msg), + soup_message_get_reason_phrase (msg)); + + data = soup_session_send_and_read_finish(SOUP_SESSION(source), res, + &error); /* This is clumsy but we need to distinguish between two cases: 1. We cancel because the process is exitting. @@ -4371,20 +4380,25 @@ static void prv_post_finished(SoupSession *session, SoupMessage *msg, upload_job->remove_idle = g_timeout_add_seconds(30, prv_remove_update_job, user_data); - if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { - upload->status = DLS_UPLOAD_STATUS_COMPLETED; - upload->bytes_uploaded = upload->bytes_to_upload; - } else if (msg->status_code == SOUP_STATUS_CANCELLED) { + // FIXME... + if(g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { upload->status = DLS_UPLOAD_STATUS_CANCELLED; } else { - upload->status = DLS_UPLOAD_STATUS_ERROR; + SoupStatus status = + soup_message_get_status(upload->msg); + if(SOUP_STATUS_IS_SUCCESSFUL(status)) { + upload->status = DLS_UPLOAD_STATUS_COMPLETED; + upload->bytes_uploaded = + upload->bytes_to_upload; + } else { + upload->status = DLS_UPLOAD_STATUS_ERROR; + } } DLEYNA_LOG_DEBUG("Upload Status: %s", upload->status); prv_generate_upload_update(upload_job, upload); - g_object_unref(upload->msg); upload->msg = NULL; g_object_unref(upload->soup_session); @@ -4420,10 +4434,9 @@ static void prv_upload_delete(gpointer up) if (upload) { if (upload->msg) { - soup_session_cancel_message(upload->soup_session, - upload->msg, - SOUP_STATUS_CANCELLED); + g_cancellable_cancel(upload->cancellable); g_object_unref(upload->msg); + g_object_unref(upload->cancellable); } if (upload->soup_session) @@ -4440,12 +4453,12 @@ static void prv_upload_delete(gpointer up) DLEYNA_LOG_DEBUG("Exit"); } -static void prv_post_bytes_written(SoupMessage *msg, SoupBuffer *chunk, +static void prv_post_bytes_written(SoupMessage *msg, guint chunk_size, gpointer user_data) { dls_device_upload_t *upload = user_data; - upload->bytes_uploaded += chunk->length; + upload->bytes_uploaded += chunk_size; if (upload->bytes_uploaded > upload->bytes_to_upload) upload->bytes_uploaded = upload->bytes_to_upload; } @@ -4484,6 +4497,7 @@ static dls_device_upload_t *prv_upload_data_new(const gchar *file_path, upload = g_new0(dls_device_upload_t, 1); upload->soup_session = soup_session_new(); + upload->cancellable = g_cancellable_new(); upload->msg = soup_message_new("POST", import_uri); upload->mapped_file = mapped_file; upload->body = body; @@ -4501,11 +4515,15 @@ static dls_device_upload_t *prv_upload_data_new(const gchar *file_path, upload->status = DLS_UPLOAD_STATUS_IN_PROGRESS; upload->bytes_to_upload = up_body_length; - soup_message_headers_set_expectations(upload->msg->request_headers, + SoupMessageHeaders *headers = + soup_message_get_request_headers(upload->msg); + soup_message_headers_set_expectations(headers, SOUP_EXPECTATION_CONTINUE); - soup_message_set_request(upload->msg, mime_type, SOUP_MEMORY_STATIC, - up_body, up_body_length); + GInputStream *is = g_memory_input_stream_new_from_data( + up_body, up_body_length, NULL); + soup_message_set_request_body(upload->msg, mime_type, is, + up_body_length); g_signal_connect(upload->msg, "wrote-body-data", G_CALLBACK(prv_post_bytes_written), upload); @@ -4657,9 +4675,9 @@ static void prv_create_object_upload_cb(GObject *source, GAsyncResult *res, upload_job->device = cb_data->task.target.device; upload_job->upload_id = (gint) cb_data->task.target.device->upload_id; - soup_session_queue_message(upload->soup_session, upload->msg, - prv_post_finished, upload_job); - g_object_ref(upload->msg); + soup_session_send_and_read_async( + upload->soup_session, upload->msg, G_PRIORITY_DEFAULT, + upload->cancellable, prv_post_finished, upload_job); upload_id = g_new(gint, 1); *upload_id = upload_job->upload_id; @@ -4820,8 +4838,7 @@ gboolean dls_device_cancel_upload(dls_task_t *task, GError **error) } if (upload->msg) { - soup_session_cancel_message(upload->soup_session, upload->msg, - SOUP_STATUS_CANCELLED); + g_cancellable_cancel(upload->cancellable); DLEYNA_LOG_DEBUG("Cancelling Upload %u ", upload_id); } @@ -5442,9 +5459,11 @@ static void prv_build_icon_result(dls_device_t *device, dls_task_t *task) { GVariant *out_p[2]; + gsize size; + gconstpointer data = g_bytes_get_data(device->icon.bytes, &size); out_p[0] = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, - device->icon.bytes, - device->icon.size, + data, + size, 1); out_p[1] = g_variant_new_string(device->icon.mime_type); task->result = g_variant_ref_sink(g_variant_new_tuple(out_p, 2)); @@ -5458,8 +5477,7 @@ static void prv_get_icon_cancelled(GCancellable *cancellable, dls_async_task_cancelled_cb(cancellable, download->task); if (download->msg) { - soup_session_cancel_message(download->session, download->msg, - SOUP_STATUS_CANCELLED); + g_cancellable_cancel(download->cancellable); DLEYNA_LOG_DEBUG("Cancelling device icon download"); } } @@ -5468,31 +5486,39 @@ static void prv_free_download_info(dls_device_download_t *download) { if (download->msg) g_object_unref(download->msg); + if(download->cancellable) + g_object_unref(download->cancellable); g_object_unref(download->session); g_free(download); } -static void prv_get_icon_session_cb(SoupSession *session, - SoupMessage *msg, +static void prv_get_icon_session_cb(GObject *source, + GAsyncResult *res, gpointer user_data) { dls_device_download_t *download = (dls_device_download_t *)user_data; dls_async_task_t *cb_data = (dls_async_task_t *)download->task; dls_device_t *device = (dls_device_t *)cb_data->task.target.device; + g_autoptr(GError) error = NULL; + GBytes *data; + + data = soup_session_send_and_read_finish(SOUP_SESSION(source), res, + &error); - if (msg->status_code == SOUP_STATUS_CANCELLED) + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) goto out; - if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { - device->icon.size = msg->response_body->length; - device->icon.bytes = g_malloc(device->icon.size); - memcpy(device->icon.bytes, msg->response_body->data, - device->icon.size); + SoupStatus status = soup_message_get_status(download->msg); + + if (SOUP_STATUS_IS_SUCCESSFUL(status)) { + device->icon.bytes = data; prv_build_icon_result(device, &cb_data->task); } else { DLEYNA_LOG_DEBUG("Failed to GET device icon: %s", - msg->reason_phrase); + error != NULL + ? error->message + : soup_message_get_reason_phrase(download->msg)); cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_OPERATION_FAILED, @@ -5513,10 +5539,10 @@ void dls_device_get_icon(dls_client_t *client, dls_device_context_t *context; dls_async_task_t *cb_data = (dls_async_task_t *)task; dls_device_t *device = task->target.device; - gchar *url; + g_autofree gchar *url; dls_device_download_t *download; - if (device->icon.size != 0) { + if (device->icon.bytes != NULL) { prv_build_icon_result(device, task); goto end; } @@ -5538,6 +5564,7 @@ void dls_device_get_icon(dls_client_t *client, download->session = soup_session_new(); download->msg = soup_message_new(SOUP_METHOD_GET, url); download->task = cb_data; + download->cancellable = g_cancellable_new(); if (!download->msg) { DLEYNA_LOG_WARNING("Invalid URL %s", url); @@ -5556,11 +5583,9 @@ void dls_device_get_icon(dls_client_t *client, G_CALLBACK(prv_get_icon_cancelled), download, NULL); - g_object_ref(download->msg); - soup_session_queue_message(download->session, download->msg, - prv_get_icon_session_cb, download); - - g_free(url); + soup_session_send_and_read_async( + download->session, download->msg, G_PRIORITY_DEFAULT, + download->cancellable, prv_get_icon_session_cb, download); return; diff --git a/libdleyna/server/device.h b/libdleyna/server/device.h index 3b383e8..4c632d9 100755 --- a/libdleyna/server/device.h +++ b/libdleyna/server/device.h @@ -64,8 +64,7 @@ struct dls_device_context_t_ { typedef struct dls_device_icon_t_ dls_device_icon_t; struct dls_device_icon_t_ { gchar *mime_type; - guchar *bytes; - gsize size; + GBytes *bytes; }; struct dls_device_t_ { diff --git a/libdleyna/server/meson.build b/libdleyna/server/meson.build index 38a3815..506f6a3 100644 --- a/libdleyna/server/meson.build +++ b/libdleyna/server/meson.build @@ -62,7 +62,7 @@ pkg.generate( name: 'dleyna-server-service-1.0', description: 'UPnP & DLNA server library', version: meson.project_version(), - requires: ['gupnp-1.2', 'glib-2.0', 'gio-2.0', 'dleyna-core-1.0'], + requires: ['gupnp-1.6', 'glib-2.0', 'gio-2.0', 'dleyna-core-1.0'], install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig') ) diff --git a/meson.build b/meson.build index 4a44707..2e802a8 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('dleyna-server', 'c', version: '0.7.2') +project('dleyna-server', 'c', version: '0.8.0') pkg = import('pkgconfig') @@ -67,12 +67,12 @@ config_h = declare_dependency( glib = dependency('glib-2.0', version: '>= 2.28') gio = dependency('gio-2.0', version: '>=2.28') -gssdp = dependency('gssdp-1.2', version: '>= 1.2.0') -gupnp = dependency('gupnp-1.2', version: '>= 1.2.0') +gssdp = dependency('gssdp-1.6', version: '>= 1.2.0') +gupnp = dependency('gupnp-1.6', version: '>= 1.2.0') gupnp_av = dependency('gupnp-av-1.0', version: '>= 0.12.9') gupnp_dlna = dependency('gupnp-dlna-2.0', version: '>= 0.9.4') -soup = dependency('libsoup-2.4', version: '>= 2.28.2') -dleyna_core = dependency('dleyna-core-1.0', version: '>= 0.6.0', fallback: 'dleyna-core-1.0') +soup = dependency('libsoup-3.0', version: '>= 3.0') +dleyna_core = dependency('dleyna-core-1.0', version: '>= 0.8.0', fallback: 'dleyna-core-1.0') libxml2 = dependency('libxml-2.0') cc = meson.get_compiler('c') -- 2.37.3