[asterisk-commits] oej: branch oej/obproxyfailover r122867 - /team/oej/obproxyfailover/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jun 16 05:19:05 CDT 2008


Author: oej
Date: Mon Jun 16 05:19:05 2008
New Revision: 122867

URL: http://svn.digium.com/view/asterisk?view=rev&rev=122867
Log:
Did some work on this while flying to portugal. Still work in progress, not done.
But a lot of good ideas on how to create a list of outbound proxys that we can
switch between in various ways to either have failover or load balancing.

Modified:
    team/oej/obproxyfailover/channels/chan_sip.c

Modified: team/oej/obproxyfailover/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/obproxyfailover/channels/chan_sip.c?view=diff&rev=122867&r1=122866&r2=122867
==============================================================================
--- team/oej/obproxyfailover/channels/chan_sip.c (original)
+++ team/oej/obproxyfailover/channels/chan_sip.c Mon Jun 16 05:19:05 2008
@@ -375,13 +375,31 @@
 	char name[MAXHOSTNAMELEN];	/*!< DNS name of domain/host or IP */
 	struct sockaddr_in ip;		/*!< Currently used IP address and port */
 	time_t last_dnsupdate;		/*!< When this was resolved */
+	struct sip_proxy *next;		/*!< Next proxy in lists */
+	int srvlookup;			/*!< Do SRV lookup? If port is given in configuration, don't do it */
+};
+
+enum proxy_scheme {
+	OBPROXY_ROUNDROBIN=0;		/*!< Take the first one, then next one, then next one and start all over again at the end. Switch every dialog (load balancing) If one fails, move on */
+	OBPROXY_FAILOVER;		/*!< Pick the first one, stay until it fails, then move to the next one in chain */
+	OBPROXY_RANDOM;			/*!< Randomly jump between proxys between each call */
+	/* OBPROXY_SRV */		/*!< SRV record based failover */
+};
+
+/*! \brief Holding pattern for proxy list, including scheme 
+	\note At some time we could implement named lists so that we only have to declare lists once for each list and use the same failover scheme.
+		Realtime hosts could then refer to named proxy lists for outbound services
+*/
+struct outbound_proxys {
+	struct sip_proxy *first;	/*!< Linked list of proxys */
+	struct sip_proxy *current;	/*!< The current one we use */	
+	enum proxy_scheme scheme;	/*!< Scheme */
 	int force;			/*!< If it's an outbound proxy, Force use of this outbound proxy for all outbound requests */
-	/* Room for a SRV record chain based on the name */
+	int count;			/*!< Count of proxys in list (for random scheme) */
 };
 
-
-#define CAN_NOT_CREATE_DIALOG	0
-#define CAN_CREATE_DIALOG	1
+#define CAN_NOT_CREATE_DIALOG			0
+#define CAN_CREATE_DIALOG			1
 #define CAN_CREATE_DIALOG_UNSUPPORTED_METHOD	2
 
 /*! XXX Note that sip_methods[i].id == i must hold or the code breaks */
@@ -583,7 +601,7 @@
 static int global_t1min;		/*!< T1 roundtrip time minimum */
 static int global_autoframing;          /*!< Turn autoframing on or off. */
 static enum transfermodes global_allowtransfer;	/*!< SIP Refer restriction scheme */
-static struct sip_proxy global_outboundproxy;	/*!< Outbound proxy */
+static struct outbound_proxys *global_outboundproxy = NULL;	/*!< Outbound proxy */
 
 static int global_matchexterniplocally; /*!< Match externip/externhost setting against localnet setting */
 
@@ -980,7 +998,7 @@
 	int jointnoncodeccapability;            /*!< Joint Non codec capability */
 	int redircodecs;			/*!< Redirect codecs */
 	int maxcallbitrate;			/*!< Maximum Call Bitrate for Video Calls */	
-	struct sip_proxy *outboundproxy;	/*!< Outbound proxy for this dialog */
+	struct outbound_proxys *outboundproxy;	/*!< Outbound proxy for this dialog */
 	struct t38properties t38;		/*!< T38 settings */
 	struct sockaddr_in udptlredirip;	/*!< Where our T.38 UDPTL should be going if not to us */
 	struct ast_udptl *udptl;		/*!< T.38 UDPTL session */
@@ -1134,7 +1152,7 @@
 	int rtpkeepalive;		/*!<  Send RTP packets for keepalive */
 	ast_group_t callgroup;		/*!<  Call group */
 	ast_group_t pickupgroup;	/*!<  Pickup group */
-	struct sip_proxy *outboundproxy; /*!<  Outbound proxy for this peer */
+	struct outbound_proxys *outboundproxy;	/*!< Outbound proxy for this dialog */
 	struct sockaddr_in addr;	/*!<  IP address of peer */
 	int maxcallbitrate;		/*!< Maximum Bitrate for a video call */
 	
@@ -1357,6 +1375,9 @@
 static int sip_refer_allocate(struct sip_pvt *p);
 static void ast_quiet_chan(struct ast_channel *chan);
 static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
+static struct outbound_proxys *outbound_proxys_allocate(struct sip_pvt *p);
+static int outbound_proxys_free(struct outbound_proxys *proxylist);
+static int outbound_proxys_add(struct outbound_proxys *proxylist, char *name);
 
 /*--- Device monitoring and Device/extension state handling */
 static int cb_extensionstate(char *context, char* exten, int state, void *data);
@@ -1688,9 +1709,12 @@
 	/* if it's actually an IP address and not a name,
            there's no need for a managed lookup */
         if (!inet_aton(proxy->name, &proxy->ip.sin_addr)) {
+		int usersrv = srvlookup;	/* Global setting */
+		if (!proxy->srvlookup)		/* Turn off if we've got host name */
+			usesrv = FALSE;
+
 		/* Ok, not an IP address, then let's check if it's a domain or host */
-		/* XXX Todo - if we have proxy port, don't do SRV */
-		if (ast_get_ip_or_srv(&proxy->ip, proxy->name, srvlookup ? "_sip._udp" : NULL) < 0) {
+		if (ast_get_ip_or_srv(&proxy->ip, proxy->name, usesrv ? "_sip._udp" : NULL) < 0) {
 			ast_log(LOG_WARNING, "Unable to locate host '%s'\n", proxy->name);
 			return FALSE;
 		}
@@ -1706,12 +1730,56 @@
 	proxy = ast_calloc(1, sizeof(struct sip_proxy));
 	if (!proxy)
 		return NULL;
+	proxy->ip.sin_family = AF_INET;
 	proxy->force = force;
 	ast_copy_string(proxy->name, name, sizeof(proxy->name));
-	if (!ast_strlen_zero(port))
+	if (!ast_strlen_zero(port)) {
 		proxy->ip.sin_port = htons(atoi(port));
+		proxy->srvlookup = FALSE;
+	} else {
+		proxy->ip.sin_port = htons(STANDARD_SIP_PORT);
+		proxy->srvlookup = TRUE;	/* No port given, use proxy SRV lookup */
+	}
 	proxy_update(proxy);
 	return proxy;
+}
+
+/*! \brief Select outbound proxy to use based on scheme */
+enum proxy_scheme {
+        OBPROXY_FAILOVER = 0;            /*!< DEFAULT: Pick the first one, stay until it fails, then move to the next one in chain */
+        OBPROXY_ROUNDROBIN;              /*!< Take the first one, then next one, then next one and start all over again at the end. Switch every dialog (load balancing) If one fails, move on */
+        OBPROXY_RANDOM;                 /*!< Randomly jump between proxys between each call */
+        /* OBPROXY_SRV */               /*!< SRV record based failover */
+
+static struct sip_proxy *outbound_proxy_select(struct outbound_proxys *proxys)
+{
+	if (proxys->scheme == OBPROXY_FAILOVER) {
+		return proxys->current;
+	}
+	if (proxys->scheme == OBPROXY_ROUNDROBIN) {
+		if (proxys->current->next) {
+			return proxys->current = proxys->current->next;
+		}
+		proxys->current = proxys->first;
+		return proxys->current;
+	}
+	if (proxys->scheme == OBPROXY_RANDOM) {
+		struct sip_proxy *start = proxys->first;
+		int winner = ast_random()  % proxys->count);
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "**** OUR WINNER TONIGHT IS OUTBOUND PROXY %d\n", winner + 1;
+		if (winner > 0) {
+			int i ;
+			for (i = 0; i < winner; i++) {
+				if (start->next) {
+					start = start->next;
+				}
+			}
+		}
+		return start;
+	}
+	/* Placeholder for another scheme */
+	return NULL;
 }
 
 /*! \brief Get default outbound proxy or global proxy */
@@ -1720,14 +1788,14 @@
 	if (peer && peer->outboundproxy) {
 		if (option_debug && sipdebug)
 			ast_log(LOG_DEBUG, "OBPROXY: Applying peer OBproxy to this call\n");
-		append_history(dialog, "OBproxy", "Using peer obproxy %s", peer->outboundproxy->name);
-		return peer->outboundproxy;
-	}
-	if (global_outboundproxy.name[0]) {
+		append_history(dialog, "OBproxy", "Using peer obproxy %s", peer->outboundproxy->current->name);
+		return outbound_proxy_select(peer->outboundproxy);
+	}
+	if (global_outboundproxy) {
 		if (option_debug && sipdebug)
 			ast_log(LOG_DEBUG, "OBPROXY: Applying global OBproxy to this call\n");
-		append_history(dialog, "OBproxy", "Using global obproxy %s", global_outboundproxy.name);
-		return &global_outboundproxy;
+		append_history(dialog, "OBproxy", "Using global obproxy %s", global_outboundproxy->current->name);
+		return outbound_proxy_select(global_outboundproxy);
 	}
 	if (option_debug && sipdebug)
 		ast_log(LOG_DEBUG, "OBPROXY: Not applying OBproxy to this call\n");
@@ -10886,8 +10954,8 @@
 	ast_cli(fd, "  SIP Transfer mode:      %s\n", transfermode2str(global_allowtransfer));
 	ast_cli(fd, "  Max Call Bitrate:       %d kbps\n", default_maxcallbitrate);
 	ast_cli(fd, "  Auto-Framing:           %s\n", global_autoframing ? "Yes" : "No");
-	ast_cli(fd, "  Outb. proxy:            %s %s\n", ast_strlen_zero(global_outboundproxy.name) ? "<not set>" : global_outboundproxy.name,
-							global_outboundproxy.force ? "(forced)" : "");
+	ast_cli(fd, "  Outb. proxy:            %s %s\n", global_outboundproxy ? "<not set>" : global_outboundproxy->current->name,
+							global_outboundproxy ? "" : global_outboundproxy->force ? "(forced) : "");
 
 	ast_cli(fd, "\nDefault Settings:\n");
 	ast_cli(fd, "-----------------\n");
@@ -16414,6 +16482,92 @@
 	return res;
 }
 
+//static int  outbound_proxys_free(struct sip_pvt *p);
+/*! \brief Allocate holding structure for outbound proxy list in peer or in general section */
+static struct outbound_proxys *outbound_proxys_allocate(struct sip_pvt *p)
+{
+	struct outbound_proxys *proxys = ast_calloc(1, sizeof(struct outbound_proxys));
+	if (!proxys)
+		return 0;
+	proxys->scheme = OBPROXY_ROUNDROBIN;
+	return 1;
+}
+
+/*! \brief Free proxy list */
+static int outbound_proxys_free(struct outbound_proxys *proxylist)
+{
+	struct sip_proxy *proxy, *prevproxy;;
+	if (!proxylist)
+		return 0;
+	proxy = proxylist->proxys;
+	while (proxy) {
+		prevproxy = proxy;
+		proxy = proxy->next;
+		ast_free(proxy);
+	};
+	ast_free(proxylist);
+	return 1;
+}
+
+/*! \brief Set outbound proxy scheme
+	\param name Configuration parameter like "scheme[,force]"
+*/
+static int outbound_proxys_scheme(struct outbound_proxys *proxylist, const char *name)
+{
+	char *scheme = ast_strdupa(name)
+	char *force = strchr(varname, ",");
+
+	if (force) {
+		*force = '\0';
+		force++;
+		while (*force == ' ') {
+			force++;
+		}
+		if (!strcasecmp(force, "force")) {
+			proxylist->force = TRUE;
+		}
+	}
+	if strcasecmp(scheme, "
+skrep
+	
+	
+}
+
+/*! \brief Add outbound proxy to list 
+	\param name Configuration parameter like hostname:port
+*/
+static int outbound_proxys_add(struct outbound_proxys *proxylist, const char *name)
+{
+	char *port, *next, *force;
+	int forceopt = FALSE;
+	struct sip_proxy *proxy;
+	char *varname;
+
+	/* Set peer channel variable */
+	varname = ast_strdupa(name);
+	next = varname;
+	if ((port = strchr(varname, ':'))) {
+		*port++ = '\0';
+		next = port;
+	}
+	/* Allocate proxy object */
+	proxy  = proxy_allocate(varname, port, forceopt);
+	if (!proxy)
+		return 0;
+
+	if (!proxylist->current && !proxylist->first) {
+		/* Set current to first one in configuration file */
+		proxylist->current = proxylist->first = proxy;
+		proxylist->count = 1;
+	} else {
+		proxy->next = proxylist->first;
+		proxylist->first = proxy->next;
+		proxylist->count++;
+	}
+	
+}
+
+
 /*! \brief Add SIP domain to list of domains we are responsible for */
 static int add_sip_domain(const char *domain, const enum domain_mode mode, const char *context)
 {
@@ -16838,22 +16992,12 @@
 			ast_set2_flag(&peer->flags[0], ast_true(v->value), SIP_USEREQPHONE);
 		} else if (!strcasecmp(v->name, "fromuser")) {
 			ast_copy_string(peer->fromuser, v->value, sizeof(peer->fromuser));
+		} else if (!strcasecmp(v->name, "outboundproxyscheme")) {
+			outbound_proxys_scheme(peer->outboundproxy, v->value);
 		} else if (!strcasecmp(v->name, "outboundproxy")) {
-			char *port, *next, *force;
-			int forceopt = FALSE;
-			/* Set peer channel variable */
-			varname = ast_strdupa(v->value);
-			next = varname;
-			if ((port = strchr(varname, ':'))) {
-				*port++ = '\0';
-				next = port;
-			}
-			if ((force = strchr(next, ','))) {
-				*force++ = '\0';
-				forceopt = strcmp(force, "force");
-			}
-			/* Allocate proxy object */
-			peer->outboundproxy = proxy_allocate(varname, port, forceopt);
+			if (!peer->outboundproxy)
+				peer->outboundproxy = outbound_proxys_allocate();
+			outbound_proxys_add(peer->outboundproxy, v->value);
 		} else if (!strcasecmp(v->name, "host")) {
 			if (!strcasecmp(v->value, "dynamic")) {
 				/* They'll register with us */
@@ -17080,9 +17224,6 @@
 	memset(&localaddr, 0, sizeof(localaddr));
 	memset(&externip, 0, sizeof(externip));
 	memset(&default_prefs, 0 , sizeof(default_prefs));
-	memset(&global_outboundproxy, 0, sizeof(struct sip_proxy));
-	global_outboundproxy.ip.sin_port = htons(STANDARD_SIP_PORT);
-	global_outboundproxy.ip.sin_family = AF_INET;	/* Type of address: IPv4 */
 	ourport = STANDARD_SIP_PORT;
 	srvlookup = DEFAULT_SRVLOOKUP;
 	global_tos_sip = DEFAULT_TOS_SIP;
@@ -17102,6 +17243,10 @@
 	global_notifyhold = FALSE;
 	global_alwaysauthreject = 0;
 	global_allowsubscribe = FALSE;
+	if (global_outboundproxy) {
+		outbound_proxys_free(global_outboundproxy);
+		global_outboundproxy = NULL;
+	}
 	ast_copy_string(global_useragent, DEFAULT_USERAGENT, sizeof(global_useragent));
 	ast_copy_string(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime));
 	if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME))
@@ -17259,21 +17404,15 @@
 			ast_copy_string(default_callerid, v->value, sizeof(default_callerid));
 		} else if (!strcasecmp(v->name, "fromdomain")) {
 			ast_copy_string(default_fromdomain, v->value, sizeof(default_fromdomain));
+		} else if (!strcasecmp(v->name, "outboundproxyscheme")) {
+			if (!global_outboundproxy) {
+				global_outboundproxy = outbound_proxys_allocate();
+			}
+			outbound_proxys_scheme(global_outboundproxy, v->value);
 		} else if (!strcasecmp(v->name, "outboundproxy")) {
-			char *name, *port = NULL, *force;
-
-			name = ast_strdupa(v->value);
-			if ((port = strchr(name, ':'))) {
-				*port++ = '\0';
-				global_outboundproxy.ip.sin_port = htons(atoi(port));
-			}
-	
-			if ((force = strchr(port ? port : name, ','))) {
-				*force++ = '\0';
-				global_outboundproxy.force = (!strcasecmp(force, "force"));
-			}
-			ast_copy_string(global_outboundproxy.name, name, sizeof(global_outboundproxy.name));
-			proxy_update(&global_outboundproxy);
+			if (!global_outboundproxy)
+				global_outboundproxy = outbound_proxys_allocate();
+			outbound_proxys_add(global_outboundproxy, v->value);
 		} else if (!strcasecmp(v->name, "autocreatepeer")) {
 			autocreatepeer = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "srvlookup")) {




More information about the asterisk-commits mailing list