diff libfaim/snac.c @ 1535:1e2cc8c8bf3c

[gaim-migrate @ 1545] libfaim updates. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Mon, 05 Mar 2001 03:59:32 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfaim/snac.c	Mon Mar 05 03:59:32 2001 +0000
@@ -0,0 +1,177 @@
+/*
+ *
+ * Various SNAC-related dodads... 
+ *
+ * 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.  
+ *
+ * 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.
+ *
+ */
+
+#define FAIM_INTERNAL
+#include <aim.h>
+
+/*
+ * 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;
+}
+
+faim_internal unsigned long aim_cachesnac(struct aim_session_t *sess,
+					  const unsigned short family,
+					  const unsigned short type,
+					  const unsigned short flags,
+					  const void *data, const int datalen)
+{
+  struct aim_snac_t snac;
+
+  snac.id = sess->snac_nextid++;
+  snac.family = family;
+  snac.type = type;
+  snac.flags = flags;
+
+  if (datalen) {
+    if (!(snac.data = malloc(datalen)))
+      return 0; /* er... */
+    memcpy(snac.data, data, datalen);
+  } else
+    snac.data = NULL;
+
+  return aim_newsnac(sess, &snac);
+}
+
+/*
+ * 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;
+  int index;
+
+  if (!newsnac)
+    return 0;
+
+  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;
+
+  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);
+}
+
+/*
+ * 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 = 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;
+    }
+  }
+  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.
+ *
+ */
+faim_internal int aim_cleansnacs(struct aim_session_t *sess,
+				 int maxage)
+{
+  int i;
+
+  for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
+    struct aim_snac_t *cur, **prev;
+    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 */
+
+    for (prev = &sess->snac_hash[i]; (cur = *prev); ) {
+      if ((curtime - cur->issuetime) > maxage) {
+
+	*prev = cur->next;
+
+	/* XXX should we have destructors here? */
+	if (cur->data)
+	  free(cur->data);
+	free(cur);
+
+      } else
+	prev = &cur->next;
+    }
+
+    faim_mutex_unlock(&sess->snac_hash_locks[i]);
+  }
+
+  return 0;
+}
+
+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));
+  curbyte += aimutil_put16(buf+curbyte, (u_short)(subtype&0xffff));
+  curbyte += aimutil_put16(buf+curbyte, (u_short)(flags&0xffff));
+  curbyte += aimutil_put32(buf+curbyte, snacid);
+  return curbyte;
+}