]> andersk Git - libfaim.git/blobdiff - aim_conn.c
- Thu Dec 14 03:39:34 UTC 2000
[libfaim.git] / aim_conn.c
index 5009627a0634b87457165d686e75160dba7df849..836c0d442652e9ab70485632c29b239fbc4eafa5 100644 (file)
@@ -38,6 +38,32 @@ faim_internal void aim_connrst(struct aim_session_t *sess)
   return;
 }
 
+/**
+ * aim_conn_init - Reset a connection to default values.
+ * @deadconn: Connection to be reset
+ *
+ * Initializes and/or resets a connection structure.
+ *
+ */
+static void aim_conn_init(struct aim_conn_t *deadconn)
+{
+  if (!deadconn)
+    return;
+
+  deadconn->fd = -1;
+  deadconn->subtype = -1;
+  deadconn->type = -1;
+  deadconn->seqnum = 0;
+  deadconn->lastactivity = 0;
+  deadconn->forcedlatency = 0;
+  deadconn->handlerlist = NULL;
+  deadconn->priv = NULL;
+  faim_mutex_init(&deadconn->active);
+  faim_mutex_init(&deadconn->seqnum_lock);
+  
+  return;
+}
+
 /**
  * aim_conn_getnext - Gets a new connection structure.
  * @sess: Session
@@ -53,7 +79,7 @@ faim_internal struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess)
     return NULL;
 
   memset(newconn, 0, sizeof(struct aim_conn_t));
-  aim_conn_close(newconn);
+  aim_conn_init(newconn);
   newconn->next = NULL;
 
   faim_mutex_lock(&sess->connlistlock);
@@ -69,32 +95,6 @@ faim_internal struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess)
   return newconn;
 }
 
-/**
- * aim_conn_init - Reset a connection to default values.
- * @deadconn: Connection to be reset
- *
- * Initializes and/or resets a connection structure.
- *
- */
-static void aim_conn_init(struct aim_conn_t *deadconn)
-{
-  if (!deadconn)
-    return;
-
-  deadconn->fd = -1;
-  deadconn->subtype = -1;
-  deadconn->type = -1;
-  deadconn->seqnum = 0;
-  deadconn->lastactivity = 0;
-  deadconn->forcedlatency = 0;
-  deadconn->handlerlist = NULL;
-  deadconn->priv = NULL;
-  faim_mutex_init(&deadconn->active);
-  faim_mutex_init(&deadconn->seqnum_lock);
-  
-  return;
-}
-
 /**
  * aim_conn_kill - Close and free a connection.
  * @sess: Session for the connection
@@ -131,7 +131,8 @@ faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **d
   /* XXX: do we need this for txqueue too? */
   aim_rxqueue_cleanbyconn(sess, *deadconn);
 
-  aim_conn_close(*deadconn);
+  if ((*deadconn)->fd != -1) 
+    aim_conn_close(*deadconn);
   if ((*deadconn)->priv)
     free((*deadconn)->priv);
   free(*deadconn);
@@ -146,34 +147,22 @@ faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **d
  *
  * Close (but not free) a connection.
  *
+ * This leaves everything untouched except for clearing the 
+ * handler list and setting the fd to -1 (used to recognize
+ * dead connections).
+ *
  */
 faim_export void aim_conn_close(struct aim_conn_t *deadconn)
 {
-  int typesav = -1, subtypesav = -1;
-  void *privsav = NULL;
 
   faim_mutex_destroy(&deadconn->active);
   faim_mutex_destroy(&deadconn->seqnum_lock);
   if (deadconn->fd >= 3)
     close(deadconn->fd);
+  deadconn->fd = -1;
   if (deadconn->handlerlist)
     aim_clearhandlers(deadconn);
 
-  typesav = deadconn->type;
-  subtypesav = deadconn->subtype;
-
-  if (deadconn->priv && (deadconn->type != AIM_CONN_TYPE_RENDEZVOUS)) {
-    free(deadconn->priv);
-    deadconn->priv = NULL;
-  }
-  privsav = deadconn->priv;
-
-  aim_conn_init(deadconn);
-
-  deadconn->type = typesav;
-  deadconn->subtype = subtypesav;
-  deadconn->priv = privsav;
-
   return;
 }
 
@@ -194,7 +183,7 @@ faim_internal struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess,
 
   faim_mutex_lock(&sess->connlistlock);
   for (cur = sess->connlist; cur; cur = cur->next) {
-    if (cur->type == type)
+    if ((cur->type == type) && !(cur->status & AIM_CONN_STATUS_INPROGRESS))
       break;
   }
   faim_mutex_unlock(&sess->connlistlock);
@@ -344,13 +333,24 @@ static int aim_proxyconnect(struct aim_session_t *sess,
       return -1;
     }
 
-    memset(&sa.sin_zero, 0, 8);
+    memset(&sa, 0, sizeof(struct sockaddr_in));
     sa.sin_port = htons(port);
     memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
     sa.sin_family = hp->h_addrtype;
   
     fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
+
+    if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT)
+      fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */
+
     if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
+      if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) {
+       if ((errno == EINPROGRESS) || (errno == EINTR)) {
+         if (statusret)
+           *statusret |= AIM_CONN_STATUS_INPROGRESS;
+         return fd;
+       }
+      }
       close(fd);
       fd = -1;
     }
@@ -518,9 +518,9 @@ faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess,
                                          struct timeval *timeout, int *status)
 {
   struct aim_conn_t *cur;
-  fd_set fds;
+  fd_set fds, wfds;
   int maxfd = 0;
-  int i;
+  int i, haveconnecting = 0;
 
   faim_mutex_lock(&sess->connlistlock);
   if (sess->connlist == NULL) {
@@ -530,32 +530,55 @@ faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess,
   }
   faim_mutex_unlock(&sess->connlistlock);
 
-  /* 
-   * If we have data waiting to be sent, return immediatly
-   */
-  if (sess->queue_outgoing != NULL) {
-    *status = 1;
-    return NULL;
-  } 
-
   FD_ZERO(&fds);
+  FD_ZERO(&wfds);
   maxfd = 0;
 
   faim_mutex_lock(&sess->connlistlock);
   for (cur = sess->connlist; cur; cur = cur->next) {
+    if (cur->fd == -1) {
+      /* don't let invalid/dead connections sit around */
+      *status = 2;
+      faim_mutex_unlock(&sess->connlistlock);
+      return cur;
+    } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
+      FD_SET(cur->fd, &wfds);
+      haveconnecting++;
+    }
     FD_SET(cur->fd, &fds);
     if (cur->fd > maxfd)
       maxfd = cur->fd;
   }
   faim_mutex_unlock(&sess->connlistlock);
 
-  if ((i = select(maxfd+1, &fds, NULL, NULL, timeout))>=1) {
+  /* 
+   * If we have data waiting to be sent, return
+   *
+   * We have to not do this if theres at least one
+   * connection thats still connecting, since that connection
+   * may have queued data and this return would prevent
+   * the connection from ever completing!  This is a major
+   * inadequacy of the libfaim way of doing things.  It means
+   * that nothing can transmit as long as there's connecting
+   * sockets. Evil.
+   *
+   * But its still better than having blocking connects.
+   *
+   */
+  if (!haveconnecting && (sess->queue_outgoing != NULL)) {
+    *status = 1;
+    return NULL;
+  } 
+
+  if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) {
     faim_mutex_lock(&sess->connlistlock);
     for (cur = sess->connlist; cur; cur = cur->next) {
-      if (FD_ISSET(cur->fd, &fds)) {
+      if ((FD_ISSET(cur->fd, &fds)) || 
+         ((cur->status & AIM_CONN_STATUS_INPROGRESS) && 
+          FD_ISSET(cur->fd, &wfds))) {
        *status = 2;
        faim_mutex_unlock(&sess->connlistlock);
-       return cur;
+       return cur; /* XXX race condition here -- shouldnt unlock connlist */
       }
     }
     *status = 0; /* shouldn't happen */
@@ -593,6 +616,8 @@ faim_export int aim_conn_isready(struct aim_conn_t *conn)
  * @newstatus is %XOR'd with the previous value of the connection
  * status and returned.  Returns -1 if the connection is invalid.
  *
+ * This isn't real useful.
+ *
  */
 faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status)
 {
@@ -669,11 +694,12 @@ faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *
 /**
  * aim_session_init - Initializes a session structure
  * @sess: Session to initialize
+ * @flags: Flags to use. Any of %AIM_SESS_FLAGS %OR'd together.
  *
  * Sets up the initial values for a session.
  *
  */
-faim_export void aim_session_init(struct aim_session_t *sess)
+faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flags)
 {
   if (!sess)
     return;
@@ -683,9 +709,20 @@ faim_export void aim_session_init(struct aim_session_t *sess)
   sess->queue_outgoing = NULL;
   sess->queue_incoming = NULL;
   sess->pendingjoin = NULL;
+  sess->pendingjoinexchange = 0;
   aim_initsnachash(sess);
+  sess->msgcookies = NULL;
   sess->snac_nextid = 0x00000001;
 
+  sess->flags = 0;
+
+  /*
+   * Default to SNAC login unless XORLOGIN is explicitly set.
+   */
+  if (!(flags & AIM_SESS_FLAGS_XORLOGIN))
+    sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
+  sess->flags |= flags;
+
   /*
    * This must always be set.  Default to the queue-based
    * version for back-compatibility.  
@@ -694,3 +731,75 @@ faim_export void aim_session_init(struct aim_session_t *sess)
 
   return;
 }
+
+/**
+ * aim_conn_isconnecting - Determine if a connection is connecting
+ * @conn: Connection to examine
+ *
+ * Returns nonzero if the connection is in the process of
+ * connecting (or if it just completed and aim_conn_completeconnect()
+ * has yet to be called on it).
+ *
+ */
+faim_export int aim_conn_isconnecting(struct aim_conn_t *conn)
+{
+  if (!conn)
+    return 0;
+  return (conn->status & AIM_CONN_STATUS_INPROGRESS)?1:0;
+}
+
+faim_export int aim_conn_completeconnect(struct aim_session_t *sess, struct aim_conn_t *conn)
+{
+  fd_set fds, wfds;
+  struct timeval tv;
+  int res, error = ETIMEDOUT;
+  rxcallback_t userfunc;
+
+  if (!conn || (conn->fd == -1))
+    return -1;
+
+  if (!(conn->status & AIM_CONN_STATUS_INPROGRESS))
+    return -1;
+
+  FD_ZERO(&fds);
+  FD_SET(conn->fd, &fds);
+  FD_ZERO(&wfds);
+  FD_SET(conn->fd, &wfds);
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) {
+    error = errno;
+    aim_conn_close(conn);
+    errno = error;
+    return -1;
+  } else if (res == 0) {
+    printf("faim: aim_conn_completeconnect: false alarm on %d\n", conn->fd);
+    return 0; /* hasn't really completed yet... */
+  } 
+
+  if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) {
+    int len = sizeof(error);
+
+    if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+      error = errno;
+  }
+
+  if (error) {
+    aim_conn_close(conn);
+    errno = error;
+    return -1;
+  }
+
+  fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */
+
+  conn->status &= ~AIM_CONN_STATUS_INPROGRESS;
+
+  if ((userfunc = aim_callhandler(conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE)))
+    userfunc(sess, NULL, conn);
+
+  /* Flush out the queues if there was something waiting for this conn  */
+  aim_tx_flushqueue(sess);
+
+  return 0;
+}
This page took 0.0458 seconds and 4 git commands to generate.