comparison libfdproto/sessions.c @ 1369:f1bbcab403a6

Clean up trailing whitespace in sessions.c
author Thomas Klausner <tk@giga.or.at>
date Mon, 10 Jun 2019 16:27:54 +0200
parents 44f3e48dfe27
children 643883ec68ef
comparison
equal deleted inserted replaced
1368:a1571234c09b 1369:f1bbcab403a6
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * 32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34 *********************************************************************************************************/ 34 *********************************************************************************************************/
35 35
36 /* Sessions module. 36 /* Sessions module.
37 * 37 *
38 * Basic functionalities to help implementing User sessions state machines from RFC3588. 38 * Basic functionalities to help implementing User sessions state machines from RFC3588.
39 */ 39 */
40 40
41 #include "fdproto-internal.h" 41 #include "fdproto-internal.h"
42 42
89 }; 89 };
90 90
91 /* Session object, one for each value of Session-Id AVP */ 91 /* Session object, one for each value of Session-Id AVP */
92 struct session { 92 struct session {
93 int eyec; /* Eyecatcher, SI_EYEC */ 93 int eyec; /* Eyecatcher, SI_EYEC */
94 94
95 os0_t sid; /* The \0-terminated Session-Id */ 95 os0_t sid; /* The \0-terminated Session-Id */
96 size_t sidlen; /* cached length of sid */ 96 size_t sidlen; /* cached length of sid */
97 uint32_t hash; /* computed hash of sid */ 97 uint32_t hash; /* computed hash of sid */
98 struct fd_list chain_h;/* chaining in the hash table of sessions. */ 98 struct fd_list chain_h;/* chaining in the hash table of sessions. */
99 99
100 struct timespec timeout;/* Timeout date for the session */ 100 struct timespec timeout;/* Timeout date for the session */
101 struct fd_list expire; /* List of expiring sessions, ordered by timeouts. */ 101 struct fd_list expire; /* List of expiring sessions, ordered by timeouts. */
102 102
103 pthread_mutex_t stlock; /* A lock to protect the list of states associated with this session */ 103 pthread_mutex_t stlock; /* A lock to protect the list of states associated with this session */
104 struct fd_list states; /* Sentinel for the list of states of this session. */ 104 struct fd_list states; /* Sentinel for the list of states of this session. */
105 int msg_cnt;/* Reference counter for the messages pointing to this session */ 105 int msg_cnt;/* Reference counter for the messages pointing to this session */
106 int is_destroyed; /* boolean telling if fd_sess_detroy has been called on this */ 106 int is_destroyed; /* boolean telling if fd_sess_detroy has been called on this */
107 }; 107 };
123 static pthread_mutex_t sid_lock = PTHREAD_MUTEX_INITIALIZER; 123 static pthread_mutex_t sid_lock = PTHREAD_MUTEX_INITIALIZER;
124 124
125 /* Expiring sessions management */ 125 /* Expiring sessions management */
126 static struct fd_list exp_sentinel = FD_LIST_INITIALIZER(exp_sentinel); /* list of sessions ordered by their timeout date */ 126 static struct fd_list exp_sentinel = FD_LIST_INITIALIZER(exp_sentinel); /* list of sessions ordered by their timeout date */
127 static pthread_mutex_t exp_lock = PTHREAD_MUTEX_INITIALIZER; /* lock protecting the list. */ 127 static pthread_mutex_t exp_lock = PTHREAD_MUTEX_INITIALIZER; /* lock protecting the list. */
128 static pthread_cond_t exp_cond = PTHREAD_COND_INITIALIZER; /* condvar used by the expiry mecahinsm. */ 128 static pthread_cond_t exp_cond = PTHREAD_COND_INITIALIZER; /* condvar used by the expiry mechainsm. */
129 static pthread_t exp_thr = (pthread_t)NULL; /* The expiry thread that handles cleanup of expired sessions */ 129 static pthread_t exp_thr = (pthread_t)NULL; /* The expiry thread that handles cleanup of expired sessions */
130 130
131 /* Hierarchy of the locks, to avoid deadlocks: 131 /* Hierarchy of the locks, to avoid deadlocks:
132 * hash lock > state lock > expiry lock 132 * hash lock > state lock > expiry lock
133 * i.e. state lock can be taken while holding the hash lock, but not while holding the expiry lock. 133 * i.e. state lock can be taken while holding the hash lock, but not while holding the expiry lock.
138 138
139 /* Initialize a session object. It is not linked now. sid must be already malloc'ed. The hash has already been computed. */ 139 /* Initialize a session object. It is not linked now. sid must be already malloc'ed. The hash has already been computed. */
140 static struct session * new_session(os0_t sid, size_t sidlen, uint32_t hash) 140 static struct session * new_session(os0_t sid, size_t sidlen, uint32_t hash)
141 { 141 {
142 struct session * sess; 142 struct session * sess;
143 143
144 TRACE_ENTRY("%p %zd", sid, sidlen); 144 TRACE_ENTRY("%p %zd", sid, sidlen);
145 CHECK_PARAMS_DO( sid && sidlen, return NULL ); 145 CHECK_PARAMS_DO( sid && sidlen, return NULL );
146 146
147 CHECK_MALLOC_DO( sess = malloc(sizeof(struct session)), return NULL ); 147 CHECK_MALLOC_DO( sess = malloc(sizeof(struct session)), return NULL );
148 memset(sess, 0, sizeof(struct session)); 148 memset(sess, 0, sizeof(struct session));
149 149
150 sess->eyec = SI_EYEC; 150 sess->eyec = SI_EYEC;
151 151
152 sess->sid = sid; 152 sess->sid = sid;
153 sess->sidlen = sidlen; 153 sess->sidlen = sidlen;
154 sess->hash = hash; 154 sess->hash = hash;
155 fd_list_init(&sess->chain_h, sess); 155 fd_list_init(&sess->chain_h, sess);
156 156
157 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &sess->timeout), return NULL ); 157 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &sess->timeout), return NULL );
158 sess->timeout.tv_sec += SESS_DEFAULT_LIFETIME; 158 sess->timeout.tv_sec += SESS_DEFAULT_LIFETIME;
159 fd_list_init(&sess->expire, sess); 159 fd_list_init(&sess->expire, sess);
160 160
161 CHECK_POSIX_DO( pthread_mutex_init(&sess->stlock, NULL), return NULL ); 161 CHECK_POSIX_DO( pthread_mutex_init(&sess->stlock, NULL), return NULL );
162 fd_list_init(&sess->states, sess); 162 fd_list_init(&sess->states, sess);
163 163
164 return sess; 164 return sess;
165 } 165 }
166 166
167 /* destroy the session object. It should really be already unlinked... */ 167 /* destroy the session object. It should really be already unlinked... */
168 static void del_session(struct session * s) 168 static void del_session(struct session * s)
172 fd_list_unlink(&s->chain_h); 172 fd_list_unlink(&s->chain_h);
173 fd_list_unlink(&s->expire); 173 fd_list_unlink(&s->expire);
174 CHECK_POSIX_DO( pthread_mutex_destroy(&s->stlock), /* continue */ ); 174 CHECK_POSIX_DO( pthread_mutex_destroy(&s->stlock), /* continue */ );
175 free(s); 175 free(s);
176 } 176 }
177 177
178 /* The expiry thread */ 178 /* The expiry thread */
179 static void * exp_fct(void * arg) 179 static void * exp_fct(void * arg)
180 { 180 {
181 fd_log_threadname ( "Session/expire" ); 181 fd_log_threadname ( "Session/expire" );
182 TRACE_ENTRY( "" ); 182 TRACE_ENTRY( "" );
183 183
184 184
185 do { 185 do {
186 struct timespec now; 186 struct timespec now;
187 struct session * first; 187 struct session * first;
188 188
189 CHECK_POSIX_DO( pthread_mutex_lock(&exp_lock), break ); 189 CHECK_POSIX_DO( pthread_mutex_lock(&exp_lock), break );
190 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock ); 190 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock );
191 again: 191 again:
192 /* Check if there are expiring sessions available */ 192 /* Check if there are expiring sessions available */
193 if (FD_IS_LIST_EMPTY(&exp_sentinel)) { 193 if (FD_IS_LIST_EMPTY(&exp_sentinel)) {
194 /* Just wait for a change or cancelation */ 194 /* Just wait for a change or cancelation */
195 CHECK_POSIX_DO( pthread_cond_wait( &exp_cond, &exp_lock ), break /* this might not pop the cleanup handler, but since we ASSERT(0), it is not the big issue... */ ); 195 CHECK_POSIX_DO( pthread_cond_wait( &exp_cond, &exp_lock ), break /* this might not pop the cleanup handler, but since we ASSERT(0), it is not the big issue... */ );
196 /* Restart the loop on wakeup */ 196 /* Restart the loop on wakeup */
197 goto again; 197 goto again;
198 } 198 }
199 199
200 /* Get the pointer to the session that expires first */ 200 /* Get the pointer to the session that expires first */
201 first = (struct session *)(exp_sentinel.next->o); 201 first = (struct session *)(exp_sentinel.next->o);
202 ASSERT( VALIDATE_SI(first) ); 202 ASSERT( VALIDATE_SI(first) );
203 203
204 /* Get the current time */ 204 /* Get the current time */
205 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), break ); 205 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), break );
206 206
207 /* If first session is not expired, we just wait until it happens */ 207 /* If first session is not expired, we just wait until it happens */
208 if ( TS_IS_INFERIOR( &now, &first->timeout ) ) { 208 if ( TS_IS_INFERIOR( &now, &first->timeout ) ) {
209 209 CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cond, &exp_lock, &first->timeout ),
210 CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cond, &exp_lock, &first->timeout ),
211 ETIMEDOUT, /* ETIMEDOUT is a normal error, continue */, 210 ETIMEDOUT, /* ETIMEDOUT is a normal error, continue */,
212 /* on other error, */ break ); 211 /* on other error, */ break );
213 212
214 /* on wakeup, loop */ 213 /* on wakeup, loop */
215 goto again; 214 goto again;
216 } 215 }
217 216
218 /* Now, the first session in the list is expired; destroy it */ 217 /* Now, the first session in the list is expired; destroy it */
219 pthread_cleanup_pop( 0 ); 218 pthread_cleanup_pop( 0 );
220 CHECK_POSIX_DO( pthread_mutex_unlock(&exp_lock), break ); 219 CHECK_POSIX_DO( pthread_mutex_unlock(&exp_lock), break );
221 220
222 CHECK_FCT_DO( fd_sess_destroy( &first ), break ); 221 CHECK_FCT_DO( fd_sess_destroy( &first ), break );
223 222
224 } while (1); 223 } while (1);
225 224
226 TRACE_DEBUG(INFO, "A system error occurred in session module! Expiry thread is terminating..."); 225 TRACE_DEBUG(INFO, "A system error occurred in session module! Expiry thread is terminating...");
227 ASSERT(0); 226 ASSERT(0);
228 return NULL; 227 return NULL;
229 } 228 }
230 229
231 230
232 231
233 /********************************************************************************************************/ 232 /********************************************************************************************************/
234 233
235 /* Initialize the session module */ 234 /* Initialize the session module */
236 int fd_sess_init(void) 235 int fd_sess_init(void)
237 { 236 {
238 int i; 237 int i;
239 238
240 TRACE_ENTRY( "" ); 239 TRACE_ENTRY( "" );
241 240
242 /* Initialize the global counters */ 241 /* Initialize the global counters */
243 sid_h = (uint32_t) time(NULL); 242 sid_h = (uint32_t) time(NULL);
244 sid_l = 0; 243 sid_l = 0;
245 244
246 /* Initialize the hash table */ 245 /* Initialize the hash table */
247 for (i = 0; i < sizeof(sess_hash) / sizeof(sess_hash[0]); i++) { 246 for (i = 0; i < sizeof(sess_hash) / sizeof(sess_hash[0]); i++) {
248 fd_list_init( &sess_hash[i].sentinel, NULL ); 247 fd_list_init( &sess_hash[i].sentinel, NULL );
249 CHECK_POSIX( pthread_mutex_init(&sess_hash[i].lock, NULL) ); 248 CHECK_POSIX( pthread_mutex_init(&sess_hash[i].lock, NULL) );
250 } 249 }
251 250
252 return 0; 251 return 0;
253 } 252 }
254 253
255 /* Run this when initializations are complete. */ 254 /* Run this when initializations are complete. */
256 int fd_sess_start(void) 255 int fd_sess_start(void)
257 { 256 {
258 /* Start session garbage collector (expiry) */ 257 /* Start session garbage collector (expiry) */
259 CHECK_POSIX( pthread_create(&exp_thr, NULL, exp_fct, NULL) ); 258 CHECK_POSIX( pthread_create(&exp_thr, NULL, exp_fct, NULL) );
260 259
261 return 0; 260 return 0;
262 } 261 }
263 262
264 /* Terminate */ 263 /* Terminate */
265 void fd_sess_fini(void) 264 void fd_sess_fini(void)
266 { 265 {
267 TRACE_ENTRY(""); 266 TRACE_ENTRY("");
268 CHECK_FCT_DO( fd_thr_term(&exp_thr), /* continue */ ); 267 CHECK_FCT_DO( fd_thr_term(&exp_thr), /* continue */ );
269 268
270 /* Destroy all sessions in the hash table, and the hash table itself? -- How to do it without a race condition ? */ 269 /* Destroy all sessions in the hash table, and the hash table itself? -- How to do it without a race condition ? */
271 270
272 return; 271 return;
273 } 272 }
274 273
275 /* Create a new handler */ 274 /* Create a new handler */
276 int fd_sess_handler_create ( struct session_handler ** handler, void (*cleanup)(struct sess_state *, os0_t, void *), session_state_dump dumper, void * opaque ) 275 int fd_sess_handler_create ( struct session_handler ** handler, void (*cleanup)(struct sess_state *, os0_t, void *), session_state_dump dumper, void * opaque )
277 { 276 {
278 struct session_handler *new; 277 struct session_handler *new;
279 278
280 TRACE_ENTRY("%p %p", handler, cleanup); 279 TRACE_ENTRY("%p %p", handler, cleanup);
281 280
282 CHECK_PARAMS( handler && cleanup ); 281 CHECK_PARAMS( handler && cleanup );
283 282
284 CHECK_MALLOC( new = malloc(sizeof(struct session_handler)) ); 283 CHECK_MALLOC( new = malloc(sizeof(struct session_handler)) );
285 memset(new, 0, sizeof(struct session_handler)); 284 memset(new, 0, sizeof(struct session_handler));
286 285
287 CHECK_POSIX( pthread_mutex_lock(&hdl_lock) ); 286 CHECK_POSIX( pthread_mutex_lock(&hdl_lock) );
288 new->id = ++hdl_id; 287 new->id = ++hdl_id;
289 CHECK_POSIX( pthread_mutex_unlock(&hdl_lock) ); 288 CHECK_POSIX( pthread_mutex_unlock(&hdl_lock) );
290 289
291 new->eyec = SH_EYEC; 290 new->eyec = SH_EYEC;
292 new->cleanup = cleanup; 291 new->cleanup = cleanup;
293 new->state_dump = dumper; 292 new->state_dump = dumper;
294 new->opaque = opaque; 293 new->opaque = opaque;
295 294
296 *handler = new; 295 *handler = new;
297 return 0; 296 return 0;
298 } 297 }
299 298
300 /* Destroy a handler, and all states attached to this handler. This operation is very slow but we don't care since it's rarely used. 299 /* Destroy a handler, and all states attached to this handler. This operation is very slow but we don't care since it's rarely used.
301 * Note that it's better to call this function after all sessions have been deleted... */ 300 * Note that it's better to call this function after all sessions have been deleted... */
302 int fd_sess_handler_destroy ( struct session_handler ** handler, void ** opaque ) 301 int fd_sess_handler_destroy ( struct session_handler ** handler, void ** opaque )
303 { 302 {
304 struct session_handler * del; 303 struct session_handler * del;
305 /* place to save the list of states to be cleaned up. We do it after finding them to avoid deadlocks. the "o" field becomes a copy of the sid. */ 304 /* place to save the list of states to be cleaned up. We do it after finding them to avoid deadlocks. the "o" field becomes a copy of the sid. */
306 struct fd_list deleted_states = FD_LIST_INITIALIZER( deleted_states ); 305 struct fd_list deleted_states = FD_LIST_INITIALIZER( deleted_states );
307 int i; 306 int i;
308 307
309 TRACE_ENTRY("%p", handler); 308 TRACE_ENTRY("%p", handler);
310 CHECK_PARAMS( handler && VALIDATE_SH(*handler) ); 309 CHECK_PARAMS( handler && VALIDATE_SH(*handler) );
311 310
312 del = *handler; 311 del = *handler;
313 *handler = NULL; 312 *handler = NULL;
314 313
315 del->eyec = 0xdead; /* The handler is not valid anymore for any other operation */ 314 del->eyec = 0xdead; /* The handler is not valid anymore for any other operation */
316 315
317 /* Now find all sessions with data registered for this handler, and move this data to the deleted_states list. */ 316 /* Now find all sessions with data registered for this handler, and move this data to the deleted_states list. */
318 for (i = 0; i < sizeof(sess_hash) / sizeof(sess_hash[0]); i++) { 317 for (i = 0; i < sizeof(sess_hash) / sizeof(sess_hash[0]); i++) {
319 struct fd_list * li_si; 318 struct fd_list * li_si;
320 CHECK_POSIX( pthread_mutex_lock(&sess_hash[i].lock) ); 319 CHECK_POSIX( pthread_mutex_lock(&sess_hash[i].lock) );
321 320
322 for (li_si = sess_hash[i].sentinel.next; li_si != &sess_hash[i].sentinel; li_si = li_si->next) { /* for each session in the hash line */ 321 for (li_si = sess_hash[i].sentinel.next; li_si != &sess_hash[i].sentinel; li_si = li_si->next) { /* for each session in the hash line */
323 struct fd_list * li_st; 322 struct fd_list * li_st;
324 struct session * sess = (struct session *)(li_si->o); 323 struct session * sess = (struct session *)(li_si->o);
325 CHECK_POSIX( pthread_mutex_lock(&sess->stlock) ); 324 CHECK_POSIX( pthread_mutex_lock(&sess->stlock) );
326 for (li_st = sess->states.next; li_st != &sess->states; li_st = li_st->next) { /* for each state in this session */ 325 for (li_st = sess->states.next; li_st != &sess->states; li_st = li_st->next) { /* for each state in this session */
338 } 337 }
339 CHECK_POSIX( pthread_mutex_unlock(&sess->stlock) ); 338 CHECK_POSIX( pthread_mutex_unlock(&sess->stlock) );
340 } 339 }
341 CHECK_POSIX( pthread_mutex_unlock(&sess_hash[i].lock) ); 340 CHECK_POSIX( pthread_mutex_unlock(&sess_hash[i].lock) );
342 } 341 }
343 342
344 /* Now, delete all states after calling their cleanup handler */ 343 /* Now, delete all states after calling their cleanup handler */
345 while (!FD_IS_LIST_EMPTY(&deleted_states)) { 344 while (!FD_IS_LIST_EMPTY(&deleted_states)) {
346 struct state * st = (struct state *)(deleted_states.next->o); 345 struct state * st = (struct state *)(deleted_states.next->o);
347 TRACE_DEBUG(FULL, "Calling cleanup handler for session '%s' and data %p", st->sid, st->state); 346 TRACE_DEBUG(FULL, "Calling cleanup handler for session '%s' and data %p", st->sid, st->state);
348 (*del->cleanup)(st->state, st->sid, del->opaque); 347 (*del->cleanup)(st->state, st->sid, del->opaque);
349 fd_list_unlink(&st->chain); 348 fd_list_unlink(&st->chain);
350 free(st); 349 free(st);
351 } 350 }
352 351
353 if (opaque) 352 if (opaque)
354 *opaque = del->opaque; 353 *opaque = del->opaque;
355 354
356 /* Free the handler */ 355 /* Free the handler */
357 free(del); 356 free(del);
358 357
359 return 0; 358 return 0;
360 } 359 }
361 360
362 361
363 362
369 uint32_t hash; 368 uint32_t hash;
370 struct session * sess; 369 struct session * sess;
371 struct fd_list * li; 370 struct fd_list * li;
372 int found = 0; 371 int found = 0;
373 int ret = 0; 372 int ret = 0;
374 373
375 TRACE_ENTRY("%p %p %zd %p %zd", session, diamid, diamidlen, opt, optlen); 374 TRACE_ENTRY("%p %p %zd %p %zd", session, diamid, diamidlen, opt, optlen);
376 CHECK_PARAMS( session && (diamid || opt) ); 375 CHECK_PARAMS( session && (diamid || opt) );
377 376
378 if (diamid) { 377 if (diamid) {
379 if (!diamidlen) { 378 if (!diamidlen) {
380 diamidlen = strlen(diamid); 379 diamidlen = strlen(diamid);
381 } 380 }
382 /* We check if the string is a valid DiameterIdentity */ 381 /* We check if the string is a valid DiameterIdentity */
383 CHECK_PARAMS( fd_os_is_valid_DiameterIdentity((uint8_t *)diamid, diamidlen) ); 382 CHECK_PARAMS( fd_os_is_valid_DiameterIdentity((uint8_t *)diamid, diamidlen) );
384 } else { 383 } else {
385 diamidlen = 0; 384 diamidlen = 0;
386 } 385 }
387 if (opt) { 386 if (opt) {
388 if (!optlen) { 387 if (!optlen) {
389 optlen = strlen((char *)opt); 388 optlen = strlen((char *)opt);
390 } else { 389 } else {
391 CHECK_PARAMS( fd_os_is_valid_os0(opt, optlen) ); 390 CHECK_PARAMS( fd_os_is_valid_os0(opt, optlen) );
392 } 391 }
393 } else { 392 } else {
394 optlen = 0; 393 optlen = 0;
395 } 394 }
396 395
397 /* Ok, first create the identifier for the string */ 396 /* Ok, first create the identifier for the string */
398 if (diamid == NULL) { 397 if (diamid == NULL) {
399 /* opt is the full string */ 398 /* opt is the full string */
400 CHECK_MALLOC( sid = os0dup(opt, optlen) ); 399 CHECK_MALLOC( sid = os0dup(opt, optlen) );
401 sidlen = optlen; 400 sidlen = optlen;
407 sidlen += 22; /* max size of ';<high32>;<low32>' */ 406 sidlen += 22; /* max size of ';<high32>;<low32>' */
408 if (opt) 407 if (opt)
409 sidlen += 1 + optlen; /* ';opt' */ 408 sidlen += 1 + optlen; /* ';opt' */
410 sidlen++; /* space for the final \0 also */ 409 sidlen++; /* space for the final \0 also */
411 CHECK_MALLOC( sid = malloc(sidlen) ); 410 CHECK_MALLOC( sid = malloc(sidlen) );
412 411
413 CHECK_POSIX( pthread_mutex_lock(&sid_lock) ); 412 CHECK_POSIX( pthread_mutex_lock(&sid_lock) );
414 if ( ++sid_l == 0 ) /* overflow */ 413 if ( ++sid_l == 0 ) /* overflow */
415 ++sid_h; 414 ++sid_h;
416 sid_h_cpy = sid_h; 415 sid_h_cpy = sid_h;
417 sid_l_cpy = sid_l; 416 sid_l_cpy = sid_l;
418 CHECK_POSIX( pthread_mutex_unlock(&sid_lock) ); 417 CHECK_POSIX( pthread_mutex_unlock(&sid_lock) );
419 418
420 if (opt) { 419 if (opt) {
421 sidlen = snprintf((char*)sid, sidlen, "%.*s;%u;%u;%.*s", (int)diamidlen, diamid, sid_h_cpy, sid_l_cpy, (int)optlen, opt); 420 sidlen = snprintf((char*)sid, sidlen, "%.*s;%u;%u;%.*s", (int)diamidlen, diamid, sid_h_cpy, sid_l_cpy, (int)optlen, opt);
422 } else { 421 } else {
423 sidlen = snprintf((char*)sid, sidlen, "%.*s;%u;%u", (int)diamidlen, diamid, sid_h_cpy, sid_l_cpy); 422 sidlen = snprintf((char*)sid, sidlen, "%.*s;%u;%u", (int)diamidlen, diamid, sid_h_cpy, sid_l_cpy);
424 } 423 }
425 } 424 }
426 425
427 hash = fd_os_hash(sid, sidlen); 426 hash = fd_os_hash(sid, sidlen);
428 427
429 /* Now find the place to add this object in the hash table. */ 428 /* Now find the place to add this object in the hash table. */
430 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash) ) ); 429 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash) ) );
431 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) ); 430 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) );
432 431
433 for (li = H_LIST(hash)->next; li != H_LIST(hash); li = li->next) { 432 for (li = H_LIST(hash)->next; li != H_LIST(hash); li = li->next) {
434 int cmp; 433 int cmp;
435 struct session * s = (struct session *)(li->o); 434 struct session * s = (struct session *)(li->o);
436 435
437 /* The list is ordered by hash and sid (in case of collisions) */ 436 /* The list is ordered by hash and sid (in case of collisions) */
438 if (s->hash < hash) 437 if (s->hash < hash)
439 continue; 438 continue;
440 if (s->hash > hash) 439 if (s->hash > hash)
441 break; 440 break;
442 441
443 cmp = fd_os_cmp(s->sid, s->sidlen, sid, sidlen); 442 cmp = fd_os_cmp(s->sid, s->sidlen, sid, sidlen);
444 if (cmp < 0) 443 if (cmp < 0)
445 continue; 444 continue;
446 if (cmp > 0) 445 if (cmp > 0)
447 break; 446 break;
448 447
449 /* A session with the same sid was already in the hash table */ 448 /* A session with the same sid was already in the hash table */
450 found = 1; 449 found = 1;
451 *session = s; 450 *session = s;
452 break; 451 break;
453 } 452 }
454 453
455 /* If the session did not exist, we can create it & link it in global tables */ 454 /* If the session did not exist, we can create it & link it in global tables */
456 if (!found) { 455 if (!found) {
457 CHECK_MALLOC_DO(sess = new_session(sid, sidlen, hash), 456 CHECK_MALLOC_DO(sess = new_session(sid, sidlen, hash),
458 { 457 {
459 ret = ENOMEM; 458 ret = ENOMEM;
460 free(sid); 459 free(sid);
461 goto out; 460 goto out;
462 } ); 461 } );
463 462
464 fd_list_insert_before(li, &sess->chain_h); /* hash table */ 463 fd_list_insert_before(li, &sess->chain_h); /* hash table */
465 sess->msg_cnt++; 464 sess->msg_cnt++;
466 } else { 465 } else {
467 free(sid); 466 free(sid);
468 467
469 CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) ); 468 CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) );
470 (*session)->msg_cnt++; 469 (*session)->msg_cnt++;
471 CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) ); 470 CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) );
472 471
473 /* it was found: was it previously destroyed? */ 472 /* it was found: was it previously destroyed? */
474 if ((*session)->is_destroyed == 0) { 473 if ((*session)->is_destroyed == 0) {
475 ret = EALREADY; 474 ret = EALREADY;
476 goto out; 475 goto out;
477 } else { 476 } else {
478 /* the session was marked destroyed, let's re-activate it. */ 477 /* the session was marked destroyed, let's re-activate it. */
479 sess = *session; 478 sess = *session;
480 sess->is_destroyed = 0; 479 sess->is_destroyed = 0;
481 480
482 /* update the expiry time */ 481 /* update the expiry time */
483 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &sess->timeout), { ASSERT(0); } ); 482 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &sess->timeout), { ASSERT(0); } );
484 sess->timeout.tv_sec += SESS_DEFAULT_LIFETIME; 483 sess->timeout.tv_sec += SESS_DEFAULT_LIFETIME;
485 } 484 }
486 } 485 }
487 486
488 /* We must insert in the expiry list */ 487 /* We must insert in the expiry list */
489 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) ); 488 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) );
490 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock ); 489 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock );
491 490
492 /* Find the position in that list. We take it in reverse order */ 491 /* Find the position in that list. We take it in reverse order */
509 508
510 out: 509 out:
511 ; 510 ;
512 pthread_cleanup_pop(0); 511 pthread_cleanup_pop(0);
513 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) ); 512 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) );
514 513
515 if (ret) /* in case of error */ 514 if (ret) /* in case of error */
516 return ret; 515 return ret;
517 516
518 *session = sess; 517 *session = sess;
519 return 0; 518 return 0;
520 } 519 }
521 520
522 /* Find or create a session -- the msg refcount is increased */ 521 /* Find or create a session -- the msg refcount is increased */
523 int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new) 522 int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new)
524 { 523 {
525 int ret; 524 int ret;
526 525
527 TRACE_ENTRY("%p %zd %p %p", sid, len, session, new); 526 TRACE_ENTRY("%p %zd %p %p", sid, len, session, new);
528 CHECK_PARAMS( sid && session ); 527 CHECK_PARAMS( sid && session );
529 528
530 if (!fd_os_is_valid_os0(sid,len)) { 529 if (!fd_os_is_valid_os0(sid,len)) {
531 TRACE_DEBUG(INFO, "Warning: a Session-Id value contains \\0 chars... (len:%zd, begin:'%.*s') => Debug messages may be truncated.", len, (int)len, sid); 530 TRACE_DEBUG(INFO, "Warning: a Session-Id value contains \\0 chars... (len:%zd, begin:'%.*s') => Debug messages may be truncated.", len, (int)len, sid);
532 } 531 }
533 532
534 /* All the work is done in sess_new */ 533 /* All the work is done in sess_new */
535 ret = fd_sess_new ( session, NULL, 0, sid, len ); 534 ret = fd_sess_new ( session, NULL, 0, sid, len );
536 switch (ret) { 535 switch (ret) {
537 case 0: 536 case 0:
538 case EALREADY: 537 case EALREADY:
539 break; 538 break;
540 539
541 default: 540 default:
542 CHECK_FCT(ret); 541 CHECK_FCT(ret);
543 } 542 }
544 543
545 if (new) 544 if (new)
546 *new = ret ? 0 : 1; 545 *new = ret ? 0 : 1;
547 546
548 return 0; 547 return 0;
549 } 548 }
550 549
551 /* Get the sid of a session */ 550 /* Get the sid of a session */
552 int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen ) 551 int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen )
553 { 552 {
554 TRACE_ENTRY("%p %p", session, sid); 553 TRACE_ENTRY("%p %p", session, sid);
555 554
556 CHECK_PARAMS( VALIDATE_SI(session) && sid ); 555 CHECK_PARAMS( VALIDATE_SI(session) && sid );
557 556
558 *sid = session->sid; 557 *sid = session->sid;
559 if (sidlen) 558 if (sidlen)
560 *sidlen = session->sidlen; 559 *sidlen = session->sidlen;
561 560
562 return 0; 561 return 0;
563 } 562 }
564 563
565 /* Change the timeout value of a session */ 564 /* Change the timeout value of a session */
566 int fd_sess_settimeout( struct session * session, const struct timespec * timeout ) 565 int fd_sess_settimeout( struct session * session, const struct timespec * timeout )
567 { 566 {
568 struct fd_list * li; 567 struct fd_list * li;
569 568
570 TRACE_ENTRY("%p %p", session, timeout); 569 TRACE_ENTRY("%p %p", session, timeout);
571 CHECK_PARAMS( VALIDATE_SI(session) && timeout ); 570 CHECK_PARAMS( VALIDATE_SI(session) && timeout );
572 571
573 /* Lock -- do we need to lock the hash table as well? I don't think so... */ 572 /* Lock -- do we need to lock the hash table as well? I don't think so... */
574 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) ); 573 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) );
575 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock ); 574 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock );
576 575
577 /* Update the timeout */ 576 /* Update the timeout */
578 fd_list_unlink(&session->expire); 577 fd_list_unlink(&session->expire);
579 memcpy(&session->timeout, timeout, sizeof(struct timespec)); 578 memcpy(&session->timeout, timeout, sizeof(struct timespec));
580 579
581 /* Find the new position in expire list. We take it in normal order */ 580 /* Find the new position in expire list. We take it in normal order */
582 for (li = exp_sentinel.next; li != &exp_sentinel; li = li->next) { 581 for (li = exp_sentinel.next; li != &exp_sentinel; li = li->next) {
583 struct session * s = (struct session *)(li->o); 582 struct session * s = (struct session *)(li->o);
584 583
585 if (TS_IS_INFERIOR( &s->timeout, &session->timeout ) ) 584 if (TS_IS_INFERIOR( &s->timeout, &session->timeout ) )
595 } 594 }
596 595
597 /* We're done */ 596 /* We're done */
598 pthread_cleanup_pop(0); 597 pthread_cleanup_pop(0);
599 CHECK_POSIX( pthread_mutex_unlock( &exp_lock ) ); 598 CHECK_POSIX( pthread_mutex_unlock( &exp_lock ) );
600 599
601 return 0; 600 return 0;
602 } 601 }
603 602
604 /* Destroy the states associated to a session, and mark it destroyed. */ 603 /* Destroy the states associated to a session, and mark it destroyed. */
605 int fd_sess_destroy ( struct session ** session ) 604 int fd_sess_destroy ( struct session ** session )
606 { 605 {
607 struct session * sess; 606 struct session * sess;
608 int destroy_now; 607 int destroy_now;
609 os0_t sid; 608 os0_t sid;
610 int ret = 0; 609 int ret = 0;
611 610
612 /* place to save the list of states to be cleaned up. We do it after finding them to avoid deadlocks. the "o" field becomes a copy of the sid. */ 611 /* place to save the list of states to be cleaned up. We do it after finding them to avoid deadlocks. the "o" field becomes a copy of the sid. */
613 struct fd_list deleted_states = FD_LIST_INITIALIZER( deleted_states ); 612 struct fd_list deleted_states = FD_LIST_INITIALIZER( deleted_states );
614 613
615 TRACE_ENTRY("%p", session); 614 TRACE_ENTRY("%p", session);
616 CHECK_PARAMS( session && VALIDATE_SI(*session) ); 615 CHECK_PARAMS( session && VALIDATE_SI(*session) );
617 616
618 sess = *session; 617 sess = *session;
619 *session = NULL; 618 *session = NULL;
620 619
621 /* Lock the hash line */ 620 /* Lock the hash line */
622 CHECK_POSIX( pthread_mutex_lock( H_LOCK(sess->hash) ) ); 621 CHECK_POSIX( pthread_mutex_lock( H_LOCK(sess->hash) ) );
623 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(sess->hash) ); 622 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(sess->hash) );
624 623
625 /* Unlink from the expiry list */ 624 /* Unlink from the expiry list */
626 CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 625 CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } );
626 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock );
627 if (!FD_IS_LIST_EMPTY(&sess->expire)) { 627 if (!FD_IS_LIST_EMPTY(&sess->expire)) {
628 sess_cnt--; 628 sess_cnt--;
629 fd_list_unlink( &sess->expire ); /* no need to signal the condition here */ 629 fd_list_unlink( &sess->expire ); /* no need to signal the condition here */
630 } 630 }
631 pthread_cleanup_pop(0);
631 CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 632 CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } );
632 633
633 /* Now move all states associated to this session into deleted_states */ 634 /* Now move all states associated to this session into deleted_states */
634 CHECK_POSIX_DO( pthread_mutex_lock( &sess->stlock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 635 CHECK_POSIX_DO( pthread_mutex_lock( &sess->stlock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } );
635 while (!FD_IS_LIST_EMPTY(&sess->states)) { 636 while (!FD_IS_LIST_EMPTY(&sess->states)) {
636 struct state * st = (struct state *)(sess->states.next->o); 637 struct state * st = (struct state *)(sess->states.next->o);
637 fd_list_unlink(&st->chain); 638 fd_list_unlink(&st->chain);
638 fd_list_insert_before(&deleted_states, &st->chain); 639 fd_list_insert_before(&deleted_states, &st->chain);
639 } 640 }
640 CHECK_POSIX_DO( pthread_mutex_unlock( &sess->stlock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 641 CHECK_POSIX_DO( pthread_mutex_unlock( &sess->stlock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } );
641 642
642 /* Mark the session as destroyed */ 643 /* Mark the session as destroyed */
643 destroy_now = (sess->msg_cnt == 0); 644 destroy_now = (sess->msg_cnt == 0);
644 if (destroy_now) { 645 if (destroy_now) {
645 fd_list_unlink( &sess->chain_h ); 646 fd_list_unlink( &sess->chain_h );
646 sid = sess->sid; 647 sid = sess->sid;
648 sess->is_destroyed = 1; 649 sess->is_destroyed = 1;
649 CHECK_MALLOC_DO( sid = os0dup(sess->sid, sess->sidlen), ret = ENOMEM ); 650 CHECK_MALLOC_DO( sid = os0dup(sess->sid, sess->sidlen), ret = ENOMEM );
650 } 651 }
651 pthread_cleanup_pop(0); 652 pthread_cleanup_pop(0);
652 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(sess->hash) ) ); 653 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(sess->hash) ) );
653 654
654 if (ret) 655 if (ret)
655 return ret; 656 return ret;
656 657
657 /* Now, really delete the states */ 658 /* Now, really delete the states */
658 while (!FD_IS_LIST_EMPTY(&deleted_states)) { 659 while (!FD_IS_LIST_EMPTY(&deleted_states)) {
659 struct state * st = (struct state *)(deleted_states.next->o); 660 struct state * st = (struct state *)(deleted_states.next->o);
660 fd_list_unlink(&st->chain); 661 fd_list_unlink(&st->chain);
661 TRACE_DEBUG(FULL, "Calling handler %p cleanup for state %p registered with session '%s'", st->hdl, st, sid); 662 TRACE_DEBUG(FULL, "Calling handler %p cleanup for state %p registered with session '%s'", st->hdl, st, sid);
662 (*st->hdl->cleanup)(st->state, sid, st->hdl->opaque); 663 (*st->hdl->cleanup)(st->state, sid, st->hdl->opaque);
663 free(st); 664 free(st);
664 } 665 }
665 666
666 /* Finally, destroy the session itself, if it is not referrenced by any message anymore */ 667 /* Finally, destroy the session itself, if it is not referrenced by any message anymore */
667 if (destroy_now) { 668 if (destroy_now) {
668 del_session(sess); 669 del_session(sess);
669 } else { 670 } else {
670 free(sid); 671 free(sid);
671 } 672 }
672 673
673 return 0; 674 return 0;
674 } 675 }
675 676
676 /* Destroy a session if it is not used */ 677 /* Destroy a session if it is not used */
677 int fd_sess_reclaim ( struct session ** session ) 678 int fd_sess_reclaim ( struct session ** session )
678 { 679 {
679 struct session * sess; 680 struct session * sess;
680 uint32_t hash; 681 uint32_t hash;
681 int destroy_now = 0; 682 int destroy_now = 0;
682 683
683 TRACE_ENTRY("%p", session); 684 TRACE_ENTRY("%p", session);
684 CHECK_PARAMS( session && VALIDATE_SI(*session) ); 685 CHECK_PARAMS( session && VALIDATE_SI(*session) );
685 686
686 sess = *session; 687 sess = *session;
687 hash = sess->hash; 688 hash = sess->hash;
688 *session = NULL; 689 *session = NULL;
689 690
690 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash) ) ); 691 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash) ) );
691 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) ); 692 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) );
692 CHECK_POSIX_DO( pthread_mutex_lock( &sess->stlock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 693 CHECK_POSIX_DO( pthread_mutex_lock( &sess->stlock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } );
693 pthread_cleanup_push( fd_cleanup_mutex, &sess->stlock ); 694 pthread_cleanup_push( fd_cleanup_mutex, &sess->stlock );
694 CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 695 CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } );
695 696 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock );
697
696 /* We only do something if the states list is empty */ 698 /* We only do something if the states list is empty */
697 if (FD_IS_LIST_EMPTY(&sess->states)) { 699 if (FD_IS_LIST_EMPTY(&sess->states)) {
698 /* In this case, we do as in destroy */ 700 /* In this case, we do as in destroy */
699 fd_list_unlink( &sess->expire ); 701 fd_list_unlink( &sess->expire );
700 destroy_now = (sess->msg_cnt == 0); 702 destroy_now = (sess->msg_cnt == 0);
703 } else { 705 } else {
704 /* just mark it as destroyed, it will be freed when the last message stops referencing it */ 706 /* just mark it as destroyed, it will be freed when the last message stops referencing it */
705 sess->is_destroyed = 1; 707 sess->is_destroyed = 1;
706 } 708 }
707 } 709 }
708 710
711 pthread_cleanup_pop(0);
709 CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 712 CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } );
710 pthread_cleanup_pop(0); 713 pthread_cleanup_pop(0);
711 CHECK_POSIX_DO( pthread_mutex_unlock( &sess->stlock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 714 CHECK_POSIX_DO( pthread_mutex_unlock( &sess->stlock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } );
712 pthread_cleanup_pop(0); 715 pthread_cleanup_pop(0);
713 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) ); 716 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) );
714 717
715 if (destroy_now) 718 if (destroy_now)
716 del_session(sess); 719 del_session(sess);
717 720
718 return 0; 721 return 0;
719 } 722 }
720 723
721 /* Save a state information with a session */ 724 /* Save a state information with a session */
722 int fd_sess_state_store ( struct session_handler * handler, struct session * session, struct sess_state ** state ) 725 int fd_sess_state_store ( struct session_handler * handler, struct session * session, struct sess_state ** state )
723 { 726 {
724 struct state *new; 727 struct state *new;
725 struct fd_list * li; 728 struct fd_list * li;
726 int already = 0; 729 int already = 0;
727 int ret = 0; 730 int ret = 0;
728 731
729 TRACE_ENTRY("%p %p %p", handler, session, state); 732 TRACE_ENTRY("%p %p %p", handler, session, state);
730 CHECK_PARAMS( handler && VALIDATE_SH(handler) && session && VALIDATE_SI(session) && (!session->is_destroyed) && state ); 733 CHECK_PARAMS( handler && VALIDATE_SH(handler) && session && VALIDATE_SI(session) && (!session->is_destroyed) && state );
731 734
732 /* Lock the session state list */ 735 /* Lock the session state list */
733 CHECK_POSIX( pthread_mutex_lock(&session->stlock) ); 736 CHECK_POSIX( pthread_mutex_lock(&session->stlock) );
734 pthread_cleanup_push( fd_cleanup_mutex, &session->stlock ); 737 pthread_cleanup_push( fd_cleanup_mutex, &session->stlock );
735 738
736 /* Create the new state object */ 739 /* Create the new state object */
737 CHECK_MALLOC_DO(new = malloc(sizeof(struct state)), { ret = ENOMEM; goto out; } ); 740 CHECK_MALLOC_DO(new = malloc(sizeof(struct state)), { ret = ENOMEM; goto out; } );
738 memset(new, 0, sizeof(struct state)); 741 memset(new, 0, sizeof(struct state));
739 742
740 new->eyec = SD_EYEC; 743 new->eyec = SD_EYEC;
741 new->state= *state; 744 new->state= *state;
742 fd_list_init(&new->chain, new); 745 fd_list_init(&new->chain, new);
743 new->hdl = handler; 746 new->hdl = handler;
744 747
745 /* find place for this state in the list */ 748 /* find place for this state in the list */
746 for (li = session->states.next; li != &session->states; li = li->next) { 749 for (li = session->states.next; li != &session->states; li = li->next) {
747 struct state * st = (struct state *)(li->o); 750 struct state * st = (struct state *)(li->o);
748 /* The list is ordered by handler's id */ 751 /* The list is ordered by handler's id */
749 if (st->hdl->id < handler->id) 752 if (st->hdl->id < handler->id)
750 continue; 753 continue;
751 754
752 if (st->hdl->id == handler->id) { 755 if (st->hdl->id == handler->id) {
753 TRACE_DEBUG(INFO, "A state was already stored for session '%s' and handler '%p', at location %p", session->sid, st->hdl, st->state); 756 TRACE_DEBUG(INFO, "A state was already stored for session '%s' and handler '%p', at location %p", session->sid, st->hdl, st->state);
754 already = EALREADY; 757 already = EALREADY;
755 } 758 }
756 759
757 break; 760 break;
758 } 761 }
759 762
760 if (!already) { 763 if (!already) {
761 fd_list_insert_before(li, &new->chain); 764 fd_list_insert_before(li, &new->chain);
762 *state = NULL; 765 *state = NULL;
763 } else { 766 } else {
764 free(new); 767 free(new);
765 } 768 }
766 out: 769 out:
767 ; 770 ;
768 pthread_cleanup_pop(0); 771 pthread_cleanup_pop(0);
769 CHECK_POSIX( pthread_mutex_unlock(&session->stlock) ); 772 CHECK_POSIX( pthread_mutex_unlock(&session->stlock) );
770 773
771 return ret ?: already; 774 return ret ?: already;
772 } 775 }
773 776
774 /* Get the data back */ 777 /* Get the data back */
775 int fd_sess_state_retrieve ( struct session_handler * handler, struct session * session, struct sess_state ** state ) 778 int fd_sess_state_retrieve ( struct session_handler * handler, struct session * session, struct sess_state ** state )
776 { 779 {
777 struct fd_list * li; 780 struct fd_list * li;
778 struct state * st = NULL; 781 struct state * st = NULL;
779 782
780 TRACE_ENTRY("%p %p %p", handler, session, state); 783 TRACE_ENTRY("%p %p %p", handler, session, state);
781 CHECK_PARAMS( handler && VALIDATE_SH(handler) && session && VALIDATE_SI(session) && state ); 784 CHECK_PARAMS( handler && VALIDATE_SH(handler) && session && VALIDATE_SI(session) && state );
782 785
783 *state = NULL; 786 *state = NULL;
784 787
785 /* Lock the session state list */ 788 /* Lock the session state list */
786 CHECK_POSIX( pthread_mutex_lock(&session->stlock) ); 789 CHECK_POSIX( pthread_mutex_lock(&session->stlock) );
787 pthread_cleanup_push( fd_cleanup_mutex, &session->stlock ); 790 pthread_cleanup_push( fd_cleanup_mutex, &session->stlock );
788 791
789 /* find the state in the list */ 792 /* find the state in the list */
790 for (li = session->states.next; li != &session->states; li = li->next) { 793 for (li = session->states.next; li != &session->states; li = li->next) {
791 st = (struct state *)(li->o); 794 st = (struct state *)(li->o);
792 795
793 /* The list is ordered by handler's id */ 796 /* The list is ordered by handler's id */
794 if (st->hdl->id > handler->id) 797 if (st->hdl->id > handler->id)
795 break; 798 break;
796 } 799 }
797 800
798 /* If we found the state */ 801 /* If we found the state */
799 if (st && (st->hdl == handler)) { 802 if (st && (st->hdl == handler)) {
800 fd_list_unlink(&st->chain); 803 fd_list_unlink(&st->chain);
801 *state = st->state; 804 *state = st->state;
802 free(st); 805 free(st);
803 } 806 }
804 807
805 pthread_cleanup_pop(0); 808 pthread_cleanup_pop(0);
806 CHECK_POSIX( pthread_mutex_unlock(&session->stlock) ); 809 CHECK_POSIX( pthread_mutex_unlock(&session->stlock) );
807 810
808 return 0; 811 return 0;
809 } 812 }
810 813
811 /* For the messages module */ 814 /* For the messages module */
812 int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new) 815 int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new)
813 { 816 {
814 TRACE_ENTRY("%p %zd %p %p", sid, len, session, new); 817 TRACE_ENTRY("%p %zd %p %p", sid, len, session, new);
815 CHECK_PARAMS( sid && len && session ); 818 CHECK_PARAMS( sid && len && session );
816 819
817 /* Get the session object */ 820 /* Get the session object */
818 CHECK_FCT( fd_sess_fromsid_msg ( sid, len, session, new) ); 821 CHECK_FCT( fd_sess_fromsid_msg ( sid, len, session, new) );
819 822
820 /* Decrease the refcount */ 823 /* Decrease the refcount */
821 CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) ); 824 CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) );
822 (*session)->msg_cnt--; /* was increased in fd_sess_new */ 825 (*session)->msg_cnt--; /* was increased in fd_sess_new */
823 CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) ); 826 CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) );
824 827
825 /* Done */ 828 /* Done */
826 return 0; 829 return 0;
827 } 830 }
828 831
829 int fd_sess_ref_msg ( struct session * session ) 832 int fd_sess_ref_msg ( struct session * session )
833 836
834 /* Update the msg refcount */ 837 /* Update the msg refcount */
835 CHECK_POSIX( pthread_mutex_lock(&session->stlock) ); 838 CHECK_POSIX( pthread_mutex_lock(&session->stlock) );
836 session->msg_cnt++; 839 session->msg_cnt++;
837 CHECK_POSIX( pthread_mutex_unlock(&session->stlock) ); 840 CHECK_POSIX( pthread_mutex_unlock(&session->stlock) );
838 841
839 return 0; 842 return 0;
840 } 843 }
841 844
842 int fd_sess_reclaim_msg ( struct session ** session ) 845 int fd_sess_reclaim_msg ( struct session ** session )
843 { 846 {
844 int reclaim; 847 int reclaim;
845 uint32_t hash; 848 uint32_t hash;
846 849
847 TRACE_ENTRY("%p", session); 850 TRACE_ENTRY("%p", session);
848 CHECK_PARAMS( session && VALIDATE_SI(*session) ); 851 CHECK_PARAMS( session && VALIDATE_SI(*session) );
849 852
850 /* Lock the hash line to avoid possibility that session is freed while we are reclaiming */ 853 /* Lock the hash line to avoid possibility that session is freed while we are reclaiming */
851 hash = (*session)->hash; 854 hash = (*session)->hash;
852 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash)) ); 855 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash)) );
853 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) ); 856 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) );
854 857
855 /* Update the msg refcount */ 858 /* Update the msg refcount */
856 CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) ); 859 CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) );
857 reclaim = (*session)->msg_cnt; 860 reclaim = (*session)->msg_cnt;
858 (*session)->msg_cnt = reclaim - 1; 861 (*session)->msg_cnt = reclaim - 1;
859 CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) ); 862 CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) );
860 863
861 /* Ok, now unlock the hash line */ 864 /* Ok, now unlock the hash line */
862 pthread_cleanup_pop( 0 ); 865 pthread_cleanup_pop( 0 );
863 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) ); 866 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) );
864 867
865 /* and reclaim if no message references the session anymore */ 868 /* and reclaim if no message references the session anymore */
866 if (reclaim == 1) { 869 if (reclaim == 1) {
867 CHECK_FCT(fd_sess_reclaim ( session )); 870 CHECK_FCT(fd_sess_reclaim ( session ));
868 } else { 871 } else {
869 *session = NULL; 872 *session = NULL;
875 878
876 /* Dump functions */ 879 /* Dump functions */
877 DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states) 880 DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states)
878 { 881 {
879 FD_DUMP_HANDLE_OFFSET(); 882 FD_DUMP_HANDLE_OFFSET();
880 883
881 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{session}(@%p): ", session), return NULL); 884 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{session}(@%p): ", session), return NULL);
882 885
883 if (!VALIDATE_SI(session)) { 886 if (!VALIDATE_SI(session)) {
884 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL); 887 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
885 } else { 888 } else {
886 char timebuf[30]; 889 char timebuf[30];
887 struct tm tm; 890 struct tm tm;
888 891
889 strftime(timebuf, sizeof(timebuf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm )); 892 strftime(timebuf, sizeof(timebuf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
890 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%zd) h:%x m:%d d:%d to:%s.%06ld", 893 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%zd) h:%x m:%d d:%d to:%s.%06ld",
891 session->sid, session->sidlen, session->hash, session->msg_cnt, session->is_destroyed, 894 session->sid, session->sidlen, session->hash, session->msg_cnt, session->is_destroyed,
892 timebuf, session->timeout.tv_nsec/1000), 895 timebuf, session->timeout.tv_nsec/1000),
893 return NULL); 896 return NULL);
894 897
895 if (with_states) { 898 if (with_states) {
896 struct fd_list * li; 899 struct fd_list * li;
897 CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ ); 900 CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ );
898 pthread_cleanup_push( fd_cleanup_mutex, &session->stlock ); 901 pthread_cleanup_push( fd_cleanup_mutex, &session->stlock );
899 902
900 for (li = session->states.next; li != &session->states; li = li->next) { 903 for (li = session->states.next; li != &session->states; li = li->next) {
901 struct state * st = (struct state *)(li->o); 904 struct state * st = (struct state *)(li->o);
902 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {state i:%d}(@%p): ", st->hdl->id, st), return NULL); 905 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {state i:%d}(@%p): ", st->hdl->id, st), return NULL);
903 if (st->hdl->state_dump) { 906 if (st->hdl->state_dump) {
904 CHECK_MALLOC_DO( (*st->hdl->state_dump)( FD_DUMP_STD_PARAMS, st->state), 907 CHECK_MALLOC_DO( (*st->hdl->state_dump)( FD_DUMP_STD_PARAMS, st->state),
905 fd_dump_extend( FD_DUMP_STD_PARAMS, "[dumper error]")); 908 fd_dump_extend( FD_DUMP_STD_PARAMS, "[dumper error]"));
906 } else { 909 } else {
907 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<%p>", st->state), return NULL); 910 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<%p>", st->state), return NULL);
908 } 911 }
909 } 912 }
910 913
911 pthread_cleanup_pop(0); 914 pthread_cleanup_pop(0);
912 CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ ); 915 CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
913 } 916 }
914 } 917 }
915 918
916 return *buf; 919 return *buf;
917 } 920 }
918 921
919 DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler) 922 DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler)
920 { 923 {
921 FD_DUMP_HANDLE_OFFSET(); 924 FD_DUMP_HANDLE_OFFSET();
922 925
923 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{sesshdl}(@%p): ", handler), return NULL); 926 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{sesshdl}(@%p): ", handler), return NULL);
924 927
925 if (!VALIDATE_SH(handler)) { 928 if (!VALIDATE_SH(handler)) {
926 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL); 929 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
927 } else { 930 } else {
928 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "i:%d cl:%p d:%p o:%p", handler->id, handler->cleanup, handler->state_dump, handler->opaque), return NULL); 931 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "i:%d cl:%p d:%p o:%p", handler->id, handler->cleanup, handler->state_dump, handler->opaque), return NULL);
929 } 932 }
930 return *buf; 933 return *buf;
931 } 934 }
932 935
933 int fd_sess_getcount(uint32_t *cnt) 936 int fd_sess_getcount(uint32_t *cnt)
934 { 937 {
935 CHECK_PARAMS(cnt); 938 CHECK_PARAMS(cnt);
936 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) ); 939 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) );
"Welcome to our mercurial repository"