From 6bdd3c7c6231cab410075e3d760f3c76b9163e8f Mon Sep 17 00:00:00 2001 From: short <> Date: Sun, 9 Nov 2003 19:59:05 +0000 Subject: [PATCH] Implemented HTTP read retries (5 retries, timeout 20sec). Abort cabinet reading on extract_file() failure (such as abort). --- src/install/acquire/cabinet.c | 121 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 7 deletions(-) diff --git a/src/install/acquire/cabinet.c b/src/install/acquire/cabinet.c index 299f609..71170ab 100644 --- a/src/install/acquire/cabinet.c +++ b/src/install/acquire/cabinet.c @@ -29,10 +29,17 @@ #include #include #include "main.h" +#include +#include #include +/* Config: */ +#define ACQUIRE_CABINET_READ_RAW_READ_TRY_MAX 5 +#define ACQUIRE_CABINET_READ_RAW_READ_TIMEOUT 20 + + void acquire_cabinet_seek(struct acquire_cabinet *acquire_cabinet,GnomeVFSFileOffset offset) { g_return_if_fail(acquire_cabinet!=NULL); @@ -63,6 +70,101 @@ GnomeVFSFileOffset acquire_cabinet_tell(struct acquire_cabinet *acquire_cabinet) return acquire_cabinet->offset; } +static gboolean handler_SIGALRM_hit; +static sigjmp_buf handler_SIGALRM_sigjmp_buf; + +static void handler_SIGALRM(int signo) +{ + g_return_if_fail(signo==SIGALRM); + + /* Try to abort the read(2) call first. + * If it already read something it will return the partially read data. + * Otherwise gnome_vfs_inet_connection_read() will loop back to retry read(2) + * and we will abort it after 1 second. OK, some data may be read that time + * but who cares. + */ + if (!handler_SIGALRM_hit) { + handler_SIGALRM_hit=TRUE; + alarm(1); + return; + } + + siglongjmp(handler_SIGALRM_sigjmp_buf,1); /* 1; meaning: !=0 */ +} + +/* FIXME: This is hack. + * Correct way would be to use 'GnomeVFSCancellation' + * to abort 'GnomeVFSInetConnection' acting as 'GnomeVFSSocket'. + * This abort should be handled from 'http'/'httpcaptive' handler + * but gnome_vfs_cancellation_cancel() cannot be invoked from + * the asynchronous slave thread. + */ +static GnomeVFSResult acquire_cabinet_read_raw + (struct acquire_cabinet *acquire_cabinet,gpointer buffer,GnomeVFSFileSize bytes,GnomeVFSFileSize *bytes_read, + GnomeVFSFileOffset offset) +{ +gint try=0; + + g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS); + g_return_val_if_fail(buffer!=NULL || bytes==0,GNOME_VFS_ERROR_BAD_PARAMETERS); + g_return_val_if_fail(bytes_read!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS); + + *bytes_read=0; + + if (!bytes) + return GNOME_VFS_ERROR_EOF; + + while (try++<=ACQUIRE_CABINET_READ_RAW_READ_TRY_MAX) { +GnomeVFSResult errvfsresult; +unsigned erruint; +GnomeVFSHandle *handle_new; +struct sigaction oldact; +int errint; + + if ((*ui_progress)(NULL)) + return GNOME_VFS_ERROR_INTERRUPTED; + + if (!sigsetjmp( + handler_SIGALRM_sigjmp_buf, /* env */ + TRUE)) { /* savesigs */ + handler_SIGALRM_hit=FALSE; + errint=sigaction( + SIGALRM, /* signum */ + NULL, /* act */ + &oldact); /* oldact */ + g_assert(errint==0); + signal(SIGALRM,handler_SIGALRM); + erruint=alarm(ACQUIRE_CABINET_READ_RAW_READ_TIMEOUT); + g_assert(erruint==0); + errvfsresult=gnome_vfs_seek(acquire_cabinet->handle,GNOME_VFS_SEEK_START,offset); + if (GNOME_VFS_OK==errvfsresult) + errvfsresult=gnome_vfs_read(acquire_cabinet->handle,buffer,bytes,bytes_read); + } + else + errvfsresult=GNOME_VFS_ERROR_INTERRUPTED; + alarm(0); + errint=sigaction( + SIGALRM, /* signum */ + &oldact, /* act */ + NULL); /* oldact */ + g_assert(errint==0); + if (errvfsresult==GNOME_VFS_OK) { + g_assert(*bytes_read>0); + return GNOME_VFS_OK; + } + + /* Reopen 'acquire_cabinet->handle' */ + + g_assert(acquire_cabinet->handle_uri!=NULL); + if (GNOME_VFS_OK==(errvfsresult=gnome_vfs_open_uri(&handle_new,acquire_cabinet->handle_uri,GNOME_VFS_OPEN_READ))) { + gnome_vfs_close(acquire_cabinet->handle); /* errors ignored */ + acquire_cabinet->handle=handle_new; + } + } + + return GNOME_VFS_ERROR_IO; +} + #define ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,pos) (!(acquire_cabinet)->base_cached \ || (acquire_cabinet)->base_cached[(pos)/8] & 1<<((pos)&7)) #define ACQUIRE_CABINET_SET_BYTE_CACHED(acquire_cabinet,pos) ((acquire_cabinet)->base_cached[(pos)/8] |= 1<<((pos)&7)) @@ -77,6 +179,8 @@ GnomeVFSFileSize bytes_read_now; g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS); g_return_val_if_fail(buffer!=NULL || bytes==0,GNOME_VFS_ERROR_BAD_PARAMETERS); + *bytes_read=0; + if ((*ui_progress)(NULL)) return GNOME_VFS_ERROR_INTERRUPTED; @@ -84,7 +188,6 @@ GnomeVFSFileSize bytes_read_now; if (!bytes) return GNOME_VFS_ERROR_EOF; - *bytes_read=0; while (bytes) { read_behind =acquire_cabinet->offset+bytes; @@ -94,10 +197,8 @@ GnomeVFSFileSize bytes_read_now; while (offset_endoffset_start) { - if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_seek(acquire_cabinet->handle,GNOME_VFS_SEEK_START,offset_start))) - return errvfsresult; - errvfsresult=gnome_vfs_read(acquire_cabinet->handle, - acquire_cabinet->base+offset_start,offset_end-offset_start,&bytes_read_now); + errvfsresult=acquire_cabinet_read_raw(acquire_cabinet, + acquire_cabinet->base+offset_start,offset_end-offset_start,&bytes_read_now,offset_start); if (errvfsresult!=GNOME_VFS_OK) return errvfsresult; g_assert(bytes_read_now>0); @@ -147,6 +248,7 @@ GnomeVFSURI *uri_cabextract; uri_cabextract->parent=gnome_vfs_uri_dup(uri); acquire_cabinet->uri=uri_cabextract; + acquire_cabinet->handle_uri=gnome_vfs_uri_ref(uri); acquire_cabinet->filename=gnome_vfs_uri_to_string(acquire_cabinet->uri,GNOME_VFS_URI_HIDE_PASSWORD); } @@ -213,6 +315,7 @@ void acquire_cabinet_free(struct acquire_cabinet *acquire_cabinet) } g_free((/* de-const */ gchar *)acquire_cabinet->filename); gnome_vfs_uri_unref(acquire_cabinet->uri); + gnome_vfs_uri_unref(acquire_cabinet->handle_uri); g_free(acquire_cabinet); } @@ -261,6 +364,7 @@ struct file *filelist,*fi; for (fi=filelist;fi;fi=fi->next) { gpointer file_buffer; GnomeVFSURI *uri_fi; +int errint; if (!captivemodid_module_length_is_valid(fi->length)) continue; @@ -273,14 +377,17 @@ GnomeVFSURI *uri_fi; file_write_fi_assertion=fi; file_write_bytearray=g_byte_array_new(); - extract_file(fi, + /* extract_file() returns 1 for success. */ + errint=extract_file(fi, 0, /* lower; ignored now */ FALSE, /* fix */ NULL); /* dir; ignored now */ - if (fi->length!=file_write_bytearray->len) { + if (!errint || fi->length!=file_write_bytearray->len) { g_byte_array_free(file_write_bytearray, TRUE); /* free_segment */ gnome_vfs_uri_unref(uri_fi); + if (!errint) + return; continue; } file_buffer=g_byte_array_free(file_write_bytearray, -- 1.8.3.1