No release numbers
------------------
+ - Thu Aug 17 22:53:03 UTC 2000
+ - Change the SNAC cache to a hash instead of list
+ - Fixed a few leaks relating to aim_gettlv_str()
+
- Thu Aug 17 14:04:18 UTC 2000
- Fix the fd closing bug introduced last week
*/
void aim_connrst(struct aim_session_t *sess)
{
- faim_mutex_init(&sess->connlistlock, NULL);
+ faim_mutex_init(&sess->connlistlock);
if (sess->connlist) {
struct aim_conn_t *cur = sess->connlist, *tmp;
deadconn->forcedlatency = 0;
deadconn->handlerlist = NULL;
deadconn->priv = NULL;
- faim_mutex_init(&deadconn->active, NULL);
- faim_mutex_init(&deadconn->seqnum_lock, NULL);
+ faim_mutex_init(&deadconn->active);
+ faim_mutex_init(&deadconn->seqnum_lock);
return;
}
sess->queue_outgoing = NULL;
sess->queue_incoming = NULL;
sess->pendingjoin = NULL;
- sess->outstanding_snacs = NULL;
+ aim_initsnachash(sess);
sess->snac_nextid = 0x00000001;
/*
* No matter what, we should have a screen name.
*/
sn = aim_gettlv_str(tlvlist, 0x0001, 1);
- memcpy(sess->logininfo.screen_name, sn, strlen(sn));
- sn[(strlen(sn))] = '\0';
-
+ strncpy(sess->logininfo.screen_name, sn, strlen(sn));
+ free(sn);
+
/*
* Check for an error code. If so, we should also
* have an error url.
int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
{
rxcallback_t userfunc = NULL;
- int i = 10; /* skip SNAC */
int ret = 1;
unsigned long newrate;
/*
* TLVs follow
*/
- tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
-
- msg = aim_gettlv_str(tlvlist, 0x000b, 1);
+ if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
+ return ret;
+
+ if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
+ aim_freetlvchain(&tlvlist);
+ return ret;
+ }
userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
if (userfunc)
ret = userfunc(sess, command, id, msg);
aim_freetlvchain(&tlvlist);
+ free(msg);
- return ret;
-
+ return ret;
}
int aim_handleredirect_middle(struct aim_session_t *sess,
if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1)))
{
printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
+ free(ip);
aim_freetlvchain(&tlvlist);
return ret;
}
if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
{
printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
+ free(ip);
aim_freetlvchain(&tlvlist);
return ret;
}
ret = userfunc(sess, command, serviceid, ip, cookie);
}
- /*
- * XXX: Is there a leak here? Where does IP get freed?
- */
+ free(ip);
aim_freetlvchain(&tlvlist);
return ret;
*
* 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 <faim/aim.h>
+/*
+ * Called from aim_session_init() to initialize the hash.
+ */
+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.
+ */
u_long aim_newsnac(struct aim_session_t *sess,
struct aim_snac_t *newsnac)
{
struct aim_snac_t *snac = NULL, *cur = NULL;
-
+ int index;
+
if (!newsnac)
return 0;
- cur = sess->outstanding_snacs;
-
snac = calloc(1, sizeof(struct aim_snac_t));
if (!snac)
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);
+
+ index = snac->id % FAIM_SNAC_HASH_SIZE;
+
+ faim_mutex_lock(&sess->snac_hash_locks[index]);
+ if (!sess->snac_hash[index])
+ sess->snac_hash[index] = snac;
+ else {
+ snac->next = sess->snac_hash[index];
+ sess->snac_hash[index] = snac;
}
- while (cur->next != NULL)
- cur = cur->next;
- cur->next = snac;
+ faim_mutex_unlock(&sess->snac_hash_locks[index]);
return(snac->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.
+ *
+ */
struct aim_snac_t *aim_remsnac(struct aim_session_t *sess,
u_long id)
{
struct aim_snac_t *cur;
+ int index;
- cur = sess->outstanding_snacs;
+ index = id % FAIM_SNAC_HASH_SIZE;
- if (cur == NULL)
- return(NULL);
-
- 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);
+ faim_mutex_lock(&sess->snac_hash_locks[index]);
+ if (!sess->snac_hash[index])
+ ;
+ else if (!sess->snac_hash[index]->next) {
+ if (sess->snac_hash[index]->id == id) {
+ cur = sess->snac_hash[index];
+ sess->snac_hash[index] = NULL;
+ }
+ } 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,
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 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);
- }
+ int i;
+
+ for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
+ faim_mutex_lock(&sess->snac_hash_locks[i]);
+ if (!sess->snac_hash[i])
+ ;
+ else if (!sess->snac_hash[i]->next) {
+ if ((sess->snac_hash[i]->issuetime + maxage) >= curtime) {
+ remed = sess->snac_hash[i];
+ if(remed->data)
+ free(remed->data);
+ free(remed);
+ sess->snac_hash[i] = NULL;
+ }
+ } else {
+ cur = sess->snac_hash[i];
+ while(cur && cur->next) {
+ if ((cur->next->issuetime + maxage) >= curtime) {
+ remed = cur->next;
+ cur->next = cur->next->next;
+ if (remed->data)
+ free(remed->data);
+ free(remed);
}
- cur = cur->next;
+ cur = cur->next;
+ }
}
-
+ faim_mutex_unlock(&sess->snac_hash_locks[i]);
+ }
+
return 0;
}
#ifdef FAIM_USEPTHREADS
#include <pthread.h>
#define faim_mutex_t pthread_mutex_t
-#define faim_mutex_init pthread_mutex_init
-#define faim_mutex_lock pthread_mutex_lock
-#define faim_mutex_unlock pthread_mutex_unlock
-#define faim_mutex_destroy pthread_mutex_destroy
+#define faim_mutex_init(x) pthread_mutex_init(x, NULL)
+#define faim_mutex_lock(x) pthread_mutex_lock(x)
+#define faim_mutex_unlock(x) pthread_mutex_unlock(x)
+#define faim_mutex_destroy(x) pthread_mutex_destroy(x)
#elif defined(FAIM_USEFAKELOCKS)
/*
* For platforms without pthreads, we also assume
* Outstanding snac handling
*
* XXX: Should these be per-connection? -mid
- **/
- struct aim_snac_t *outstanding_snacs;
+ */
+ struct aim_snac_t *snac_hash[FAIM_SNAC_HASH_SIZE];
+ faim_mutex_t snac_hash_locks[FAIM_SNAC_HASH_SIZE];
u_long snac_nextid;
struct aim_msgcookie_t *msgcookies;
time_t issuetime;
struct aim_snac_t *next;
};
+void aim_initsnachash(struct aim_session_t *sess);
u_long aim_newsnac(struct aim_session_t *, struct aim_snac_t *newsnac);
struct aim_snac_t *aim_remsnac(struct aim_session_t *, u_long id);
int aim_cleansnacs(struct aim_session_t *, int maxage);
int aim_parse_last_bad(struct aim_session_t *, struct command_rx_struct *, ...);
int aim_parse_generalerrs(struct aim_session_t *, struct command_rx_struct *command, ...);
int aim_parsemotd_middle(struct aim_session_t *sess, struct command_rx_struct *command, ...);
+int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command);
+int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command);
/* aim_im.c */
struct aim_directim_priv {
#define FAIM_USEFAKELOCKS
#endif
+/*
+ * Size of the SNAC caching hash.
+ *
+ * Default: 16
+ *
+ */
+#define FAIM_SNAC_HASH_SIZE 16
+
#endif /* __FAIMCONFIG_H__ */