2
* Copyright (C) 2008 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
3
* Copyright (C) 2008 Nokia Corporation.
5
* Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6
* <zeeshan.ali@nokia.com>
8
* This file is part of Rygel.
10
* Rygel is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU Lesser General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* Rygel is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public License
21
* along with this program; if not, write to the Free Software Foundation,
22
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26
#include <glib-object.h>
28
#include <libsoup/soup.h>
33
#define RYGEL_TYPE_STATE_MACHINE (rygel_state_machine_get_type ())
34
#define RYGEL_STATE_MACHINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_STATE_MACHINE, RygelStateMachine))
35
#define RYGEL_IS_STATE_MACHINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_STATE_MACHINE))
36
#define RYGEL_STATE_MACHINE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), RYGEL_TYPE_STATE_MACHINE, RygelStateMachineIface))
38
typedef struct _RygelStateMachine RygelStateMachine;
39
typedef struct _RygelStateMachineIface RygelStateMachineIface;
41
#define RYGEL_TYPE_HTTP_RESPONSE (rygel_http_response_get_type ())
42
#define RYGEL_HTTP_RESPONSE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_HTTP_RESPONSE, RygelHTTPResponse))
43
#define RYGEL_HTTP_RESPONSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_HTTP_RESPONSE, RygelHTTPResponseClass))
44
#define RYGEL_IS_HTTP_RESPONSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_HTTP_RESPONSE))
45
#define RYGEL_IS_HTTP_RESPONSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_HTTP_RESPONSE))
46
#define RYGEL_HTTP_RESPONSE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_HTTP_RESPONSE, RygelHTTPResponseClass))
48
typedef struct _RygelHTTPResponse RygelHTTPResponse;
49
typedef struct _RygelHTTPResponseClass RygelHTTPResponseClass;
50
typedef struct _RygelHTTPResponsePrivate RygelHTTPResponsePrivate;
52
#define RYGEL_TYPE_SEEKABLE_RESPONSE (rygel_seekable_response_get_type ())
53
#define RYGEL_SEEKABLE_RESPONSE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_SEEKABLE_RESPONSE, RygelSeekableResponse))
54
#define RYGEL_SEEKABLE_RESPONSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_SEEKABLE_RESPONSE, RygelSeekableResponseClass))
55
#define RYGEL_IS_SEEKABLE_RESPONSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_SEEKABLE_RESPONSE))
56
#define RYGEL_IS_SEEKABLE_RESPONSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_SEEKABLE_RESPONSE))
57
#define RYGEL_SEEKABLE_RESPONSE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_SEEKABLE_RESPONSE, RygelSeekableResponseClass))
59
typedef struct _RygelSeekableResponse RygelSeekableResponse;
60
typedef struct _RygelSeekableResponseClass RygelSeekableResponseClass;
61
typedef struct _RygelSeekableResponsePrivate RygelSeekableResponsePrivate;
63
#define RYGEL_TYPE_HTTP_SEEK (rygel_http_seek_get_type ())
64
#define RYGEL_HTTP_SEEK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_HTTP_SEEK, RygelHTTPSeek))
65
#define RYGEL_HTTP_SEEK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_HTTP_SEEK, RygelHTTPSeekClass))
66
#define RYGEL_IS_HTTP_SEEK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_HTTP_SEEK))
67
#define RYGEL_IS_HTTP_SEEK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_HTTP_SEEK))
68
#define RYGEL_HTTP_SEEK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_HTTP_SEEK, RygelHTTPSeekClass))
70
typedef struct _RygelHTTPSeek RygelHTTPSeek;
71
typedef struct _RygelHTTPSeekClass RygelHTTPSeekClass;
72
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
73
#define _g_free0(var) (var = (g_free (var), NULL))
74
#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
76
struct _RygelStateMachineIface {
77
GTypeInterface parent_iface;
78
void (*run) (RygelStateMachine* self);
79
GCancellable* (*get_cancellable) (RygelStateMachine* self);
80
void (*set_cancellable) (RygelStateMachine* self, GCancellable* value);
83
struct _RygelHTTPResponse {
84
GObject parent_instance;
85
RygelHTTPResponsePrivate * priv;
89
struct _RygelHTTPResponseClass {
90
GObjectClass parent_class;
91
void (*run) (RygelHTTPResponse* self);
92
void (*end) (RygelHTTPResponse* self, gboolean aborted, guint status);
95
struct _RygelSeekableResponse {
96
RygelHTTPResponse parent_instance;
97
RygelSeekableResponsePrivate * priv;
100
struct _RygelSeekableResponseClass {
101
RygelHTTPResponseClass parent_class;
104
struct _RygelSeekableResponsePrivate {
107
GFileInputStream* input_stream;
116
static gpointer rygel_seekable_response_parent_class = NULL;
118
GType rygel_state_machine_get_type (void);
119
GType rygel_http_response_get_type (void);
120
GType rygel_seekable_response_get_type (void);
121
GType rygel_http_seek_get_type (void);
122
#define RYGEL_SEEKABLE_RESPONSE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RYGEL_TYPE_SEEKABLE_RESPONSE, RygelSeekableResponsePrivate))
124
RYGEL_SEEKABLE_RESPONSE_DUMMY_PROPERTY
126
#define RYGEL_SEEKABLE_RESPONSE_BUFFER_LENGTH ((gsize) 4096)
127
RygelHTTPResponse* rygel_http_response_construct (GType object_type, SoupServer* server, SoupMessage* msg, gboolean partial, GCancellable* cancellable);
128
static gint rygel_seekable_response_get_requested_priority (RygelSeekableResponse* self);
129
gint64 rygel_http_seek_get_length (RygelHTTPSeek* self);
130
static void rygel_seekable_response_on_wrote_chunk (RygelSeekableResponse* self, SoupMessage* msg);
131
static void _rygel_seekable_response_on_wrote_chunk_soup_message_wrote_chunk (SoupMessage* _sender, gpointer self);
132
RygelSeekableResponse* rygel_seekable_response_new (SoupServer* server, SoupMessage* msg, const char* uri, RygelHTTPSeek* seek, gsize file_length, GCancellable* cancellable);
133
RygelSeekableResponse* rygel_seekable_response_construct (GType object_type, SoupServer* server, SoupMessage* msg, const char* uri, RygelHTTPSeek* seek, gsize file_length, GCancellable* cancellable);
134
GCancellable* rygel_state_machine_get_cancellable (RygelStateMachine* self);
135
void rygel_state_machine_set_cancellable (RygelStateMachine* self, GCancellable* value);
136
static void rygel_seekable_response_on_file_read (RygelSeekableResponse* self, GObject* source_object, GAsyncResult* _result_);
137
static void _rygel_seekable_response_on_file_read_gasync_ready_callback (GObject* source_object, GAsyncResult* res, gpointer self);
138
static void rygel_seekable_response_real_run (RygelHTTPResponse* base);
139
void rygel_http_response_end (RygelHTTPResponse* self, gboolean aborted, guint status);
140
gint64 rygel_http_seek_get_start (RygelHTTPSeek* self);
141
gint64 rygel_http_seek_get_stop (RygelHTTPSeek* self);
142
static void rygel_seekable_response_on_contents_read (RygelSeekableResponse* self, GObject* source_object, GAsyncResult* _result_);
143
static void _rygel_seekable_response_on_contents_read_gasync_ready_callback (GObject* source_object, GAsyncResult* res, gpointer self);
144
void rygel_http_response_push_data (RygelHTTPResponse* self, void* data, gsize length);
145
static void rygel_seekable_response_on_input_stream_closed (RygelSeekableResponse* self, GObject* source_object, GAsyncResult* _result_);
146
static void _rygel_seekable_response_on_input_stream_closed_gasync_ready_callback (GObject* source_object, GAsyncResult* res, gpointer self);
147
static void rygel_seekable_response_finalize (GObject* obj);
148
static int _vala_strcmp0 (const char * str1, const char * str2);
152
static gpointer _g_object_ref0 (gpointer self) {
153
return self ? g_object_ref (self) : NULL;
157
static void _rygel_seekable_response_on_wrote_chunk_soup_message_wrote_chunk (SoupMessage* _sender, gpointer self) {
158
rygel_seekable_response_on_wrote_chunk (self, _sender);
162
RygelSeekableResponse* rygel_seekable_response_construct (GType object_type, SoupServer* server, SoupMessage* msg, const char* uri, RygelHTTPSeek* seek, gsize file_length, GCancellable* cancellable) {
163
RygelSeekableResponse * self;
164
RygelHTTPSeek* _tmp0_;
167
g_return_val_if_fail (server != NULL, NULL);
168
g_return_val_if_fail (msg != NULL, NULL);
169
g_return_val_if_fail (uri != NULL, NULL);
170
self = (RygelSeekableResponse*) rygel_http_response_construct (object_type, server, msg, seek != NULL, cancellable);
171
self->priv->seek = (_tmp0_ = _g_object_ref0 (seek), _g_object_unref0 (self->priv->seek), _tmp0_);
172
self->priv->total_length = file_length;
173
self->priv->priority = rygel_seekable_response_get_requested_priority (self);
175
self->priv->total_length = (gsize) rygel_http_seek_get_length (seek);
177
self->priv->total_length = file_length;
179
g_signal_connect_object (msg, "wrote-chunk", (GCallback) _rygel_seekable_response_on_wrote_chunk_soup_message_wrote_chunk, self, 0);
180
self->priv->buffer = (_tmp1_ = g_new0 (gchar, RYGEL_SEEKABLE_RESPONSE_BUFFER_LENGTH), self->priv->buffer = (g_free (self->priv->buffer), NULL), self->priv->buffer_length1 = RYGEL_SEEKABLE_RESPONSE_BUFFER_LENGTH, self->priv->buffer_size = self->priv->buffer_length1, _tmp1_);
181
self->priv->file = (_tmp2_ = g_file_new_for_uri (uri), _g_object_unref0 (self->priv->file), _tmp2_);
186
RygelSeekableResponse* rygel_seekable_response_new (SoupServer* server, SoupMessage* msg, const char* uri, RygelHTTPSeek* seek, gsize file_length, GCancellable* cancellable) {
187
return rygel_seekable_response_construct (RYGEL_TYPE_SEEKABLE_RESPONSE, server, msg, uri, seek, file_length, cancellable);
191
static void _rygel_seekable_response_on_file_read_gasync_ready_callback (GObject* source_object, GAsyncResult* res, gpointer self) {
192
rygel_seekable_response_on_file_read (self, source_object, res);
196
static void rygel_seekable_response_real_run (RygelHTTPResponse* base) {
197
RygelSeekableResponse * self;
198
self = (RygelSeekableResponse*) base;
199
rygel_state_machine_set_cancellable ((RygelStateMachine*) self, rygel_state_machine_get_cancellable ((RygelStateMachine*) self));
200
g_file_read_async (self->priv->file, self->priv->priority, rygel_state_machine_get_cancellable ((RygelStateMachine*) self), _rygel_seekable_response_on_file_read_gasync_ready_callback, self);
204
static void _rygel_seekable_response_on_contents_read_gasync_ready_callback (GObject* source_object, GAsyncResult* res, gpointer self) {
205
rygel_seekable_response_on_contents_read (self, source_object, res);
209
static void rygel_seekable_response_on_file_read (RygelSeekableResponse* self, GObject* source_object, GAsyncResult* _result_) {
210
GError * _inner_error_;
211
g_return_if_fail (self != NULL);
212
g_return_if_fail (_result_ != NULL);
213
_inner_error_ = NULL;
215
GFileInputStream* _tmp0_;
216
GFileInputStream* _tmp1_;
217
_tmp0_ = g_file_read_finish (self->priv->file, _result_, &_inner_error_);
218
if (_inner_error_ != NULL) {
219
goto __catch22_g_error;
222
self->priv->input_stream = (_tmp1_ = _tmp0_, _g_object_unref0 (self->priv->input_stream), _tmp1_);
229
_inner_error_ = NULL;
232
g_warning ("rygel-seekable-response.vala:74: Failed to read from URI: %s: %s\n", _tmp2_ = g_file_get_uri (self->priv->file), err->message);
234
rygel_http_response_end ((RygelHTTPResponse*) self, FALSE, (guint) SOUP_STATUS_NOT_FOUND);
235
_g_error_free0 (err);
240
if (_inner_error_ != NULL) {
241
g_critical ("file %s: line %d: uncaught error: %s", __FILE__, __LINE__, _inner_error_->message);
242
g_clear_error (&_inner_error_);
245
if (self->priv->seek != NULL) {
247
G_FILE_INPUT_STREAM_GET_CLASS (self->priv->input_stream)->seek (self->priv->input_stream, rygel_http_seek_get_start (self->priv->seek), G_SEEK_SET, rygel_state_machine_get_cancellable ((RygelStateMachine*) self), &_inner_error_);
248
if (_inner_error_ != NULL) {
249
goto __catch23_g_error;
258
_inner_error_ = NULL;
263
g_warning ("rygel-seekable-response.vala:87: Failed to seek to %s-%s on URI %s: %s\n", _tmp3_ = g_strdup_printf ("%lli", rygel_http_seek_get_start (self->priv->seek)), _tmp4_ = g_strdup_printf ("%lli", rygel_http_seek_get_stop (self->priv->seek)), _tmp5_ = g_file_get_uri (self->priv->file), err->message);
267
rygel_http_response_end ((RygelHTTPResponse*) self, FALSE, (guint) SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
268
_g_error_free0 (err);
273
if (_inner_error_ != NULL) {
274
g_critical ("file %s: line %d: uncaught error: %s", __FILE__, __LINE__, _inner_error_->message);
275
g_clear_error (&_inner_error_);
279
g_input_stream_read_async ((GInputStream*) self->priv->input_stream, self->priv->buffer, RYGEL_SEEKABLE_RESPONSE_BUFFER_LENGTH, self->priv->priority, rygel_state_machine_get_cancellable ((RygelStateMachine*) self), _rygel_seekable_response_on_contents_read_gasync_ready_callback, self);
283
static void _rygel_seekable_response_on_input_stream_closed_gasync_ready_callback (GObject* source_object, GAsyncResult* res, gpointer self) {
284
rygel_seekable_response_on_input_stream_closed (self, source_object, res);
288
static void rygel_seekable_response_on_contents_read (RygelSeekableResponse* self, GObject* source_object, GAsyncResult* _result_) {
289
GError * _inner_error_;
290
GFileInputStream* input_stream;
292
g_return_if_fail (self != NULL);
293
g_return_if_fail (_result_ != NULL);
294
_inner_error_ = NULL;
295
input_stream = _g_object_ref0 (G_FILE_INPUT_STREAM (source_object));
299
_tmp0_ = g_input_stream_read_finish ((GInputStream*) input_stream, _result_, &_inner_error_);
300
if (_inner_error_ != NULL) {
301
goto __catch24_g_error;
311
_inner_error_ = NULL;
314
g_warning ("rygel-seekable-response.vala:113: Failed to read contents from URI: %s: %s\n", _tmp1_ = g_file_get_uri (self->priv->file), err->message);
316
rygel_http_response_end ((RygelHTTPResponse*) self, FALSE, (guint) SOUP_STATUS_NOT_FOUND);
317
_g_error_free0 (err);
318
_g_object_unref0 (input_stream);
323
if (_inner_error_ != NULL) {
324
_g_object_unref0 (input_stream);
325
g_critical ("file %s: line %d: uncaught error: %s", __FILE__, __LINE__, _inner_error_->message);
326
g_clear_error (&_inner_error_);
329
if (bytes_read > 0) {
330
rygel_http_response_push_data ((RygelHTTPResponse*) self, self->priv->buffer, (gsize) bytes_read);
332
g_input_stream_close_async ((GInputStream*) input_stream, self->priv->priority, rygel_state_machine_get_cancellable ((RygelStateMachine*) self), _rygel_seekable_response_on_input_stream_closed_gasync_ready_callback, self);
334
_g_object_unref0 (input_stream);
338
static void rygel_seekable_response_on_input_stream_closed (RygelSeekableResponse* self, GObject* source_object, GAsyncResult* _result_) {
339
GError * _inner_error_;
340
GFileInputStream* input_stream;
341
g_return_if_fail (self != NULL);
342
g_return_if_fail (_result_ != NULL);
343
_inner_error_ = NULL;
344
input_stream = _g_object_ref0 (G_FILE_INPUT_STREAM (source_object));
346
g_input_stream_close_finish ((GInputStream*) input_stream, _result_, &_inner_error_);
347
if (_inner_error_ != NULL) {
348
goto __catch25_g_error;
357
_inner_error_ = NULL;
360
g_warning ("rygel-seekable-response.vala:136: Failed to close stream to URI %s: %s\n", _tmp0_ = g_file_get_uri (self->priv->file), err->message);
362
_g_error_free0 (err);
366
if (_inner_error_ != NULL) {
367
_g_object_unref0 (input_stream);
368
g_critical ("file %s: line %d: uncaught error: %s", __FILE__, __LINE__, _inner_error_->message);
369
g_clear_error (&_inner_error_);
372
rygel_http_response_end ((RygelHTTPResponse*) self, FALSE, (guint) SOUP_STATUS_NONE);
373
_g_object_unref0 (input_stream);
377
static void rygel_seekable_response_on_wrote_chunk (RygelSeekableResponse* self, SoupMessage* msg) {
378
g_return_if_fail (self != NULL);
379
g_return_if_fail (msg != NULL);
380
g_input_stream_read_async ((GInputStream*) self->priv->input_stream, self->priv->buffer, RYGEL_SEEKABLE_RESPONSE_BUFFER_LENGTH, self->priv->priority, rygel_state_machine_get_cancellable ((RygelStateMachine*) self), _rygel_seekable_response_on_contents_read_gasync_ready_callback, self);
384
static gint rygel_seekable_response_get_requested_priority (RygelSeekableResponse* self) {
388
g_return_val_if_fail (self != NULL, 0);
389
mode = g_strdup (soup_message_headers_get (((RygelHTTPResponse*) self)->msg->request_headers, "transferMode.dlna.org"));
394
_tmp0_ = _vala_strcmp0 (mode, "Interactive") == 0;
397
result = G_PRIORITY_DEFAULT;
401
if (_vala_strcmp0 (mode, "Streaming") == 0) {
402
result = G_PRIORITY_HIGH;
406
if (_vala_strcmp0 (mode, "Background") == 0) {
407
result = G_PRIORITY_LOW;
411
result = G_PRIORITY_DEFAULT;
421
static void rygel_seekable_response_class_init (RygelSeekableResponseClass * klass) {
422
rygel_seekable_response_parent_class = g_type_class_peek_parent (klass);
423
g_type_class_add_private (klass, sizeof (RygelSeekableResponsePrivate));
424
RYGEL_HTTP_RESPONSE_CLASS (klass)->run = rygel_seekable_response_real_run;
425
G_OBJECT_CLASS (klass)->finalize = rygel_seekable_response_finalize;
429
static void rygel_seekable_response_instance_init (RygelSeekableResponse * self) {
430
self->priv = RYGEL_SEEKABLE_RESPONSE_GET_PRIVATE (self);
434
static void rygel_seekable_response_finalize (GObject* obj) {
435
RygelSeekableResponse * self;
436
self = RYGEL_SEEKABLE_RESPONSE (obj);
437
_g_object_unref0 (self->priv->seek);
438
_g_object_unref0 (self->priv->file);
439
_g_object_unref0 (self->priv->input_stream);
440
self->priv->buffer = (g_free (self->priv->buffer), NULL);
441
G_OBJECT_CLASS (rygel_seekable_response_parent_class)->finalize (obj);
445
GType rygel_seekable_response_get_type (void) {
446
static GType rygel_seekable_response_type_id = 0;
447
if (rygel_seekable_response_type_id == 0) {
448
static const GTypeInfo g_define_type_info = { sizeof (RygelSeekableResponseClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) rygel_seekable_response_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (RygelSeekableResponse), 0, (GInstanceInitFunc) rygel_seekable_response_instance_init, NULL };
449
rygel_seekable_response_type_id = g_type_register_static (RYGEL_TYPE_HTTP_RESPONSE, "RygelSeekableResponse", &g_define_type_info, 0);
451
return rygel_seekable_response_type_id;
455
static int _vala_strcmp0 (const char * str1, const char * str2) {
457
return -(str1 != str2);
462
return strcmp (str1, str2);