# include "../conf/portability.h"
#endif
+#include <bits/libc-lock.h>
+
+/* Lock to protect the connection use. */
+__libc_lock_define_initialized (static, lock)
+
+static void res_close_internal (void);
+
#if defined(USE_OPTIONS_H)
# include <../conf/options.h>
#endif
int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
register int n;
u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
+ int result = -1;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
/* errno should have been set by res_init() in this case. */
terrno = ETIMEDOUT;
badns = 0;
+ __libc_lock_lock (lock);
+
/*
* Send request, RETRY times, or until successful
*/
struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
same_ns:
if (badns & (1 << ns)) {
- res_close();
+ res_close_internal();
goto next_ns;
}
done = 1;
break;
case res_nextns:
- res_close();
+ res_close_internal();
goto next_ns;
case res_done:
- return (resplen);
+ result = resplen;
+ goto and_out;
case res_modified:
/* give the hook another try */
if (++loops < 42) /*doug adams*/
case res_error:
/*FALLTHROUGH*/
default:
- return (-1);
+ goto and_out;
}
} while (!done);
}
truncated = 0;
if ((s < 0) || (!vc)) {
if (s >= 0)
- res_close();
+ res_close_internal();
s = socket(PF_INET, SOCK_STREAM, 0);
if (s < 0) {
terrno = errno;
Perror(stderr, "socket(vc)", errno);
- return (-1);
+ goto and_out;
}
__set_errno (0);
if (connect(s, (struct sockaddr *)nsap,
Aerror(stderr, "connect/vc",
errno, *nsap);
badns |= (1 << ns);
- res_close();
+ res_close_internal();
goto next_ns;
}
vc = 1;
terrno = errno;
Perror(stderr, "write failed", errno);
badns |= (1 << ns);
- res_close();
+ res_close_internal();
goto next_ns;
}
/*
if (n <= 0) {
terrno = errno;
Perror(stderr, "read failed", errno);
- res_close();
+ res_close_internal();
/*
* A long running process might get its TCP
* connection reset if the remote server was
*/
if (terrno == ECONNRESET && !connreset) {
connreset = 1;
- res_close();
+ res_close_internal();
goto same_ns;
}
- res_close();
+ res_close_internal();
goto next_ns;
}
resplen = _getshort(ans);
(stdout, ";; undersized: %d\n", len));
terrno = EMSGSIZE;
badns |= (1 << ns);
- res_close();
+ res_close_internal();
goto next_ns;
}
cp = ans;
if (n <= 0) {
terrno = errno;
Perror(stderr, "read(vc)", errno);
- res_close();
+ res_close_internal();
goto next_ns;
}
if (truncated) {
if ((s < 0) || vc) {
if (vc)
- res_close();
+ res_close_internal();
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
#if !CAN_RECONNECT
#endif
terrno = errno;
Perror(stderr, "socket(dg)", errno);
- return (-1);
+ goto and_out;
}
connected = 0;
}
"connect(dg)",
errno, *nsap);
badns |= (1 << ns);
- res_close();
+ res_close_internal();
goto next_ns;
}
connected = 1;
if (send(s, (char*)buf, buflen, 0) != buflen) {
Perror(stderr, "send", errno);
badns |= (1 << ns);
- res_close();
+ res_close_internal();
goto next_ns;
}
} else {
!= buflen) {
Aerror(stderr, "sendto", errno, *nsap);
badns |= (1 << ns);
- res_close();
+ res_close_internal();
goto next_ns;
}
}
wait:
if (s < 0 || s >= FD_SETSIZE) {
Perror(stderr, "s out-of-bounds", EMFILE);
- res_close();
+ res_close_internal();
goto next_ns;
}
pfd[0].fd = s;
if (errno == EINTR)
goto wait;
Perror(stderr, "poll", errno);
- res_close();
+ res_close_internal();
goto next_ns;
}
if (n == 0) {
Dprint(_res.options & RES_DEBUG,
(stdout, ";; timeout\n"));
gotsomewhere = 1;
- res_close();
+ res_close_internal();
goto next_ns;
}
__set_errno (0);
(struct sockaddr *)&from, &fromlen);
if (resplen <= 0) {
Perror(stderr, "recvfrom", errno);
- res_close();
+ res_close_internal();
goto next_ns;
}
gotsomewhere = 1;
resplen));
terrno = EMSGSIZE;
badns |= (1 << ns);
- res_close();
+ res_close_internal();
goto next_ns;
}
if (hp->id != anhp->id) {
(stdout, "server rejected query:\n"),
ans, (resplen>anssiz)?anssiz:resplen);
badns |= (1 << ns);
- res_close();
+ res_close_internal();
/* don't retry if called from dig */
if (!_res.pfcode)
goto next_ns;
Dprint(_res.options & RES_DEBUG,
(stdout, ";; truncated answer\n"));
v_circuit = 1;
- res_close();
+ res_close_internal();
goto same_ns;
}
} /*if vc/dg*/
*/
if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
!(_res.options & RES_STAYOPEN)) {
- res_close();
+ res_close_internal();
}
if (Rhook) {
int done = 0, loops = 0;
done = 1;
break;
case res_nextns:
- res_close();
+ res_close_internal();
goto next_ns;
case res_modified:
/* give the hook another try */
case res_error:
/*FALLTHROUGH*/
default:
- return (-1);
+ goto and_out;
}
} while (!done);
}
- return (resplen);
+ result = resplen;
+ goto and_out;
next_ns: ;
} /*foreach ns*/
} /*foreach retry*/
- res_close();
+ res_close_internal();
if (!v_circuit) {
if (!gotsomewhere)
__set_errno (ECONNREFUSED); /* no nameservers found */
__set_errno (ETIMEDOUT); /* no answer obtained */
} else
__set_errno (terrno);
- return (-1);
+
+ and_out:
+ __libc_lock_unlock (lock);
+
+ return result;
}
/*
*
* This routine is not expected to be user visible.
*/
-void
-res_close()
+static void
+res_close_internal()
{
if (s >= 0) {
(void) close(s);
}
}
+void
+res_close ()
+{
+ __libc_lock_lock (lock);
+ res_close_internal ();
+ __libc_lock_unlock (lock);
+}
+
#ifdef ultrix
/* ultrix 4.0 had some icky packaging in its libc.a. alias for it here.
* there is more gunk of this kind over in res_debug.c.