X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/128a99037c1ac10a72d286e311ce3b7bf6822caf..68c5deb920aea924db1c0da22309c80e60e8992b:/aim_snac.c diff --git a/aim_snac.c b/aim_snac.c index 5c51482..64b884a 100644 --- a/aim_snac.c +++ b/aim_snac.c @@ -5,113 +5,151 @@ * * outstanding_snacs is a list of aim_snac_t structs. A SNAC should be added * whenever a new SNAC is sent and it should remain in the list until the - * response for it has been receieved. + * response for it has been receieved. * - * First edition badly written by Adam Fritzler (afritz@delphid.ml.org) - * Current edition nicely rewritten (it even works) by n (n@ml.org) + * cleansnacs() should be called periodically by the client in order + * to facilitate the aging out of unreplied-to SNACs. This can and does + * happen, so it should be handled. * */ #include -u_long aim_newsnac(struct aim_session_t *sess, - struct aim_snac_t *newsnac) +/* + * Called from aim_session_init() to initialize the hash. + */ +faim_internal void aim_initsnachash(struct aim_session_t *sess) +{ + int i; + + for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { + sess->snac_hash[i] = NULL; + faim_mutex_init(&sess->snac_hash_locks[i]); + } + + return; +} + +/* + * Clones the passed snac structure and caches it in the + * list/hash. + */ +faim_internal unsigned long aim_newsnac(struct aim_session_t *sess, + struct aim_snac_t *newsnac) { - struct aim_snac_t *snac = NULL, *cur = NULL; - + struct aim_snac_t *snac = NULL; + int index; + if (!newsnac) return 0; - cur = sess->outstanding_snacs; - - snac = calloc(1, sizeof(struct aim_snac_t)); - if (!snac) + if (!(snac = calloc(1, sizeof(struct aim_snac_t)))) return 0; memcpy(snac, newsnac, sizeof(struct aim_snac_t)); snac->issuetime = time(&snac->issuetime); snac->next = NULL; - - if (cur == NULL) { - sess->outstanding_snacs = snac; - return(snac->id); - } - while (cur->next != NULL) - cur = cur->next; - cur->next = snac; - printf("faim: snac: added %08lx\n", snac->id); + + index = snac->id % FAIM_SNAC_HASH_SIZE; + + faim_mutex_lock(&sess->snac_hash_locks[index]); + snac->next = sess->snac_hash[index]; + sess->snac_hash[index] = snac; + faim_mutex_unlock(&sess->snac_hash_locks[index]); + return(snac->id); } -struct aim_snac_t *aim_remsnac(struct aim_session_t *sess, - u_long id) +/* + * Finds a snac structure with the passed SNAC ID, + * removes it from the list/hash, and returns a pointer to it. + * + * The returned structure must be freed by the caller. + * + */ +faim_internal struct aim_snac_t *aim_remsnac(struct aim_session_t *sess, + u_long id) { - struct aim_snac_t *cur; - - if (cur == NULL) - return(NULL); - - printf("faim: snac: searching for %08lx to remove\n", id); - - cur = sess->outstanding_snacs; - - if (cur->id == id) { - sess->outstanding_snacs = cur->next; - return(cur); - } - while (cur->next != NULL) { - if (cur->next->id == id) { - struct aim_snac_t *tmp = NULL; - - tmp = cur->next; - cur->next = cur->next->next; - return(tmp); + struct aim_snac_t *cur = NULL; + int index; + + index = id % FAIM_SNAC_HASH_SIZE; + + faim_mutex_lock(&sess->snac_hash_locks[index]); + if (!sess->snac_hash[index]) + ; + else if (sess->snac_hash[index]->id == id) { + cur = sess->snac_hash[index]; + sess->snac_hash[index] = cur->next; + } else { + cur = sess->snac_hash[index]; + while (cur->next) { + if (cur->next->id == id) { + struct aim_snac_t *tmp; + + tmp = cur->next; + cur->next = cur->next->next; + cur = tmp; + break; + } + cur = cur->next; } - cur = cur->next; } - return(NULL); + faim_mutex_unlock(&sess->snac_hash_locks[index]); + + return cur; } /* * This is for cleaning up old SNACs that either don't get replies or * a reply was never received for. Garabage collection. Plain and simple. * - * maxage is the _minimum_ age in seconds to keep SNACs (though I don't know - * why its called _max_age). + * maxage is the _minimum_ age in seconds to keep SNACs. * */ -int aim_cleansnacs(struct aim_session_t *sess, - int maxage) +faim_internal int aim_cleansnacs(struct aim_session_t *sess, + int maxage) { - struct aim_snac_t *cur; - struct aim_snac_t *remed = NULL; - time_t curtime; - - cur = sess->outstanding_snacs; - - curtime = time(&curtime); - - while (cur) - { - if ( (cur) && (((cur->issuetime) + maxage) < curtime)) - { -#if 1/* DEBUG > 1*/ - printf("aimsnac: WARNING purged obsolete snac %08lx\n", cur->id); -#endif - remed = aim_remsnac(sess, cur->id); - if (remed) - { - if (remed->data) - free(remed->data); - free(remed); - } - } - cur = cur->next; + int i; + + for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { + struct aim_snac_t *cur = NULL, *next = NULL, *prev = NULL; + time_t curtime; + + faim_mutex_lock(&sess->snac_hash_locks[i]); + if (!sess->snac_hash[i]) { + faim_mutex_unlock(&sess->snac_hash_locks[i]); + continue; } - + + curtime = time(NULL); /* done here in case we waited for the lock */ + + cur = sess->snac_hash[i]; + while (cur) { + next = cur->next; + if ((curtime - cur->issuetime) > maxage) { + if (sess->snac_hash[i] == cur) + prev = sess->snac_hash[i] = next; + else + prev->next = next; + + /* XXX should we have destructors here? */ + if (cur->data) + free(cur->data); + free(cur); + + } else { + prev = cur; + } + cur = next; + } + + faim_mutex_unlock(&sess->snac_hash_locks[i]); + } + return 0; } -int aim_putsnac(u_char *buf, int family, int subtype, int flags, u_long snacid) +faim_internal int aim_putsnac(u_char *buf, int family, int subtype, int flags, u_long snacid) { int curbyte = 0; curbyte += aimutil_put16(buf+curbyte, (u_short)(family&0xffff));