diff options
| author | Sam Varshavchik | 2020-04-06 23:05:23 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2020-04-06 23:20:09 -0400 | 
| commit | e7b9dfe7c3f940625941ca725d403677c744c671 (patch) | |
| tree | 13f9dc550e3ba34d0238cf68b7c290ff106670f0 /rfc1035/rfc1035udp.c | |
| parent | 80a7d970578c67841992bd3ba609e833767be573 (diff) | |
| download | courier-libs-e7b9dfe7c3f940625941ca725d403677c744c671.tar.bz2 | |
Refactor rfc1035_query_udp (1/2).
The struct rfc1035_udp_query_responses collects multiple UDP responses
to concurrent UDP queries.
rfc1035_udp_query_response_alloc() allocates it.
rfc1035_udp_query_response_free() deletes it.
Nobody else cares about rfc1035_recv_udp, make it static. The existing
rfc1035_recv_udp code gets renamed as rfc1035_recv_one_udp_response,
and receives a rfc1035_udp_query_responses pointer, and instead of
returning a response, and its buflen, it reads a response, and finds
an unanswered query, in rfc1035_udp_query_responses, for which this
response is receives, and saves it there: loop over each query, and
if it doesn't have its response yet, and the response's serial number
matches the query's, store the query there, else throw it away.
The replacement rfc1035_recv_udp wrapper rfc1035_udp_query_response_alloc-s,
rfc1035_recv_one_udp_response, and fetches the received response out of it.
then rfc1035_udp_query_response_free()s.
Diffstat (limited to 'rfc1035/rfc1035udp.c')
| -rw-r--r-- | rfc1035/rfc1035udp.c | 140 | 
1 files changed, 115 insertions, 25 deletions
| diff --git a/rfc1035/rfc1035udp.c b/rfc1035/rfc1035udp.c index 29dac33..91fbe3c 100644 --- a/rfc1035/rfc1035udp.c +++ b/rfc1035/rfc1035udp.c @@ -40,7 +40,55 @@ int rfc1035_send_udp(int fd, const struct sockaddr *sin, int sin_len,  	return (-1);  } -static int dorecv(int fd, char *bufptr, int buflen, int flags, + +struct rfc1035_udp_query_responses * +rfc1035_udp_query_response_alloc(const char **queries, +				 const unsigned *querylens, +				 int n_queries) +{ +	struct rfc1035_udp_query_response *buf= +		calloc(n_queries, sizeof(struct rfc1035_udp_query_response)); +	int n; + +	struct rfc1035_udp_query_responses *resps; + +	if (!buf) +		return 0; + +	resps=malloc(sizeof(struct rfc1035_udp_query_responses)); + +	if (!resps) +	{ +		free(buf); +		return 0; +	} +	resps->n_queries=n_queries; +	resps->queries=buf; + +	for (n=0; n<n_queries; ++n) +	{ +		buf[n].query=queries[n]; +		buf[n].querylen=querylens[n]; +	} + +	return resps; +} + +void rfc1035_udp_query_response_free(struct rfc1035_udp_query_responses *resps) +{ +	int n; + +	for (n=0; n<resps->n_queries; ++n) +	{ +		if (resps->queries[n].response) +			free(resps->queries[n].response); +	} + +	free(resps->queries); +	free(resps); +} + +static int dorecv(int fd, char *bufptr, unsigned buflen, int flags,  		struct sockaddr *addr, socklen_t *addrlen)  {  socklen_t len; @@ -52,9 +100,9 @@ socklen_t len;  	return (len);  } -char *rfc1035_recv_udp(int fd, +static int rfc1035_recv_one_udp_response(int fd,  	const struct sockaddr *addrshouldfrom, int addrshouldfrom_len, -	int *buflen, const char *query) +        struct rfc1035_udp_query_responses *queries)  {  int	len; @@ -72,23 +120,23 @@ socklen_t addrfromlen;  char	rfc1035_buf[512];  char	*bufptr=rfc1035_buf;  char	*mallocedbuf=0; +int     i; +unsigned     buflen=sizeof(rfc1035_buf); -	*buflen=sizeof(rfc1035_buf); - -	while ((len=dorecv(fd, bufptr, *buflen, MSG_PEEK, 0, 0)) >= *buflen ) +	while ((len=dorecv(fd, bufptr, buflen, MSG_PEEK, 0, 0)) >= buflen )  	{ -		if (len == *buflen)	len += 511; +		if (len == buflen)	len += 511;  		++len;  		if (mallocedbuf)	free(mallocedbuf);  		mallocedbuf=(char *)malloc(len);  		if (!mallocedbuf)	return (0);  		bufptr= mallocedbuf; -		*buflen=len; +		buflen=len;  	}  	addrfromlen=sizeof(addrfrom); -	if (len < 0 || (len=dorecv(fd, bufptr, *buflen, 0, +	if (len < 0 || (len=dorecv(fd, bufptr, buflen, 0,  		(struct sockaddr *)&addrfrom, &addrfromlen)) < 0)  	{  		if (mallocedbuf) @@ -97,7 +145,7 @@ char	*mallocedbuf=0;  		return (0);  	} -	*buflen=len; +	buflen=len;  	if ( !rfc1035_same_ip( &addrfrom, addrfromlen,  				addrshouldfrom, addrshouldfrom_len)) @@ -109,31 +157,72 @@ char	*mallocedbuf=0;  		return (0);  	} -	if ( *buflen < 2) +	if ( buflen < 2)  	{  		if (mallocedbuf)  			free(mallocedbuf); -		errno=EIO; +		errno=EAGAIN;  		return (0);  	} -	if ( query && (bufptr[0] != query[0] || bufptr[1] != query[1] -		|| (unsigned char)(bufptr[2] & 0x80) == 0 )) +	for (i=0; i<queries->n_queries; ++i)  	{ -		if (mallocedbuf) -			free(mallocedbuf); -		errno=EAGAIN; -		return (0); +		if (queries->queries[i].response) +			continue; /* Already received this one */ + +		if ( bufptr[0] != queries->queries[i].query[0] || +		     bufptr[1] != queries->queries[i].query[1] +		     || (unsigned char)(bufptr[2] & 0x80) == 0 ) +			continue; + +		if (!mallocedbuf) +		{ +			if ((mallocedbuf=malloc( buflen )) == 0) +				return (0); + +			memcpy(mallocedbuf, bufptr, buflen); +			bufptr=mallocedbuf; +		} + +		queries->queries[i].response=mallocedbuf; +		queries->queries[i].resplen=buflen; +		return 1;  	} -	if (!mallocedbuf) + +	if (mallocedbuf) +		free(mallocedbuf); +	errno=EAGAIN; +	return (0); +} + +static char *rfc1035_recv_udp(int fd, +	const struct sockaddr *addrshouldfrom, int addrshouldfrom_len, +			      int *buflen, const char *query, +			      unsigned query_len) +{ +	struct rfc1035_udp_query_responses *resps= +		rfc1035_udp_query_response_alloc(&query, &query_len, 1); + +	if (!resps) +		return 0; + +	if (rfc1035_recv_one_udp_response(fd, +					  addrshouldfrom, +					  addrshouldfrom_len, +					  resps))  	{ -		if ((mallocedbuf=malloc( *buflen )) == 0) -			return (0); +		char *bufptr=resps->queries[0].response; + +		*buflen=resps->queries[0].resplen; -		memcpy(mallocedbuf, bufptr, *buflen); -		bufptr=mallocedbuf; +		resps->queries[0].response=0; +		rfc1035_udp_query_response_free(resps); +		return bufptr;  	} -	return (bufptr); + +	rfc1035_udp_query_response_free(resps); + +	return NULL;  }  char *rfc1035_query_udp(struct rfc1035_res *res, @@ -155,7 +244,8 @@ char	*rc;  		if (rfc1035_wait_reply(fd, final_time-current_time))  			break; -		rc=rfc1035_recv_udp(fd, sin, sin_len, buflen, query); +		rc=rfc1035_recv_udp(fd, sin, sin_len, buflen, +				    query, query_len);  		if (rc)	return (rc);  		if (errno != EAGAIN)	break; | 
