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 | |
| 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.
| -rw-r--r-- | rfc1035/rfc1035.h | 52 | ||||
| -rw-r--r-- | rfc1035/rfc1035udp.c | 140 |
2 files changed, 156 insertions, 36 deletions
diff --git a/rfc1035/rfc1035.h b/rfc1035/rfc1035.h index 7b9c4e7..9884677 100644 --- a/rfc1035/rfc1035.h +++ b/rfc1035/rfc1035.h @@ -363,17 +363,6 @@ int rfc1035_wait_query(int, /* File descriptor from rfc1035_open */ unsigned); /* Number of seconds to wait, use 0 for default */ /* Like reply, but we select for writing */ -char *rfc1035_recv_udp(int, /* File descriptor from rfc1035_open */ - const struct sockaddr *, int, - /* Expecting reply from this IP address */ - int *, /* * will be set to point to # of bytes received */ - const char *); /* Original query, used to validate id # */ - /* Returns ptr to dynamically allocated memory containing the reply, - ** or NULL if error. Errno will be set EAGAIN if we should try - ** again, because the message received was not in response - ** to the query. - */ - char *rfc1035_query_udp(struct rfc1035_res *, int, /* file descriptor */ const struct sockaddr *, int, /* Attempt number */ @@ -623,6 +612,47 @@ struct rfc1035_ifconf { struct rfc1035_ifconf *rfc1035_ifconf(int *errflag); void rfc1035_ifconf_free(struct rfc1035_ifconf *ifconf_list); +/* +** Outstanding UDP queries. +*/ + +struct rfc1035_udp_query_response; + + /* How many queries, and the queries */ + +struct rfc1035_udp_query_responses { + int n_queries; + struct rfc1035_udp_query_response *queries; +}; + + /* Each query, and response already receives so far, if any. */ + +struct rfc1035_udp_query_response { + const char *query; + unsigned querylen; + char *response; + unsigned resplen; +}; + +/* +** Allocate a new rfc1035_udp_query_responses. +** Copies each query into the rfc1035_udp_query_response, each response is +** initialized to null. +*/ + +struct rfc1035_udp_query_responses * +rfc1035_udp_query_response_alloc(const char **queries, + const unsigned *querylens, + int n_queries); + +/* +** Deallocate rfc1035_udp_query_responses. Each non-NULL response pointer +** gets free()d. +*/ + +void rfc1035_udp_query_response_free(struct rfc1035_udp_query_responses *); + + #ifdef __cplusplus } #endif 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; |
