changeset 13205:76c66b7e1327

[gaim-migrate @ 15568] fixing sametime to work with non-blocking writes. outpa is for you, Paco; may it bring you joy. committer: Tailor Script <tailor@pidgin.im>
author Christopher O'Brien <siege@pidgin.im>
date Thu, 09 Feb 2006 07:47:32 +0000
parents 307a259d6f6c
children 0c4db52c6a3d
files src/protocols/sametime/sametime.c
diffstat 1 files changed, 114 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/sametime/sametime.c	Thu Feb 09 05:10:47 2006 +0000
+++ b/src/protocols/sametime/sametime.c	Thu Feb 09 07:47:32 2006 +0000
@@ -41,6 +41,7 @@
 #include <conversation.h>
 #include <debug.h>
 #include <ft.h>
+#include <gaim_buffer.h>
 #include <imgstore.h>
 #include <mime.h>
 #include <notify.h>
@@ -224,6 +225,10 @@
 
   /** socket fd */
   int socket;
+  gint outpa;  /* like inpa, but the other way */
+
+  /** circular buffer for outgoing data */
+  GaimCircBuffer *sock_buf;
 
   GaimConnection *gc;
 };
@@ -337,10 +342,42 @@
 }
 
 
+static void write_cb(gpointer data, gint source, GaimInputCondition cond) {
+  struct mwGaimPluginData *pd = data;
+  GaimCircBuffer *circ = pd->sock_buf;
+  gsize avail;
+  int ret;
+
+  DEBUG_INFO("write_cb\n");
+
+  g_return_if_fail(circ != NULL);
+
+  avail = gaim_circ_buffer_get_max_read(circ);
+  if(BUF_LONG < avail) avail = BUF_LONG;
+
+  while(avail) {
+    ret = write(pd->socket, circ->outptr, avail);
+    
+    if(ret <= 0)
+      break;
+
+    gaim_circ_buffer_mark_read(circ, ret);
+    avail = gaim_circ_buffer_get_max_read(circ);
+    if(BUF_LONG < avail) avail = BUF_LONG;
+  }
+
+  if(! avail) {
+    gaim_input_remove(pd->outpa);
+    pd->outpa = 0;
+  }
+}
+
+
 static int mw_session_io_write(struct mwSession *session,
 			       const guchar *buf, gsize len) {
   struct mwGaimPluginData *pd;
   int ret = 0;
+  int err = 0;
 
   pd = mwSession_getClientData(session);
 
@@ -348,13 +385,33 @@
   if(pd->socket == 0)
     return 1;
 
+  if(pd->outpa) {
+    DEBUG_INFO("already pending INPUT_WRITE, buffering\n");
+    gaim_circ_buffer_append(pd->sock_buf, buf, len);
+    return 0;
+  }
+
   while(len) {
-    ret = write(pd->socket, buf, len);
-    if(ret <= 0) break;
+    ret = write(pd->socket, buf, (len > BUF_LEN)? BUF_LEN: len);
+    DEBUG_INFO("wrote %i bytes in one turn\n", ret);
+
+    if(ret <= 0)
+      break;
+
     len -= ret;
+    buf += ret;
   }
 
-  if(len > 0) {
+  if(ret <= 0)
+    err = errno;
+
+  if(err == EAGAIN) {
+    /* append remainder to circular buffer */
+    DEBUG_INFO("EAGAIN\n");
+    gaim_circ_buffer_append(pd->sock_buf, buf, len);
+    pd->outpa = gaim_input_add(pd->socket, GAIM_INPUT_WRITE, write_cb, pd);
+
+  } else if(len > 0) {
     DEBUG_ERROR("write returned %i, %i bytes left unwritten\n", ret, len);
     gaim_connection_error(pd->gc, _("Connection closed (writing)"));
 
@@ -379,11 +436,16 @@
 
   gc = pd->gc;
   
+  if(pd->outpa) {
+    gaim_input_remove(pd->outpa);
+    pd->outpa = 0;
+  }
+
   if(pd->socket) {
     close(pd->socket);
     pd->socket = 0;
   }
-    
+  
   if(gc->inpa) {
     gaim_input_remove(gc->inpa);
     gc->inpa = 0;
@@ -1567,19 +1629,12 @@
 
 /** callback triggered from gaim_input_add, watches the socked for
     available data to be processed by the session */
-static void read_cb(gpointer data, gint source,
-		    GaimInputCondition cond) {
-
+static void read_cb(gpointer data, gint source, GaimInputCondition cond) {
   struct mwGaimPluginData *pd = data;
   int ret = 0, err = 0;
 
-  /* How the heck can this happen? Fix submitted to Gaim so that it
-     won't happen anymore. */
-  if(! cond) return;
-
   g_return_if_fail(pd != NULL);
-  g_return_if_fail(cond & GAIM_INPUT_READ);
-
+ 
   ret = read_recv(pd->session, pd->socket);
 
   /* normal operation ends here */
@@ -1651,7 +1706,8 @@
   }
 
   pd->socket = source;
-  gc->inpa = gaim_input_add(source, GAIM_INPUT_READ, read_cb, pd);
+  gc->inpa = gaim_input_add(source, GAIM_INPUT_READ,
+			    read_cb, pd);
 
   mwSession_start(pd->session);
 }
@@ -3017,6 +3073,7 @@
   pd->srvc_resolve = mw_srvc_resolve_new(pd->session);
   pd->srvc_store = mw_srvc_store_new(pd->session);
   pd->group_list_map = g_hash_table_new(g_direct_hash, g_direct_equal);
+  pd->sock_buf = gaim_circ_buffer_new(0);
 
   mwSession_addService(pd->session, MW_SERVICE(pd->srvc_aware));
   mwSession_addService(pd->session, MW_SERVICE(pd->srvc_conf));
@@ -3063,6 +3120,7 @@
   mwSession_free(pd->session);
 
   g_hash_table_destroy(pd->group_list_map);
+  gaim_circ_buffer_destroy(pd->sock_buf);
 
   g_free(pd);
 }
@@ -3447,6 +3505,42 @@
 }
 
 
+#if 0
+static void blist_menu_announce(GaimBlistNode *node, gpointer data) {
+  GaimBuddy *buddy = (GaimBuddy *) node;
+  GaimAccount *acct;
+  GaimConnection *gc;
+  struct mwGaimPluginData *pd;
+  struct mwSession *session;
+  char *rcpt_name;
+  GList *rcpt;
+
+  g_return_if_fail(node != NULL);
+  g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
+
+  acct = buddy->account;
+  g_return_if_fail(acct != NULL);
+
+  gc = gaim_account_get_connection(acct);
+  g_return_if_fail(gc != NULL);
+
+  pd = gc->proto_data;
+  g_return_if_fail(pd != NULL);
+
+  rcpt_name = g_strdup_printf("@U %s", buddy->name);
+  rcpt = g_list_prepend(NULL, rcpt_name);
+
+  session = pd->session;
+  mwSession_sendAnnounce(session, FALSE,
+			 "This is a TEST announcement. Please ignore.",
+			 rcpt);
+
+  g_list_free(rcpt);
+  g_free(rcpt_name);
+}
+#endif
+
+
 static GList *mw_prpl_blist_node_menu(GaimBlistNode *node) {
   GList *l = NULL;
   GaimMenuAction *act;
@@ -3460,6 +3554,12 @@
                              GAIM_CALLBACK(blist_menu_conf), NULL, NULL);
   l = g_list_append(l, act);
 
+#if 0
+  act = gaim_menu_action_new(_("Send TEST Announcement"),
+			     GAIM_CALLBACK(blist_menu_announce), NULL, NULL);
+  l = g_list_append(l, act);
+#endif
+
   /** note: this never gets called for a GaimGroup, have to use the
       blist-node-extended-menu signal for that. The function
       blist_node_menu_cb is assigned to this signal in the function