]> andersk Git - libfaim.git/blobdiff - aim_snac.c
- Wed Dec 13 02:26:39 UTC 2000
[libfaim.git] / aim_snac.c
index 1d2c4fb3f702025fa946f0e290d1c4c8c5218b22..ae46e47ed28b1af41fb51206c4439ca5ff611774 100644 (file)
  *
  * 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>
 
-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)
 {
-  struct aim_snac_t *snac = NULL, *cur = NULL;
-  
+  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;
+
+  snac.data = malloc(datalen);
+  memcpy(snac.data, data, datalen);
+
+  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;
 
-  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;
+
+  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);
-
-  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 DEBUG > 1
-         printf("aimsnac: WARNING purged obsolete snac %ul\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));
This page took 0.039582 seconds and 4 git commands to generate.