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 |