gmyth/src/gmyth_file_transfer.c
author rosfran
Wed Dec 06 13:50:55 2006 +0000 (2006-12-06)
branchtrunk
changeset 203 a43fed947ec8
parent 202 0ef699880d59
child 205 01879d8f56db
permissions -rwxr-xr-x
[svn r204] Fixed problem with the MonitorHandler thread, removed from FileTransfer.
rosfran@41
     1
/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */
rosfran@41
     2
/**
rosfran@68
     3
 * GMyth Library
rosfran@68
     4
 *
rosfran@68
     5
 * @file gmyth/gmyth_file_transfer.c
rosfran@68
     6
 * 
rosfran@68
     7
 * @brief <p> GMythFileTransfer deals with the file streaming media remote/local
rosfran@68
     8
 * transfering to the MythTV frontend.
rosfran@68
     9
 *
rosfran@68
    10
 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
rosfran@68
    11
 * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
rosfran@68
    12
 *
rosfran@68
    13
 *//*
rosfran@68
    14
 * 
rosfran@68
    15
 * This program is free software; you can redistribute it and/or modify
rosfran@68
    16
 * it under the terms of the GNU Lesser General Public License as published by
rosfran@68
    17
 * the Free Software Foundation; either version 2 of the License, or
rosfran@68
    18
 * (at your option) any later version.
rosfran@68
    19
 *
rosfran@68
    20
 * This program is distributed in the hope that it will be useful,
rosfran@68
    21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rosfran@68
    22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rosfran@68
    23
 * GNU General Public License for more details.
rosfran@68
    24
 *
rosfran@68
    25
 * You should have received a copy of the GNU Lesser General Public License
rosfran@68
    26
 * along with this program; if not, write to the Free Software
rosfran@68
    27
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
rosfran@68
    28
 *
rosfran@68
    29
 * GStreamer MythTV plug-in properties:
rosfran@41
    30
 * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
rosfran@41
    31
 * - path (qurl - remote file to be opened)
rosfran@68
    32
 * - port number *   
rosfran@41
    33
 */
rosfran@41
    34
rosfran@42
    35
#include "gmyth_file_transfer.h"
rosfran@42
    36
#include "gmyth_livetv.h"
rosfran@42
    37
#include "gmyth_util.h"
rosfran@42
    38
#include "gmyth_socket.h"
rosfran@42
    39
#include "gmyth_stringlist.h"
renatofilho@131
    40
#include "gmyth_debug.h"
rosfran@41
    41
rosfran@41
    42
#include <unistd.h>
rosfran@41
    43
#include <glib.h>
rosfran@41
    44
rosfran@41
    45
#include <arpa/inet.h>
rosfran@41
    46
#include <sys/types.h>
rosfran@41
    47
#include <sys/socket.h>
rosfran@41
    48
#include <netdb.h>
rosfran@41
    49
#include <errno.h>
rosfran@41
    50
#include <stdlib.h>
melunko@117
    51
#include <assert.h>
rosfran@41
    52
melunko@112
    53
#define GMYTHTV_QUERY_HEADER		"QUERY_FILETRANSFER "
rosfran@41
    54
rosfran@41
    55
/* default values to the file transfer parameters */
rosfran@97
    56
#define GMYTHTV_USER_READ_AHEAD			TRUE
rosfran@97
    57
#define GMYTHTV_RETRIES							-1
rosfran@54
    58
#define GMYTHTV_FILE_SIZE						0
rosfran@41
    59
rosfran@177
    60
#define GMYTHTV_BUFFER_SIZE					8*1024
rosfran@41
    61
rosfran@54
    62
#define GMYTHTV_VERSION							30
rosfran@41
    63
rosfran@41
    64
#define GMYTHTV_TRANSFER_MAX_WAITS	700
rosfran@41
    65
rosfran@41
    66
#ifdef GMYTHTV_ENABLE_DEBUG
rosfran@54
    67
#define GMYTHTV_ENABLE_DEBUG				1
rosfran@41
    68
#else
rosfran@41
    69
#undef GMYTHTV_ENABLE_DEBUG
rosfran@41
    70
#endif
rosfran@41
    71
rosfran@41
    72
/* this NDEBUG is to maintain compatibility with GMyth library */
rosfran@41
    73
#ifndef NDEBUG
rosfran@54
    74
#define GMYTHTV_ENABLE_DEBUG				1
rosfran@41
    75
#endif
rosfran@41
    76
rosfran@41
    77
enum myth_sock_types {
rosfran@41
    78
  GMYTH_PLAYBACK_TYPE = 0,
rosfran@41
    79
  GMYTH_MONITOR_TYPE,
rosfran@41
    80
  GMYTH_FILETRANSFER_TYPE,
rosfran@41
    81
  GMYTH_RINGBUFFER_TYPE
rosfran@41
    82
};
rosfran@41
    83
rosfran@177
    84
//static GStaticMutex st_mutex = G_STATIC_MUTEX_INIT;
rosfran@115
    85
rosfran@41
    86
static void gmyth_file_transfer_class_init          (GMythFileTransferClass *klass);
rosfran@41
    87
static void gmyth_file_transfer_init                (GMythFileTransfer *object);
rosfran@41
    88
rosfran@41
    89
static void gmyth_file_transfer_dispose  (GObject *object);
rosfran@41
    90
static void gmyth_file_transfer_finalize (GObject *object);
rosfran@41
    91
melunko@112
    92
static gboolean gmyth_connect_to_backend (GMythFileTransfer *transfer);
rosfran@41
    93
rosfran@41
    94
void gmyth_file_transfer_close( GMythFileTransfer *transfer );
rosfran@41
    95
rosfran@97
    96
static gboolean myth_control_acquire_context( gboolean do_wait );
rosfran@97
    97
rosfran@97
    98
static gboolean myth_control_release_context( );
rosfran@97
    99
rosfran@41
   100
G_DEFINE_TYPE(GMythFileTransfer, gmyth_file_transfer, G_TYPE_OBJECT)
rosfran@41
   101
rosfran@41
   102
static void
rosfran@41
   103
gmyth_file_transfer_class_init (GMythFileTransferClass *klass)
rosfran@41
   104
{
rosfran@41
   105
  GObjectClass *gobject_class;
rosfran@41
   106
rosfran@41
   107
  gobject_class = (GObjectClass *) klass;
rosfran@41
   108
rosfran@41
   109
  gobject_class->dispose  = gmyth_file_transfer_dispose;
rosfran@41
   110
  gobject_class->finalize = gmyth_file_transfer_finalize;
rosfran@41
   111
}
rosfran@41
   112
melunko@112
   113
static void
melunko@112
   114
gmyth_file_transfer_init (GMythFileTransfer *transfer)
rosfran@41
   115
{ 
melunko@112
   116
  g_return_if_fail( transfer != NULL );
melunko@112
   117
melunko@112
   118
  transfer->readposition = 0;
melunko@112
   119
  transfer->filesize = GMYTHTV_FILE_SIZE;
melunko@112
   120
melunko@112
   121
  transfer->control_sock = NULL;
melunko@112
   122
  transfer->sock = NULL;
rosfran@177
   123
  
rosfran@41
   124
}
rosfran@41
   125
rosfran@41
   126
static void
rosfran@41
   127
gmyth_file_transfer_dispose  (GObject *object)
rosfran@41
   128
{
rosfran@192
   129
	GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (object);
rosfran@192
   130
	
rosfran@192
   131
  if ( transfer->control_sock != NULL )  
rosfran@192
   132
  {
rosfran@192
   133
  	g_object_unref( transfer->control_sock );
rosfran@192
   134
  	transfer->control_sock = NULL;
rosfran@192
   135
  }  
rosfran@192
   136
  
rosfran@192
   137
  if ( transfer->sock != NULL )  
rosfran@192
   138
  {
rosfran@192
   139
  	g_object_unref( transfer->sock );
rosfran@192
   140
  	transfer->sock = NULL;
renatofilho@187
   141
  }
rosfran@203
   142
    
rosfran@192
   143
  if ( transfer->filename != NULL )  
rosfran@192
   144
  {
rosfran@192
   145
  	g_free( transfer->filename );
rosfran@192
   146
  	transfer->filename = NULL;
renatofilho@187
   147
  }
renatofilho@187
   148
rosfran@41
   149
  G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->dispose (object);
rosfran@41
   150
}
rosfran@41
   151
rosfran@101
   152
static void
rosfran@41
   153
gmyth_file_transfer_finalize (GObject *object)
rosfran@41
   154
{
renatofilho@187
   155
rosfran@41
   156
  g_signal_handlers_destroy (object);
rosfran@41
   157
rosfran@41
   158
  G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->finalize (object);
rosfran@41
   159
}
rosfran@41
   160
melunko@112
   161
// fixme: do we need the card_id????
melunko@112
   162
GMythFileTransfer*
rosfran@177
   163
gmyth_file_transfer_new ( const GMythBackendInfo *backend_info)
rosfran@41
   164
{
renatofilho@166
   165
  GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (g_object_new (GMYTH_FILE_TRANSFER_TYPE, NULL));
rosfran@177
   166
  
rosfran@177
   167
  transfer->backend_info = (GMythBackendInfo *)backend_info;
renatofilho@187
   168
  g_object_ref (transfer->backend_info);
rosfran@41
   169
rosfran@177
   170
  return transfer;
rosfran@177
   171
}
rosfran@177
   172
rosfran@177
   173
GMythFileTransfer* 
renatofilho@187
   174
gmyth_file_transfer_new_with_uri (const gchar* uri_str)
rosfran@177
   175
{
rosfran@177
   176
  GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER (g_object_new (GMYTH_FILE_TRANSFER_TYPE, NULL));
melunko@158
   177
melunko@201
   178
  transfer->backend_info = gmyth_backend_info_new_with_uri (uri_str);
renatofilho@187
   179
rosfran@41
   180
  return transfer;
rosfran@41
   181
}
rosfran@41
   182
rosfran@41
   183
gboolean
renatofilho@187
   184
gmyth_file_transfer_open (GMythFileTransfer *transfer, const gchar* filename)
rosfran@41
   185
{
rosfran@41
   186
  gboolean ret = TRUE;
rosfran@177
   187
  
renatofilho@202
   188
  g_return_val_if_fail (transfer != NULL, FALSE);
renatofilho@202
   189
  g_return_val_if_fail (filename != NULL, FALSE);
rosfran@177
   190
  
renatofilho@202
   191
  if (transfer->filename != NULL)
rosfran@184
   192
  {
renatofilho@202
   193
    g_free (transfer->filename);
renatofilho@202
   194
    transfer->filename = NULL;
rosfran@184
   195
  }
renatofilho@202
   196
renatofilho@202
   197
  transfer->filename = g_strdup (filename);
rosfran@184
   198
  
rosfran@41
   199
  /* configure the control socket */
melunko@112
   200
  if (transfer->control_sock == NULL) { 
renatofilho@143
   201
    if (!gmyth_connect_to_backend (transfer)) {
renatofilho@187
   202
      gmyth_debug ("Connection to backend failed (Control Socket).\n");
rosfran@41
   203
      ret = FALSE;
rosfran@41
   204
    }
rosfran@41
   205
  } else {
rosfran@41
   206
    g_warning("Remote transfer control socket already created.\n");
rosfran@41
   207
  }
rosfran@177
   208
  
rosfran@41
   209
  return ret;
rosfran@41
   210
rosfran@41
   211
}
rosfran@41
   212
rosfran@115
   213
static gboolean
melunko@112
   214
gmyth_connect_to_backend (GMythFileTransfer *transfer)
rosfran@41
   215
{
renatofilho@143
   216
  GString *base_str = NULL;
rosfran@177
   217
  GString *hostname = NULL;
melunko@158
   218
  GMythStringList *strlist = NULL; 
renatofilho@143
   219
  gboolean ret = TRUE;
rosfran@41
   220
melunko@112
   221
  g_return_val_if_fail (transfer != NULL, FALSE );
rosfran@41
   222
renatofilho@143
   223
  base_str = g_string_new ("");
rosfran@41
   224
melunko@112
   225
  /* Creates the control socket */
renatofilho@143
   226
  if (transfer->control_sock != NULL) {
renatofilho@143
   227
    g_object_unref (transfer->control_sock);
renatofilho@143
   228
    transfer->control_sock = NULL;
renatofilho@143
   229
  }
renatofilho@143
   230
melunko@112
   231
  transfer->control_sock = gmyth_socket_new();
rosfran@41
   232
melunko@112
   233
  // Connects the socket, send Mythtv ANN command and verify Mythtv protocol version 
melunko@112
   234
  if (!gmyth_socket_connect_to_backend (transfer->control_sock,
renatofilho@187
   235
        transfer->backend_info->hostname, transfer->backend_info->port, TRUE)) {
rosfran@41
   236
melunko@112
   237
    g_object_unref (transfer->control_sock);
melunko@112
   238
    transfer->control_sock = NULL;
melunko@112
   239
    return FALSE;
melunko@112
   240
  }
melunko@112
   241
    
melunko@112
   242
  /* Creates the data socket */
renatofilho@143
   243
  if (transfer->sock != NULL) {
renatofilho@143
   244
    g_object_unref (transfer->sock);
renatofilho@143
   245
    transfer->sock = NULL;
renatofilho@143
   246
  }
renatofilho@143
   247
melunko@112
   248
  transfer->sock = gmyth_socket_new ();
renatofilho@187
   249
  gmyth_socket_connect (transfer->sock, transfer->backend_info->hostname, transfer->backend_info->port);
rosfran@41
   250
melunko@112
   251
  strlist = gmyth_string_list_new();
melunko@112
   252
  hostname = gmyth_socket_get_local_hostname();
renatofilho@131
   253
  gmyth_debug( "[%s] MythTV version (from backend) = %d.\n", __FUNCTION__, transfer->control_sock->mythtv_version );
rosfran@115
   254
  if ( transfer->control_sock->mythtv_version > 26 )
rosfran@115
   255
  	g_string_printf( base_str, "ANN FileTransfer %s 1 -1", hostname->str);
rosfran@115
   256
  else
rosfran@115
   257
  	g_string_printf( base_str, "ANN FileTransfer %s", hostname->str);
rosfran@97
   258
melunko@112
   259
  gmyth_string_list_append_string (strlist, base_str );
renatofilho@191
   260
  gmyth_string_list_append_char_array (strlist, transfer->filename);
rosfran@41
   261
melunko@112
   262
  gmyth_socket_write_stringlist (transfer->sock, strlist );
melunko@112
   263
  gmyth_socket_read_stringlist (transfer->sock, strlist );
rosfran@101
   264
    
melunko@112
   265
  /* file identification used in future file transfer requests to backend */
melunko@112
   266
  transfer->file_id = gmyth_string_list_get_int( strlist, 1 );
rosfran@41
   267
melunko@112
   268
  /* Myth URI stream file size - decoded using two 8-bytes sequences (64 bits/long long types) */
melunko@112
   269
  transfer->filesize = gmyth_util_decode_long_long( strlist, 2 );
rosfran@41
   270
renatofilho@131
   271
  gmyth_debug ( "[%s] ***** Received: recordernum = %d, filesize = %" G_GUINT64_FORMAT "\n", __FUNCTION__,
melunko@112
   272
          transfer->file_id, transfer->filesize );
rosfran@41
   273
melunko@112
   274
  if (transfer->filesize < 0 ) {
renatofilho@131
   275
      gmyth_debug ( "[%s] Got filesize equals to %llu is lesser than 0 [invalid stream file]\n", __FUNCTION__, transfer->filesize );
renatofilho@143
   276
      g_object_unref (transfer->sock);
melunko@112
   277
      transfer->sock = NULL;
renatofilho@143
   278
      ret = FALSE;
renatofilho@143
   279
      goto cleanup;
rosfran@41
   280
  }
melunko@112
   281
  
renatofilho@143
   282
cleanup:
rosfran@41
   283
rosfran@41
   284
  if ( strlist != NULL )
rosfran@41
   285
    g_object_unref( strlist );
rosfran@41
   286
melunko@112
   287
  g_string_free (base_str, TRUE);
melunko@112
   288
  g_string_free (hostname, TRUE);
rosfran@41
   289
renatofilho@143
   290
  return ret;
rosfran@41
   291
}    
rosfran@41
   292
melunko@112
   293
gboolean
melunko@112
   294
gmyth_file_transfer_is_open (GMythFileTransfer *transfer)
rosfran@41
   295
{
melunko@112
   296
    GMythStringList *strlist;
melunko@112
   297
    GString *query;
rosfran@41
   298
melunko@112
   299
    g_return_val_if_fail (transfer->control_sock != NULL, FALSE);
melunko@112
   300
    g_return_val_if_fail (transfer->sock != NULL, FALSE);
rosfran@41
   301
melunko@112
   302
    strlist = gmyth_string_list_new();
melunko@112
   303
    query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   304
    g_string_append_printf (query, "%d", transfer->file_id );
rosfran@41
   305
melunko@112
   306
    gmyth_string_list_append_string (strlist, query );
melunko@112
   307
    gmyth_string_list_append_char_array( strlist, "IS_OPEN" );
rosfran@41
   308
melunko@112
   309
    gmyth_socket_write_stringlist( transfer->control_sock, strlist );
melunko@112
   310
    gmyth_socket_read_stringlist( transfer->control_sock, strlist );
rosfran@41
   311
melunko@112
   312
    g_string_free (query, TRUE);
melunko@112
   313
    g_object_unref (strlist);
rosfran@41
   314
melunko@112
   315
    return ( strlist != NULL && gmyth_string_list_get_int( strlist, 0 ) == 1 );
rosfran@41
   316
}
rosfran@41
   317
melunko@112
   318
void
rosfran@41
   319
gmyth_file_transfer_close( GMythFileTransfer *transfer )
rosfran@41
   320
{
rosfran@41
   321
  GMythStringList *strlist;
melunko@112
   322
  GString *query;
rosfran@41
   323
melunko@112
   324
  g_return_if_fail (transfer->control_sock != NULL);
rosfran@41
   325
rosfran@41
   326
  strlist = gmyth_string_list_new( );
melunko@112
   327
  query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   328
  g_string_append_printf( query, "%d", transfer->file_id);
rosfran@41
   329
melunko@112
   330
  gmyth_string_list_append_string( strlist, query );
rosfran@41
   331
  gmyth_string_list_append_char_array( strlist, "DONE" );
rosfran@41
   332
melunko@112
   333
  if ( gmyth_socket_sendreceive_stringlist(transfer->control_sock, strlist) <= 0 ) {
melunko@112
   334
    // fixme: time out???
rosfran@41
   335
    g_printerr( "Remote file timeout.\n" );
rosfran@41
   336
  }
rosfran@41
   337
melunko@112
   338
  g_string_free (query, TRUE);
melunko@112
   339
  g_object_unref (strlist);
melunko@112
   340
melunko@112
   341
  if (transfer->sock) {
rosfran@41
   342
    g_object_unref( transfer->sock );
rosfran@41
   343
    transfer->sock = NULL;
rosfran@41
   344
  }
rosfran@41
   345
melunko@112
   346
  if (transfer->control_sock) {
rosfran@41
   347
    g_object_unref( transfer->control_sock );
rosfran@41
   348
    transfer->control_sock = NULL;
rosfran@41
   349
  } 
rosfran@177
   350
  
rosfran@41
   351
}
rosfran@41
   352
rosfran@41
   353
gint64
rosfran@41
   354
gmyth_file_transfer_seek(GMythFileTransfer *transfer, guint64 pos, gint whence)
rosfran@41
   355
{
melunko@112
   356
  GMythStringList *strlist = gmyth_string_list_new();
melunko@112
   357
  GString *query;
rosfran@41
   358
melunko@112
   359
  g_return_val_if_fail (transfer->sock != NULL, -1);
melunko@112
   360
  g_return_val_if_fail (transfer->control_sock != NULL, -1);
rosfran@41
   361
melunko@112
   362
  strlist = gmyth_string_list_new();
melunko@112
   363
  query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   364
  g_string_append_printf (query, "%d", transfer->file_id);
rosfran@97
   365
  
rosfran@97
   366
  myth_control_acquire_context( TRUE );
rosfran@41
   367
melunko@112
   368
  gmyth_string_list_append_string( strlist, query );
rosfran@41
   369
  gmyth_string_list_append_char_array( strlist, "SEEK" );
rosfran@41
   370
  gmyth_string_list_append_uint64( strlist, pos );
rosfran@41
   371
  
rosfran@41
   372
  gmyth_string_list_append_int( strlist, whence );  
rosfran@41
   373
rosfran@41
   374
  if (pos > 0 )
rosfran@41
   375
    gmyth_string_list_append_uint64( strlist, pos );
rosfran@41
   376
  else
rosfran@41
   377
    gmyth_string_list_append_uint64( strlist, transfer->readposition );
rosfran@41
   378
  
rosfran@41
   379
  gmyth_socket_sendreceive_stringlist( transfer->control_sock, strlist );
rosfran@41
   380
rosfran@41
   381
  gint64 retval = gmyth_string_list_get_int64(strlist, 0);
rosfran@41
   382
  transfer->readposition = retval;
renatofilho@131
   383
  gmyth_debug ( "[%s] got reading position pointer from the streaming = %lld\n", 
rosfran@41
   384
      __FUNCTION__, retval );
rosfran@41
   385
rosfran@97
   386
  myth_control_release_context( );
rosfran@41
   387
rosfran@41
   388
  return retval;
rosfran@41
   389
}
rosfran@41
   390
rosfran@97
   391
static gboolean 
rosfran@97
   392
myth_control_acquire_context( gboolean do_wait ) 
rosfran@97
   393
{
rosfran@97
   394
	
rosfran@97
   395
	gboolean ret = TRUE;	
rosfran@140
   396
	//guint max_iter = 50;
rosfran@97
   397
	
rosfran@97
   398
	//g_mutex_lock( mutex );
rosfran@97
   399
	
rosfran@97
   400
  //while ( !has_io_access ) 
rosfran@97
   401
  //	g_cond_wait( io_watcher_cond, mutex );
rosfran@97
   402
  	
rosfran@97
   403
  //has_io_access = FALSE;
rosfran@97
   404
  
rosfran@97
   405
  //myth_control_acquire_context (FALSE);
rosfran@140
   406
   
rosfran@140
   407
  /* 
rosfran@97
   408
  if ( do_wait ) {
rosfran@120
   409
  	while ( --max_iter > 0 && !g_main_context_wait( io_watcher_context, io_watcher_cond, mutex ) )
rosfran@97
   410
  		ret = FALSE;
rosfran@97
   411
  } else if ( !g_main_context_acquire( io_watcher_context ) )
rosfran@97
   412
  	ret = FALSE;
rosfran@140
   413
  */
rosfran@140
   414
  	
rosfran@140
   415
  //g_static_mutex_lock( &st_mutex );
rosfran@97
   416
  
rosfran@97
   417
  return ret;
rosfran@97
   418
  
rosfran@97
   419
}
rosfran@97
   420
rosfran@97
   421
static gboolean 
rosfran@97
   422
myth_control_release_context( ) 
rosfran@97
   423
{
rosfran@97
   424
	
rosfran@97
   425
	gboolean ret = TRUE;
rosfran@140
   426
    
rosfran@140
   427
  //g_static_mutex_unlock( &st_mutex );
rosfran@97
   428
  
rosfran@140
   429
	//g_main_context_release( io_watcher_context );
rosfran@140
   430
  
rosfran@140
   431
  //g_main_context_wakeup( io_watcher_context );
rosfran@97
   432
  
rosfran@97
   433
  //has_io_access = TRUE;
rosfran@97
   434
rosfran@97
   435
  //g_cond_broadcast( io_watcher_cond );
rosfran@97
   436
  
rosfran@140
   437
  //g_mutex_unlock( mutex );  
rosfran@97
   438
 
rosfran@97
   439
  return ret;
rosfran@97
   440
  
rosfran@97
   441
}
rosfran@97
   442
rosfran@41
   443
gint 
rosfran@115
   444
gmyth_file_transfer_read(GMythFileTransfer *transfer, GByteArray *data, gint size, gboolean read_unlimited)
rosfran@41
   445
{
rosfran@177
   446
  gint bytes_sent = 0;
rosfran@41
   447
  gsize bytes_read = 0;
melunko@112
   448
  gsize total_read = 0;
melunko@112
   449
  
melunko@112
   450
  GError *error = NULL;
melunko@112
   451
  
rosfran@41
   452
  GIOChannel *io_channel;
rosfran@41
   453
  GIOChannel *io_channel_control;
rosfran@41
   454
rosfran@41
   455
  GIOCondition io_cond;
rosfran@41
   456
  GIOCondition io_cond_control;
rosfran@41
   457
  GIOStatus io_status = G_IO_STATUS_NORMAL, io_status_control = G_IO_STATUS_NORMAL;   
rosfran@41
   458
melunko@112
   459
  GString *query;
rosfran@115
   460
  
rosfran@41
   461
  g_return_val_if_fail ( data != NULL, -2 );
rosfran@101
   462
rosfran@41
   463
  io_channel = transfer->sock->sd_io_ch;
rosfran@41
   464
  io_channel_control = transfer->control_sock->sd_io_ch;
rosfran@41
   465
rosfran@41
   466
  io_status = g_io_channel_set_encoding( io_channel, NULL, &error );
rosfran@41
   467
  if ( io_status == G_IO_STATUS_NORMAL )
renatofilho@131
   468
    gmyth_debug ( "[%s] Setting encoding to binary data socket).\n", __FUNCTION__ );
rosfran@41
   469
rosfran@41
   470
  io_cond = g_io_channel_get_buffer_condition( io_channel );  
rosfran@41
   471
rosfran@41
   472
  io_cond_control = g_io_channel_get_buffer_condition( io_channel );
melunko@112
   473
  if ( transfer->sock == NULL || ( io_status == G_IO_STATUS_ERROR ) ) {
rosfran@41
   474
    g_printerr( "gmyth_file_transfer_read(): Called with no raw socket.\n" );
rosfran@177
   475
    //exit(0); // fixme remove this
melunko@112
   476
    return -1;
rosfran@41
   477
  }
rosfran@41
   478
melunko@112
   479
  if ( transfer->control_sock == NULL || ( io_status_control == G_IO_STATUS_ERROR ) ) {
rosfran@41
   480
    g_printerr( "gmyth_file_transfer_read(): Called with no control socket.\n" );
rosfran@177
   481
    //exit(0); // fixme remove this
melunko@112
   482
    return -1;
rosfran@41
   483
  }
rosfran@41
   484
melunko@112
   485
  query = g_string_new (GMYTHTV_QUERY_HEADER);
melunko@112
   486
  g_string_append_printf ( query, "%d", transfer->file_id );
renatofilho@131
   487
  gmyth_debug ("[%s] Transfer_query = %s\n", __FUNCTION__, query->str );
rosfran@41
   488
  
rosfran@177
   489
  /* send requests to the maximum number of REQUEST_BLOCK messages */
rosfran@197
   490
  guint max_tries = 5;
rosfran@177
   491
  
rosfran@140
   492
  myth_control_acquire_context( TRUE );
rosfran@140
   493
  
rosfran@177
   494
  while (total_read == 0 && --max_tries > 0) {
renatofilho@143
   495
    GMythStringList *strlist = gmyth_string_list_new();
melunko@112
   496
melunko@112
   497
    gmyth_string_list_append_char_array( strlist, query->str );
rosfran@101
   498
    gmyth_string_list_append_char_array( strlist, "REQUEST_BLOCK" );
melunko@112
   499
    gmyth_string_list_append_int( strlist, size );
melunko@112
   500
melunko@112
   501
    // Request the block to the backend
melunko@112
   502
    gmyth_socket_write_stringlist( transfer->control_sock, strlist );
melunko@112
   503
melunko@112
   504
    // Receives the backand answer    
rosfran@101
   505
    gmyth_socket_read_stringlist( transfer->control_sock, strlist );
rosfran@101
   506
melunko@112
   507
    if ( strlist != NULL && gmyth_string_list_length( strlist ) > 0 ) { 
renatofilho@143
   508
	    bytes_sent = gmyth_string_list_get_int( strlist,  0 ); // -1 on backend error
renatofilho@143
   509
	    gmyth_debug ( "[%s] got SENT buffer message = %d\n", __FUNCTION__, bytes_sent );
rosfran@89
   510
melunko@112
   511
      	if ( bytes_sent != 0 ) {
renatofilho@143
   512
            gchar *data_buffer = g_new0 (gchar, bytes_sent);    
renatofilho@143
   513
     	    while ( 0 != bytes_sent) { 
rosfran@115
   514
                io_status = g_io_channel_read_chars( io_channel, data_buffer + total_read, 
renatofilho@143
   515
    				(gsize) bytes_sent, // buffer_len
renatofilho@143
   516
					&bytes_read, &error );
renatofilho@143
   517
    	        total_read += bytes_read;
renatofilho@143
   518
                bytes_sent -= bytes_read;
rosfran@115
   519
	        
renatofilho@143
   520
	            /* append new data to the increasing byte array */
rosfran@177
   521
		    		data = g_byte_array_append (data, (const guint8*)data_buffer, bytes_read);
renatofilho@143
   522
		        gmyth_debug ("Total file transfer data read: %d\n", total_read);
renatofilho@143
   523
	        }
renatofilho@143
   524
            g_free (data_buffer);
rosfran@177
   525
	    } else {
rosfran@177
   526
	    	
rosfran@177
   527
      }
rosfran@177
   528
    } else {
rosfran@177
   529
    	total_read = GMYTHTV_FILE_TRANSFER_READ_ERROR;
rosfran@177
   530
    	g_object_unref (strlist);
rosfran@177
   531
    	strlist = NULL; 
rosfran@177
   532
    	break;
melunko@112
   533
    }
renatofilho@143
   534
    g_object_unref (strlist);
renatofilho@143
   535
    strlist = NULL;
melunko@112
   536
  }
rosfran@140
   537
  
rosfran@140
   538
  myth_control_release_context( );
renatofilho@143
   539
  g_string_free (query, TRUE);
rosfran@41
   540
renatofilho@143
   541
  if ( error != NULL ) {
renatofilho@143
   542
    gmyth_debug ("Cleaning-up ERROR: %s [msg = %s, code = %d]\n", __FUNCTION__, error->message, 
renatofilho@143
   543
	    error->code);
renatofilho@143
   544
    g_error_free (error);
renatofilho@143
   545
  }
melunko@112
   546
  
rosfran@177
   547
  if ( total_read >= 0 )
rosfran@177
   548
  	transfer->readposition += total_read;
rosfran@177
   549
  	
melunko@112
   550
  return total_read;
rosfran@41
   551
}
rosfran@41
   552
melunko@112
   553
gboolean 
rosfran@41
   554
gmyth_file_transfer_settimeout( GMythFileTransfer *transfer, gboolean fast )
rosfran@41
   555
{
rosfran@41
   556
rosfran@41
   557
  GMythStringList *strlist = NULL;
rosfran@41
   558
melunko@112
   559
  g_return_val_if_fail (transfer->sock != NULL, FALSE);
melunko@112
   560
  g_return_val_if_fail (transfer->control_sock != NULL, FALSE);
rosfran@41
   561
melunko@112
   562
//  if ( transfer->timeoutisfast == fast )
melunko@112
   563
//    return;
rosfran@41
   564
rosfran@41
   565
  strlist = gmyth_string_list_new(); 
melunko@112
   566
  gmyth_string_list_append_char_array( strlist, GMYTHTV_QUERY_HEADER );
rosfran@41
   567
  gmyth_string_list_append_char_array( strlist, "SET_TIMEOUT" );
rosfran@41
   568
  gmyth_string_list_append_int( strlist, fast ); 
rosfran@41
   569
rosfran@41
   570
  gmyth_socket_write_stringlist( transfer->control_sock, strlist );
rosfran@41
   571
  gmyth_socket_read_stringlist( transfer->control_sock, strlist );
rosfran@41
   572
melunko@112
   573
//  transfer->timeoutisfast = fast;
rosfran@41
   574
melunko@112
   575
  return TRUE;
rosfran@41
   576
}
rosfran@41
   577
melunko@117
   578
melunko@117
   579
guint64
melunko@117
   580
gmyth_file_transfer_get_filesize (GMythFileTransfer *transfer)
melunko@117
   581
{
melunko@117
   582
    assert (transfer);
melunko@117
   583
    
melunko@117
   584
    return transfer->filesize;
melunko@117
   585
}