3 * Various SNAC-related dodads...
5 * outstanding_snacs is a list of aim_snac_t structs. A SNAC should be added
6 * whenever a new SNAC is sent and it should remain in the list until the
7 * response for it has been receieved.
9 * cleansnacs() should be called periodically by the client in order
10 * to facilitate the aging out of unreplied-to SNACs. This can and does
11 * happen, so it should be handled.
19 * Called from aim_session_init() to initialize the hash.
21 faim_internal void aim_initsnachash(aim_session_t *sess)
25 for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
26 sess->snac_hash[i] = NULL;
27 faim_mutex_init(&sess->snac_hash_locks[i]);
33 faim_internal aim_snacid_t aim_cachesnac(aim_session_t *sess, const fu16_t family, const fu16_t type, const fu16_t flags, const void *data, const int datalen)
37 snac.id = sess->snacid_next++;
43 if (!(snac.data = malloc(datalen)))
45 memcpy(snac.data, data, datalen);
49 return aim_newsnac(sess, &snac);
53 * Clones the passed snac structure and caches it in the
56 faim_internal aim_snacid_t aim_newsnac(aim_session_t *sess, aim_snac_t *newsnac)
64 if (!(snac = malloc(sizeof(aim_snac_t))))
66 memcpy(snac, newsnac, sizeof(aim_snac_t));
67 snac->issuetime = time(NULL);
69 index = snac->id % FAIM_SNAC_HASH_SIZE;
71 faim_mutex_lock(&sess->snac_hash_locks[index]);
72 snac->next = (aim_snac_t *)sess->snac_hash[index];
73 sess->snac_hash[index] = (void *)snac;
74 faim_mutex_unlock(&sess->snac_hash_locks[index]);
80 * Finds a snac structure with the passed SNAC ID,
81 * removes it from the list/hash, and returns a pointer to it.
83 * The returned structure must be freed by the caller.
86 faim_internal aim_snac_t *aim_remsnac(aim_session_t *sess, aim_snacid_t id)
88 aim_snac_t *cur, **prev;
91 index = id % FAIM_SNAC_HASH_SIZE;
93 faim_mutex_lock(&sess->snac_hash_locks[index]);
94 for (prev = (aim_snac_t **)&sess->snac_hash[index]; (cur = *prev); ) {
101 faim_mutex_unlock(&sess->snac_hash_locks[index]);
107 * This is for cleaning up old SNACs that either don't get replies or
108 * a reply was never received for. Garabage collection. Plain and simple.
110 * maxage is the _minimum_ age in seconds to keep SNACs.
113 faim_internal void aim_cleansnacs(aim_session_t *sess, int maxage)
117 for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
118 aim_snac_t *cur, **prev;
121 faim_mutex_lock(&sess->snac_hash_locks[i]);
122 if (!sess->snac_hash[i]) {
123 faim_mutex_unlock(&sess->snac_hash_locks[i]);
127 curtime = time(NULL); /* done here in case we waited for the lock */
129 for (prev = (aim_snac_t **)&sess->snac_hash[i]; (cur = *prev); ) {
130 if ((curtime - cur->issuetime) > maxage) {
134 /* XXX should we have destructors here? */
141 faim_mutex_unlock(&sess->snac_hash_locks[i]);
147 faim_internal int aim_putsnac(aim_bstream_t *bs, fu16_t family, fu16_t subtype, fu16_t flags, aim_snacid_t snacid)
150 aimbs_put16(bs, family);
151 aimbs_put16(bs, subtype);
152 aimbs_put16(bs, flags);
153 aimbs_put32(bs, snacid);