changeset 11194:4c1f45ac00e9

[gaim-migrate @ 13317] - added retries for UDP transport - added keep alive for UDP to stay in NAT tables - unregistering contact on logout - start of argument unification (struct simple_account_data *sip, ...) committer: Tailor Script <tailor@pidgin.im>
author Thomas Butter <tbutter>
date Sat, 06 Aug 2005 12:25:15 +0000
parents e865bdbbf91d
children 3aeb85cc9cda
files src/protocols/simple/simple.c src/protocols/simple/simple.h
diffstat 2 files changed, 80 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/simple/simple.c	Sat Aug 06 04:05:09 2005 +0000
+++ b/src/protocols/simple/simple.c	Sat Aug 06 12:25:15 2005 +0000
@@ -68,7 +68,14 @@
 }
 
 static void simple_keep_alive(GaimConnection *gc) {
-	return; // need it?
+	struct simple_account_data *sip = gc->proto_data;
+	if(sip->udp) { // in case of UDP send a packet only with a 0 byte to
+			// stay in the NAT table
+		gchar buf[2]={0,0};
+		gaim_debug_info("simple", "sending keep alive\n");
+		sendto(sip->fd, buf, 1, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in));
+	}
+	return; 
 }
 
 static gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc);
@@ -300,6 +307,28 @@
 	return ret;
 }
 
+static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) {
+	gchar *oldstr;
+	gchar *outstr = g_strdup_printf("%s %s SIP/2.0\r\n", msg->method, msg->target);
+	gchar *name;
+	gchar *value;
+	GSList *tmp = msg->headers;
+	while(tmp) {
+		oldstr = outstr;
+                name = ((struct siphdrelement*)(tmp->data))->name;
+                value = ((struct siphdrelement*)(tmp->data))->value;
+                outstr = g_strdup_printf("%s%s: %s\r\n",oldstr, name, value);
+		g_free(oldstr);
+		tmp = g_slist_next(tmp);
+	}
+	oldstr = outstr;
+	if(msg->body) outstr = g_strdup_printf("%s\r\n%s", outstr, msg->body);
+	else outstr = g_strdup_printf("%s\r\n", outstr);
+	g_free(oldstr);
+	sendout_pkt(sip->gc, outstr);
+        g_free(outstr);
+}
+
 static void send_sip_response(GaimConnection *gc, struct sipmsg *msg, int code, char *text, char *body) {
 	GSList *tmp = msg->headers;
 	char *oldstr;
@@ -322,6 +351,12 @@
 	g_free(outstr);
 }
 
+static void transactions_remove(struct simple_account_data *sip, struct transaction *trans) {
+	if(trans->msg) sipmsg_free(trans->msg);
+	sip->transactions = g_slist_remove(sip->transactions, trans);
+	g_free(trans);
+}
+
 static void transactions_add_buf(struct simple_account_data *sip, gchar *buf, void *callback) {
 	struct transaction *trans = g_new0(struct transaction, 1);
 	trans->time = time(NULL);
@@ -418,24 +453,31 @@
 	g_free(buf);
 }
 
-static void do_register(GaimConnection *gc) {
-        struct simple_account_data *sip = gc->proto_data;
+static void do_register_exp(struct simple_account_data *sip, int expire) {
 	sip->registerstatus = 1;
 	
 	char *uri = g_strdup_printf("sip:%s",sip->servername);
 	char *to = g_strdup_printf("sip:%s@%s",sip->username,sip->servername);
-	char *contact = g_strdup_printf("Contact: <sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: 900\r\n", sip->username, sip->ip, sip->listenport, sip->udp ? "udp" : "tcp");
+	char *contact = g_strdup_printf("Contact: <sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: %d\r\n", sip->username, sip->ip, sip->listenport, sip->udp ? "udp" : "tcp", expire);
 	
 	// allow one auth try per register
 	sip->proxy.fouroseven = 0;
 	sip->registrar.fouroseven = 0;
 	
-	sip->reregister = time(NULL) + 540;
-	send_sip_request(gc,"REGISTER",uri,to, contact, "", NULL, process_register_response);
+	if(expire) {
+		sip->reregister = time(NULL) + expire - 50;
+	} else {
+		sip->reregister = time(NULL) + 600;
+	}
+	send_sip_request(sip->gc,"REGISTER",uri,to, contact, "", NULL, process_register_response);
 	g_free(uri);
 	g_free(to);
 }
 
+static void do_register(struct simple_account_data *sip) {
+	do_register_exp(sip, sip->registerexpire);
+}
+
 static gchar *parse_from(gchar *hdr) {
 	gchar *from = hdr;
 	gchar *tmp;
@@ -505,12 +547,31 @@
 	}
 }
 
+static gboolean resend_timeout(struct simple_account_data *sip) {
+	GSList *tmp = sip->transactions;
+	time_t currtime = time(NULL);
+	while(tmp) {
+		struct transaction *trans = tmp->data;
+		tmp = tmp->next;
+		gaim_debug_info("simple", "have open transaction age: %d\n", currtime- trans->time);
+		if((currtime - trans->time > 5) && trans->retries >= 1) {
+			// TODO 408
+		} else {
+			if((currtime - trans->time > 2) && trans->retries == 0) {
+				trans->retries++;
+				sendout_sipmsg(sip, trans->msg);
+			}
+		}
+	}
+	return TRUE;
+}
+
 static gboolean register_timeout(struct simple_account_data *sip) {
 	GSList *tmp;
 	time_t curtime = time(NULL);
 	// register again if first registration expires
 	if(sip->reregister < curtime) {
-		do_register(sip->gc);
+		do_register(sip);
 	}
 	
 	// check for every subscription if we need to resubscribe
@@ -645,7 +706,7 @@
 				fill_auth(sip, tmp, &sip->registrar);
 				sip->registerstatus=2;
 				gaim_debug(GAIM_DEBUG_MISC, "simple", "HA1: %s\n",sip->registrar.HA1);
-				do_register(sip->gc);
+				do_register(sip);
 			}
 			break;
 		}
@@ -865,11 +926,8 @@
 				if(trans->callback) {
 					// call the callback to process response
 					(trans->callback)(sip, msg, trans);
-						sip->transactions = g_slist_remove(sip->transactions, trans);
-				} else {
-					// transaction has no callback - just remove it
-					sip->transactions = g_slist_remove(sip->transactions, trans);
 				}
+				transactions_remove(sip, trans);
 			}
 			found = 1;
 		} else {
@@ -1013,7 +1071,7 @@
 	// get the local ip
 	sip->ip = g_strdup(gaim_network_get_my_ip(source));
 	
-	do_register(gc);
+	do_register(sip);
 	
 	conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc);
 }
@@ -1045,7 +1103,7 @@
 	gc->proto_data = sip = g_new0(struct simple_account_data,1);
 	sip->gc=gc;
 	sip->account = account;
-
+	sip->registerexpire = 900;
 	sip->udp = gaim_account_get_bool(account, "udp", FALSE);	
         if (strpbrk(username, " \t\v\r\n") != NULL) {
                 gaim_connection_error(gc, _("SIP usernames may not contain whitespaces or @ symbols"));
@@ -1112,18 +1170,21 @@
 		h = gethostbyname(serveradr->name);
 		sip->serveraddr.sin_addr.s_addr = ((struct in_addr*)h->h_addr)->s_addr;
 	        sip->ip = g_strdup(gaim_network_get_my_ip(sip->listenfd));
-
-	        do_register(gc);
+		sip->resendtimeout = gaim_timeout_add(2500, (GSourceFunc)resend_timeout, sip);
+	        do_register(sip);
 		
 	}
 		
 	// register timeout callback for register / subscribe renewal
-	sip->registertimeout = gaim_timeout_add((rand()%10)+10*1000, (GSourceFunc)register_timeout, sip);
+	sip->registertimeout = gaim_timeout_add((rand()%100)+10*1000, (GSourceFunc)register_timeout, sip);
 }
 
 static void simple_close(GaimConnection *gc)
 {
 	struct simple_account_data *sip = gc->proto_data;
+
+	// unregister
+	do_register_exp(sip, 0);
 //	if(sip) {
 	if(0) {
 		if(sip->servername) g_free(sip->servername);
--- a/src/protocols/simple/simple.h	Sat Aug 06 04:05:09 2005 +0000
+++ b/src/protocols/simple/simple.h	Sat Aug 06 12:25:15 2005 +0000
@@ -74,6 +74,7 @@
 	gchar *status;
 	GHashTable *buddies;
 	guint registertimeout;
+	guint resendtimeout;
 	int connecting;
 	GaimAccount *account;
 	gchar *sendlater;
@@ -82,6 +83,7 @@
 	GSList *openconns;
 	gboolean udp;
 	struct sockaddr_in serveraddr;
+	int registerexpire;
 };
 
 struct sip_connection {