view libfaim/aim_rxqueue.c @ 312:3069be4c291e

[gaim-migrate @ 322] I don't know why I did this. I have homework due in 15 hours that I haven't started yet, and it's in a language I don't know and it's a project I don't understand. If my teacher knew about this, he would be pissed. He looks pissed all the time, even when he's not. When he smiles he looks devilish. Maybe I only think that because literally half the class flunked the midterm. I am not joking about that. More people got F's than A, B, and C combined. It's 2 am and the homework's due at 5 tomorrow so what do I do? Get chat to work. Wow. That's going to look good on my resume. "Why did you flunk this class?" "Because I was getting chat in Instant Messenger to work." Not that that's not something to be proud of, but I wonder which is more important to employers. The big battle, experience versus education. Just because you got good grades in college doesn't mean you're smarter than someone who flunked, it just means you put in the effort necessary to get a better grade and the other person didn't. Maybe the person who flunked was working on real honest-to-god actually *used* software, as opposed to some stupid tree that only gets used for a fringe branch of computer science that doesn't offer much more than a normal heap or binary search tree offers. Maybe the person was out there reverse-engineering protocols and allowing cross- platform communication to occur, creating interoperability and causing a greater demand not only for the product, but for the platform it runs on! Given the choices, who would you pick? Someone who was told how to code a tree and managed to get it to work, or someone who increases your userbase and marketability? Enough of my rant for a while. I've had waaaaay too much sugar (gummy candy is deadly). committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 02 Jun 2000 09:11:48 +0000
parents 0f14e6d8a51b
children 9d258a0aa560
line wrap: on
line source

/*
 *  aim_rxqueue.c
 *
 * This file contains the management routines for the receive
 * (incoming packet) queue.  The actual packet handlers are in
 * aim_rxhandlers.c.
 */

#include <faim/aim.h> 

/*
 * Grab a single command sequence off the socket, and enqueue
 * it in the incoming event queue in a seperate struct.
 */
int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
{
  u_char generic[6]; 
  struct command_rx_struct *newrx = NULL;

  if (!sess || !conn)
    return 0;

  if (conn->fd < 3)  /* can happen when people abuse the interface */
    return 0;

  /*
   * Read FLAP header.  Six bytes:
   *    
   *   0 char  -- Always 0x2a
   *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
   *   2 short -- Sequence number 
   *   4 short -- Number of data bytes that follow.
   */
  faim_mutex_lock(&conn->active);
  if (read(conn->fd, generic, 6) < 6){
    aim_conn_close(conn);
    faim_mutex_unlock(&conn->active);
    return -1;
  }
  faim_mutex_unlock(&conn->active);

  /*
   * This shouldn't happen unless the socket breaks, the server breaks,
   * or we break.  We must handle it just in case.
   */
  if (generic[0] != 0x2a) {
    faimdprintf(1, "Bad incoming data!");
    return -1;
  }	

  /* allocate a new struct */
  newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct));
  if (!newrx)
    return -1;
  memset(newrx, 0x00, sizeof(struct command_rx_struct));

  newrx->lock = 1;  /* lock the struct */

  /* store channel -- byte 2 */
  newrx->type = (char) generic[1];

  /* store seqnum -- bytes 3 and 4 */
  newrx->seqnum = aimutil_get16(generic+2);

  /* store commandlen -- bytes 5 and 6 */
  newrx->commandlen = aimutil_get16(generic+4);

  newrx->nofree = 0; /* free by default */

  /* malloc for data portion */
  newrx->data = (u_char *) malloc(newrx->commandlen);
  if (!newrx->data) {
    free(newrx);
    return -1;
  }

  /* read the data portion of the packet */
  faim_mutex_lock(&conn->active);
  if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
    free(newrx->data);
    free(newrx);
    aim_conn_close(conn);
    faim_mutex_unlock(&conn->active);
    return -1;
  }
  faim_mutex_unlock(&conn->active);

  newrx->conn = conn;

  newrx->next = NULL;  /* this will always be at the bottom */
  newrx->lock = 0; /* unlock */

  /* enqueue this packet */
  if (sess->queue_incoming == NULL) {
    sess->queue_incoming = newrx;
  } else {
    struct command_rx_struct *cur;

    /*
     * This append operation takes a while.  It might be faster
     * if we maintain a pointer to the last entry in the queue
     * and just update that.  Need to determine if the overhead
     * to maintain that is lower than the overhead for this loop.
     */
    for (cur = sess->queue_incoming; cur->next; cur = cur->next)
      ;
    cur->next = newrx;
  }
  
  newrx->conn->lastactivity = time(NULL);

  return 0;  
}

/*
 * Purge recieve queue of all handled commands (->handled==1).  Also
 * allows for selective freeing using ->nofree so that the client can
 * keep the data for various purposes.  
 *
 * If ->nofree is nonzero, the frame will be delinked from the global list, 
 * but will not be free'ed.  The client _must_ keep a pointer to the
 * data -- libfaim will not!  If the client marks ->nofree but
 * does not keep a pointer, it's lost forever.
 *
 */
void aim_purge_rxqueue(struct aim_session_t *sess)
{
  struct command_rx_struct *cur = NULL;
  struct command_rx_struct *tmp;

  if (sess->queue_incoming == NULL)
    return;
  
  if (sess->queue_incoming->next == NULL) {
    if (sess->queue_incoming->handled) {
      tmp = sess->queue_incoming;
      sess->queue_incoming = NULL;

      if (!tmp->nofree) {
	free(tmp->data);
	free(tmp);
      } else
	tmp->next = NULL;
    }
    return;
  }

  for(cur = sess->queue_incoming; cur->next != NULL; ) {
    if (cur->next->handled) {
      tmp = cur->next;
      cur->next = tmp->next;
      if (!tmp->nofree) {
	free(tmp->data);
	free(tmp);
      } else
	tmp->next = NULL;
    }	
    cur = cur->next;

    /* 
     * Be careful here.  Because of the way we just
     * manipulated the pointer, cur may be NULL and 
     * the for() will segfault doing the check unless
     * we find this case first.
     */
    if (cur == NULL)	
      break;
  }

  return;
}