Review Board 1.7.16


Patch for issue 12312 (DNS SRV lookups causing re-registration problems)

Review Request #132 - Created Jan. 26, 2009 and submitted

Mark Michelson
1.4
Reviewers
asterisk-dev
Asterisk
This patch is to address issue 12312 on the Asterisk bugtracker.

The short version of what this patch does is to only do an SRV lookup on a hostname if we have encountered some sort of error condition (e.g. REGISTER sent with no reply, error when calling sendto() function. For simple cases like re-registration, we do not need to do another SRV lookup. While this patch has received some testing from Leif Madsen, I would like to have at least one other developer take a look at this code change to make sure there is not anything I am overlooking here.

This review request may sound similar to review request 124 (http://reviewboard.digium.com/r/124/). Essentially, this patch I am providing does the same thing, with a couple of exceptions:
1. Instead of using a patch already attached to an issue, I have written this patch myself, so I am more aware of what is intended.
2. Instead of posting a patch for trunk, this patch is for Asterisk 1.4. It turns out that the dnsmgr work in trunk already has fixed this specific problem there.
As such, I am removing request #124 since it is no longer relevant.
Leif Madsen has tested this patch with a provider that has multiple SRV records for its hostname. Leif has confirmed that when sending a re-registration, another DNS lookup is not performed and the request is sent to the same IP address as was used in the original registration.

Diff revision 1 (Latest)

  1. /branches/1.4/channels/chan_sip.c: Loading...
/branches/1.4/channels/chan_sip.c
Revision 171438 New Change
[20] 1170 lines
[+20] [+] struct sip_registry {
1171
	int regattempts;		/*!< Number of attempts (since the last success) */
1171
	int regattempts;		/*!< Number of attempts (since the last success) */
1172
	int timeout; 			/*!< sched id of sip_reg_timeout */
1172
	int timeout; 			/*!< sched id of sip_reg_timeout */
1173
	int refresh;			/*!< How often to refresh */
1173
	int refresh;			/*!< How often to refresh */
1174
	struct sip_pvt *call;		/*!< create a sip_pvt structure for each outbound "registration dialog" in progress */
1174
	struct sip_pvt *call;		/*!< create a sip_pvt structure for each outbound "registration dialog" in progress */
1175
	enum sipregistrystate regstate;	/*!< Registration state (see above) */
1175
	enum sipregistrystate regstate;	/*!< Registration state (see above) */

    
   
1176
	unsigned int needdns:1; /*!< Set if we need a new dns lookup before we try to transmit */
1176
	time_t regtime;		/*!< Last succesful registration time */
1177
	time_t regtime;		/*!< Last succesful registration time */
1177
	int callid_valid;		/*!< 0 means we haven't chosen callid for this registry yet. */
1178
	int callid_valid;		/*!< 0 means we haven't chosen callid for this registry yet. */
1178
	unsigned int ocseq;		/*!< Sequence number we got to for REGISTERs for this registry */
1179
	unsigned int ocseq;		/*!< Sequence number we got to for REGISTERs for this registry */
1179
	struct sockaddr_in us;		/*!< Who the server thinks we are */
1180
	struct sockaddr_in us;		/*!< Who the server thinks we are */
1180
	int noncecount;			/*!< Nonce-count */
1181
	int noncecount;			/*!< Nonce-count */
[+20] [20] 328 lines
[+20] [+] static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch);
1509
static int init_resp(struct sip_request *resp, const char *msg);
1510
static int init_resp(struct sip_request *resp, const char *msg);
1510
static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req);
1511
static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req);
1511
static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
1512
static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
1512
static void build_via(struct sip_pvt *p);
1513
static void build_via(struct sip_pvt *p);
1513
static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
1514
static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
1514
static int create_addr(struct sip_pvt *dialog, const char *opeer);
1515
static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin);
1515
static char *generate_random_string(char *buf, size_t size);
1516
static char *generate_random_string(char *buf, size_t size);
1516
static void build_callid_pvt(struct sip_pvt *pvt);
1517
static void build_callid_pvt(struct sip_pvt *pvt);
1517
static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
1518
static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
1518
static void make_our_tag(char *tagbuf, size_t len);
1519
static void make_our_tag(char *tagbuf, size_t len);
1519
static int add_header(struct sip_request *req, const char *var, const char *value);
1520
static int add_header(struct sip_request *req, const char *var, const char *value);
[+20] [20] 277 lines
[+20] [+] static int __sip_xmit(struct sip_pvt *p, char *data, int len)
1797
		case ENETDOWN: 		/* Inteface down */
1798
		case ENETDOWN: 		/* Inteface down */
1798
		case ENETUNREACH:	/* Network failure */
1799
		case ENETUNREACH:	/* Network failure */
1799
		case ECONNREFUSED:      /* ICMP port unreachable */ 
1800
		case ECONNREFUSED:      /* ICMP port unreachable */ 
1800
			res = XMIT_ERROR;	/* Don't bother with trying to transmit again */
1801
			res = XMIT_ERROR;	/* Don't bother with trying to transmit again */
1801
		}
1802
		}

    
   
1803

   

    
   
1804
		if (p->registry && p->registry->regstate < REG_STATE_REGISTERED) {

    
   
1805
			AST_SCHED_DEL(sched, p->registry->timeout);

    
   
1806
			p->registry->needdns = TRUE;

    
   
1807
			p->registry->timeout = ast_sched_add(sched, 1, sip_reg_timeout, p->registry);

    
   
1808
		}
1802
	}
1809
	}

    
   
1810

   
1803
	if (res != len)
1811
	if (res != len)
1804
		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno));
1812
		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno));
1805
	return res;
1813
	return res;
1806
}
1814
}
1807

    
   
1815

   
[+20] [20] 1096 lines
[+20] [+] static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
2904
}
2912
}
2905

    
   
2913

   
2906
/*! \brief create address structure from peer name
2914
/*! \brief create address structure from peer name
2907
 *      Or, if peer not found, find it in the global DNS 
2915
 *      Or, if peer not found, find it in the global DNS 
2908
 *      returns TRUE (-1) on failure, FALSE on success */
2916
 *      returns TRUE (-1) on failure, FALSE on success */
2909
static int create_addr(struct sip_pvt *dialog, const char *opeer)
2917
static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin)
2910
{
2918
{
2911
	struct hostent *hp;
2919
	struct hostent *hp;
2912
	struct ast_hostent ahp;
2920
	struct ast_hostent ahp;
2913
	struct sip_peer *p;
2921
	struct sip_peer *p;
2914
	char *port;
2922
	char *port;
[+20] [20] 16 lines
[+20] static int create_addr(struct sip_pvt *dialog, const char *opeer) [+] static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin)
2931
			dialog->sa.sin_port = dialog->recv.sin_port = htons(portno);
2939
			dialog->sa.sin_port = dialog->recv.sin_port = htons(portno);
2932
		}
2940
		}
2933
		ASTOBJ_UNREF(p, sip_destroy_peer);
2941
		ASTOBJ_UNREF(p, sip_destroy_peer);
2934
		return res;
2942
		return res;
2935
	}
2943
	}

    
   
2944
	

    
   
2945
	ast_string_field_set(dialog, tohost, peer);

    
   
2946

   

    
   
2947
	if (sin) {

    
   
2948
		memcpy(&dialog->sa.sin_addr, &sin->sin_addr, sizeof(dialog->sa.sin_addr));

    
   
2949
		if (!sin->sin_port) {

    
   
2950
			if (ast_strlen_zero(port) || sscanf(port, "%u", &portno) != 1) {

    
   
2951
				portno = STANDARD_SIP_PORT;

    
   
2952
			}

    
   
2953
		} else {

    
   
2954
			portno = ntohs(sin->sin_port);

    
   
2955
		}

    
   
2956
	} else {
2936
	hostn = peer;
2957
		hostn = peer;
2937
	portno = port ? atoi(port) : STANDARD_SIP_PORT;
2958
		portno = port ? atoi(port) : STANDARD_SIP_PORT;
2938
	if (srvlookup) {
2959
		if (srvlookup) {
2939
		char service[MAXHOSTNAMELEN];
2960
			char service[MAXHOSTNAMELEN];
2940
		int tportno;
2961
			int tportno;
[+20] [20] 9 lines
[+20] static int create_addr(struct sip_pvt *dialog, const char *opeer) static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin)
2950
	hp = ast_gethostbyname(hostn, &ahp);
2971
		hp = ast_gethostbyname(hostn, &ahp);
2951
	if (!hp) {
2972
		if (!hp) {
2952
		ast_log(LOG_WARNING, "No such host: %s\n", peer);
2973
			ast_log(LOG_WARNING, "No such host: %s\n", peer);
2953
		return -1;
2974
			return -1;
2954
	}
2975
		}
2955
	ast_string_field_set(dialog, tohost, peer);

   
2956
	memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr));
2976
		memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr));

    
   
2977
	}
2957
	dialog->sa.sin_port = htons(portno);
2978
	dialog->sa.sin_port = htons(portno);
2958
	dialog->recv = dialog->sa;
2979
	dialog->recv = dialog->sa;
2959
	return 0;
2980
	return 0;
2960
}
2981
}
2961

    
   
2982

   
[+20] [20] 1845 lines
[+20] [+] static int sip_register(char *value, int lineno)
4807
	reg->timeout =  -1;
4828
	reg->timeout =  -1;
4808
	reg->refresh = default_expiry;
4829
	reg->refresh = default_expiry;
4809
	reg->portno = portnum;
4830
	reg->portno = portnum;
4810
	reg->callid_valid = FALSE;
4831
	reg->callid_valid = FALSE;
4811
	reg->ocseq = INITIAL_CSEQ;
4832
	reg->ocseq = INITIAL_CSEQ;

    
   
4833
	reg->needdns = TRUE;
4812
	ASTOBJ_CONTAINER_LINK(&regl, reg);	/* Add the new registry entry to the list */
4834
	ASTOBJ_CONTAINER_LINK(&regl, reg);	/* Add the new registry entry to the list */
4813
	ASTOBJ_UNREF(reg,sip_registry_destroy);
4835
	ASTOBJ_UNREF(reg,sip_registry_destroy);
4814
	return 0;
4836
	return 0;
4815
}
4837
}
4816

    
   
4838

   
[+20] [20] 2820 lines
[+20] [+] static int sip_reg_timeout(const void *data)
7637
		ast_log(LOG_NOTICE, "   -- Giving up forever trying to register '%s@%s'\n", r->username, r->hostname);
7659
		ast_log(LOG_NOTICE, "   -- Giving up forever trying to register '%s@%s'\n", r->username, r->hostname);
7638
		r->regstate = REG_STATE_FAILED;
7660
		r->regstate = REG_STATE_FAILED;
7639
	} else {
7661
	} else {
7640
		r->regstate = REG_STATE_UNREGISTERED;
7662
		r->regstate = REG_STATE_UNREGISTERED;
7641
		r->timeout = -1;
7663
		r->timeout = -1;

    
   
7664
		r->needdns = TRUE;
7642
		res=transmit_register(r, SIP_REGISTER, NULL, NULL);
7665
		res=transmit_register(r, SIP_REGISTER, NULL, NULL);
7643
	}
7666
	}
7644
	manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
7667
	manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
7645
	ASTOBJ_UNREF(r, sip_registry_destroy);
7668
	ASTOBJ_UNREF(r, sip_registry_destroy);
7646
	return 0;
7669
	return 0;
[+20] [20] 38 lines
[+20] [+] static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader)
7685
			ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
7708
			ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
7686
			return 0;
7709
			return 0;
7687
		}
7710
		}
7688
		if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
7711
		if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
7689
			append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
7712
			append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
7690
		/* Find address to hostname */
7713
		/* Find address to hostname if we haven't tried to connect
7691
		if (create_addr(p, r->hostname)) {
7714
		 * or a connection error has occurred */

    
   
7715
		if (create_addr(p, r->hostname, r->needdns ? NULL : &r->us)) {
7692
			/* we have what we hope is a temporary network error,
7716
			/* we have what we hope is a temporary network error,
7693
			 * probably DNS.  We need to reschedule a registration try */
7717
			 * probably DNS.  We need to reschedule a registration try */
7694
			sip_destroy(p);
7718
			sip_destroy(p);
7695

    
   
7719

   
7696
			if (r->timeout > -1)
7720
			if (r->timeout > -1)
[+20] [20] 4 lines
[+20] static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader)
7701
			AST_SCHED_DEL(sched, r->timeout);
7725
			AST_SCHED_DEL(sched, r->timeout);
7702
			r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, r);
7726
			r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, r);
7703
			r->regattempts++;
7727
			r->regattempts++;
7704
			return 0;
7728
			return 0;
7705
		}
7729
		}

    
   
7730
		if (r->needdns) {

    
   
7731
			memcpy(&r->us, &p->sa, sizeof(r->us));

    
   
7732
		}

    
   
7733
		r->needdns = FALSE;
7706
		/* Copy back Call-ID in case create_addr changed it */
7734
		/* Copy back Call-ID in case create_addr changed it */
7707
		ast_string_field_set(r, callid, p->callid);
7735
		ast_string_field_set(r, callid, p->callid);
7708
		if (r->portno) {
7736
		if (r->portno) {
7709
			p->sa.sin_port = htons(r->portno);
7737
			p->sa.sin_port = htons(r->portno);
7710
			p->recv.sin_port = htons(r->portno);
7738
			p->recv.sin_port = htons(r->portno);
[+20] [20] 3845 lines
[+20] [+] static int sip_notify(int fd, int argc, char *argv[])
11556
		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
11584
		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
11557
			ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
11585
			ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
11558
			return RESULT_FAILURE;
11586
			return RESULT_FAILURE;
11559
		}
11587
		}
11560

    
   
11588

   
11561
		if (create_addr(p, argv[i])) {
11589
		if (create_addr(p, argv[i], NULL)) {
11562
			/* Maybe they're not registered, etc. */
11590
			/* Maybe they're not registered, etc. */
11563
			sip_destroy(p);
11591
			sip_destroy(p);
11564
			ast_cli(fd, "Could not create address for '%s'\n", argv[i]);
11592
			ast_cli(fd, "Could not create address for '%s'\n", argv[i]);
11565
			continue;
11593
			continue;
11566
		}
11594
		}
[+20] [20] 5108 lines
[+20] [+] static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause)
16675
		if (ext) 
16703
		if (ext) 
16676
			*ext++ = '\0';
16704
			*ext++ = '\0';
16677
		host = tmp;
16705
		host = tmp;
16678
	}
16706
	}
16679

    
   
16707

   
16680
	if (create_addr(p, host)) {
16708
	if (create_addr(p, host, NULL)) {
16681
		*cause = AST_CAUSE_UNREGISTERED;
16709
		*cause = AST_CAUSE_UNREGISTERED;
16682
		if (option_debug > 2)
16710
		if (option_debug > 2)
16683
			ast_log(LOG_DEBUG, "Cant create SIP call - target device not registred\n");
16711
			ast_log(LOG_DEBUG, "Cant create SIP call - target device not registred\n");
16684
		sip_destroy(p);
16712
		sip_destroy(p);
16685
		return NULL;
16713
		return NULL;
[+20] [20] 2212 lines
  1. /branches/1.4/channels/chan_sip.c: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.