Mercurial > noffle
comparison src/fetch.c @ 188:f1bacee93ca6 noffle
[svn] * src/client.c,src/client.h,src/fetch.c,src/noffle.c,src/server.c:
robustness - instead of retruning simple Passed/Failed statuses from
connection functions, return an integer status instead. This allows
Noffle to distinguish between a connection failure, an unrecoverable
protocol error and a recoverable problem. As a concrete instance, Noffle
will no longer abort the connection if a group is removed from the
upstream server. Also beef up error detection a bit.
* src/content.c: instead of overwriting the existing content file(s) when
updating - which leaves a window where Noffle is vulnerable to failure
which will leave the content file corrupted (yes, it happened to me),
write a new content file and rename it over the old file only when it
has been written and closed with no errors reported.
| author | bears |
|---|---|
| date | Wed, 12 Sep 2001 21:33:44 +0100 |
| parents | fed1334d766b |
| children | 021d145e34e9 |
comparison
equal
deleted
inserted
replaced
| 187:166008a80f03 | 188:f1bacee93ca6 |
|---|---|
| 1 /* | 1 /* |
| 2 fetch.c | 2 fetch.c |
| 3 | 3 |
| 4 $Id: fetch.c 300 2001-08-05 08:24:22Z bears $ | 4 $Id: fetch.c 307 2001-09-12 20:33:44Z bears $ |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #if HAVE_CONFIG_H | 7 #if HAVE_CONFIG_H |
| 8 #include <config.h> | 8 #include <config.h> |
| 9 #endif | 9 #endif |
| 72 { | 72 { |
| 73 Log_err( "Cannot read %s. Please run noffle --query groups", file ); | 73 Log_err( "Cannot read %s. Please run noffle --query groups", file ); |
| 74 return FALSE; | 74 return FALSE; |
| 75 } | 75 } |
| 76 Log_inf( "Updating groupinfo" ); | 76 Log_inf( "Updating groupinfo" ); |
| 77 return Client_getNewgrps( &t ); | 77 |
| 78 /* | |
| 79 * If NEWGROUPS fails, it isn't necessarily fatal. You can do | |
| 80 * a periodic noffle --query groups to refresh your group list. | |
| 81 * So only return failure here if the status indicates the link | |
| 82 * itself failed. | |
| 83 * | |
| 84 * In particular, older versions of NNTPcache have a Y2K bug that | |
| 85 * stops NEWGROUPS working. | |
| 86 */ | |
| 87 return ( ! IS_FATAL( Client_getNewgrps( &t ) ) ); | |
| 78 } | 88 } |
| 79 | 89 |
| 80 /* Databases open on entry, closed on exit. */ | 90 /* Databases open on entry, closed on exit. */ |
| 81 static Bool | 91 static int |
| 82 fetchNewArts( const char *name, FetchMode mode ) | 92 fetchNewArts( const char *name, FetchMode mode ) |
| 83 { | 93 { |
| 84 int next, first, last, refetch; | 94 int next, first, last, refetch, stat; |
| 85 | 95 |
| 86 if ( ! Client_changeToGrp( name ) ) | 96 stat = Client_changeToGrp( name ); |
| 97 if ( stat != STAT_OK ) | |
| 87 { | 98 { |
| 88 Log_err( "Could not change to group %s", name ); | 99 Log_err( "Could not change to group %s", name ); |
| 89 if ( Lock_gotLock() ) | 100 if ( Lock_gotLock() ) |
| 90 Lock_closeDatabases(); | 101 Lock_closeDatabases(); |
| 91 return TRUE; | 102 return stat; |
| 92 } | 103 } |
| 93 Client_rmtFirstLast( &first, &last ); | 104 Client_rmtFirstLast( &first, &last ); |
| 94 Cont_read( name ); | 105 Cont_read( name ); |
| 95 next = Grp_rmtNext( name ); | 106 next = Grp_rmtNext( name ); |
| 96 if ( next == GRP_RMT_NEXT_NOT_SUBSCRIBED ) | 107 if ( next == GRP_RMT_NEXT_NOT_SUBSCRIBED ) |
| 99 { | 110 { |
| 100 Log_inf( "No new articles in %s", name ); | 111 Log_inf( "No new articles in %s", name ); |
| 101 Cont_write(); | 112 Cont_write(); |
| 102 Grp_setFirstLast( name, Cont_first(), Cont_last() ); | 113 Grp_setFirstLast( name, Cont_first(), Cont_last() ); |
| 103 Lock_closeDatabases(); | 114 Lock_closeDatabases(); |
| 104 return TRUE; | 115 return STAT_OK; |
| 105 } | 116 } |
| 106 if ( first == 0 && last == 0 ) | 117 if ( first == 0 && last == 0 ) |
| 107 { | 118 { |
| 108 Log_inf( "No articles in %s", name ); | 119 Log_inf( "No articles in %s", name ); |
| 109 Cont_write(); | 120 Cont_write(); |
| 110 Grp_setFirstLast( name, Cont_first(), Cont_last() ); | 121 Grp_setFirstLast( name, Cont_first(), Cont_last() ); |
| 111 Lock_closeDatabases(); | 122 Lock_closeDatabases(); |
| 112 return TRUE; | 123 return STAT_OK; |
| 113 } | 124 } |
| 114 if ( next > last + 1 ) | 125 if ( next > last + 1 ) |
| 115 { | 126 { |
| 116 refetch = last - Cfg_maxFetch() + 1; | 127 refetch = last - Cfg_maxFetch() + 1; |
| 117 if ( refetch < 0 ) refetch = 1; | 128 if ( refetch < 0 ) refetch = 1; |
| 118 Log_err( "Article number inconsistent (%s rmt=%lu-%lu, next=%lu). Refetching from %lu", | 129 Log_err( "Article number inconsistent (%s rmt=%lu-%lu, next=%lu). " |
| 130 "Refetching from %lu", | |
| 119 name, first, last, next, refetch ); | 131 name, first, last, next, refetch ); |
| 120 Pseudo_cntInconsistent( name, first, last, next, refetch ); | 132 Pseudo_cntInconsistent( name, first, last, next, refetch ); |
| 121 first = refetch; | 133 first = refetch; |
| 122 } | 134 } |
| 123 else if ( next < first ) | 135 else if ( next < first ) |
| 124 { | 136 { |
| 125 Log_inf( "Missing articles (%s first=%lu next=%lu)", | 137 Log_inf( "Missing articles (%s first=%lu next=%lu)", |
| 126 name, first, next ); | 138 name, first, next ); |
| 127 Pseudo_missArts( name, first, next ); | 139 Pseudo_missArts( name, first, next ); |
| 140 | |
| 141 /* | |
| 142 * If we are missing articles but there are none to fetch, | |
| 143 * we must ensure we don't repeatedly generate missing | |
| 144 * article warning on every fetch until there is something | |
| 145 * to fetch. To guard against this, update the group remote | |
| 146 * next now. | |
| 147 */ | |
| 148 Grp_setRmtNext( name, first ); | |
| 149 next = first; | |
| 128 } | 150 } |
| 129 else | 151 else |
| 130 first = next; | 152 first = next; |
| 131 if ( last - first > Cfg_maxFetch() ) | 153 if ( last - first > Cfg_maxFetch() ) |
| 132 { | 154 { |
| 168 for ( i = 0; i < size; ++i ) | 190 for ( i = 0; i < size; ++i ) |
| 169 { | 191 { |
| 170 Fetchlist_element( &name, &mode, i ); | 192 Fetchlist_element( &name, &mode, i ); |
| 171 if ( strcmp( Grp_server( name ), fetch.serv ) == 0 ) | 193 if ( strcmp( Grp_server( name ), fetch.serv ) == 0 ) |
| 172 { | 194 { |
| 173 if ( ! fetchNewArts( name, mode ) ) | 195 if ( IS_FATAL( fetchNewArts( name, mode ) ) ) |
| 174 return FALSE; | 196 return FALSE; |
| 175 if ( ! Lock_openDatabases() ) | 197 if ( ! Lock_openDatabases() ) |
| 176 { | 198 { |
| 177 Log_err( "Could not open message base" ); | 199 Log_err( "Could not open message base" ); |
| 178 return FALSE; | 200 return FALSE; |
| 181 } | 203 } |
| 182 Lock_closeDatabases(); | 204 Lock_closeDatabases(); |
| 183 return TRUE; | 205 return TRUE; |
| 184 } | 206 } |
| 185 | 207 |
| 186 static Bool | 208 static int |
| 187 fetchMessageList( const char *list, int *artcnt, int artmax ) | 209 fetchMessageList( const char *list, int *artcnt, int artmax ) |
| 188 { | 210 { |
| 189 const char *p; | 211 const char *p; |
| 190 Str msgId; | 212 Str msgId; |
| 213 int stat; | |
| 191 | 214 |
| 192 ASSERT( Lock_gotLock() ); | 215 ASSERT( Lock_gotLock() ); |
| 193 if ( ! Client_retrieveArtList( list, artcnt, artmax ) ) | 216 stat = Client_retrieveArtList( list, artcnt, artmax ); |
| 194 return FALSE; | 217 if ( stat != STAT_OK ) |
| 218 return stat; | |
| 195 p = list; | 219 p = list; |
| 196 while ( ( p = Utl_getLn( msgId, p ) ) ) | 220 while ( ( p = Utl_getLn( msgId, p ) ) ) |
| 197 Req_remove( fetch.serv, msgId ); | 221 Req_remove( fetch.serv, msgId ); |
| 198 return TRUE; | 222 return STAT_OK; |
| 199 } | 223 } |
| 200 | 224 |
| 201 Bool | 225 Bool |
| 202 Fetch_getReq_( void ) | 226 Fetch_getReq_( void ) |
| 203 { | 227 { |
| 205 DynStr *list; | 229 DynStr *list; |
| 206 DynStr *fetchList; | 230 DynStr *fetchList; |
| 207 const char *p; | 231 const char *p; |
| 208 int count = 0, artcnt = 0, artmax = 0; | 232 int count = 0, artcnt = 0, artmax = 0; |
| 209 Bool res; | 233 Bool res; |
| 234 int stat; | |
| 210 | 235 |
| 211 ASSERT( fetch.ready ); | 236 ASSERT( fetch.ready ); |
| 212 Log_dbg( LOG_DBG_FETCH, "Retrieving articles marked for download" ); | 237 Log_dbg( LOG_DBG_FETCH, "Retrieving articles marked for download" ); |
| 213 list = new_DynStr( 10000 ); | 238 list = new_DynStr( 10000 ); |
| 214 fetchList = new_DynStr( 1000 ); | 239 fetchList = new_DynStr( 1000 ); |
| 248 while ( res && ( p = Utl_getLn( msgId, p ) ) != NULL ) | 273 while ( res && ( p = Utl_getLn( msgId, p ) ) != NULL ) |
| 249 { | 274 { |
| 250 DynStr_appLn( fetchList, msgId ); | 275 DynStr_appLn( fetchList, msgId ); |
| 251 if ( ++count % MAX_ARTICLE_CMDS_QUEUED == 0 ) | 276 if ( ++count % MAX_ARTICLE_CMDS_QUEUED == 0 ) |
| 252 { | 277 { |
| 253 res = fetchMessageList( DynStr_str( fetchList ), &artcnt, artmax ); | 278 stat = fetchMessageList( DynStr_str( fetchList ), &artcnt, |
| 279 artmax ); | |
| 280 res = ! IS_FATAL( stat ); | |
| 254 DynStr_clear( fetchList ); | 281 DynStr_clear( fetchList ); |
| 255 } | 282 } |
| 256 } | 283 } |
| 257 res = res && fetchMessageList( DynStr_str( fetchList ), &artcnt, artmax ); | 284 stat = fetchMessageList( DynStr_str( fetchList ), &artcnt, artmax ); |
| 285 res = res && ! IS_FATAL( stat ); | |
| 258 | 286 |
| 259 del_DynStr( fetchList ); | 287 del_DynStr( fetchList ); |
| 260 del_DynStr( list ); | 288 del_DynStr( list ); |
| 261 Lock_closeDatabases(); | 289 Lock_closeDatabases(); |
| 262 return res; | 290 return res; |
| 317 { | 345 { |
| 318 Log_inf( "Posting articles" ); | 346 Log_inf( "Posting articles" ); |
| 319 do | 347 do |
| 320 { | 348 { |
| 321 txt = DynStr_str( s ); | 349 txt = DynStr_str( s ); |
| 322 if ( ! Client_postArt( msgId, txt, errStr ) ) | 350 if ( Client_postArt( msgId, txt, errStr ) != STAT_OK ) |
| 323 { | 351 { |
| 324 res = FALSE; | 352 res = FALSE; |
| 325 break; | 353 break; |
| 326 } | 354 } |
| 327 | 355 |
