⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 res_send.c

📁 DHCP服务器源码
💻 C
📖 第 1 页 / 共 2 页
字号:
				       (stdout, ";; undersized: %d\n", len));				terrno = ISC_R_NOSPACE;				badns |= (1 << ns);				res_nclose(statp);				goto next_ns;			}			cp = (u_char *)ans;			while (len != 0 &&			       (n = read(statp->_sock,					 (char *)cp, (unsigned)len))			       > 0) {				cp += n;				len -= n;			}			if (n <= 0) {				terrno = uerr2isc (errno);				Perror(statp, stderr, "read(vc)", errno);				res_nclose(statp);				goto next_ns;			}			if (truncated) {				/*				 * Flush rest of answer				 * so connection stays in synch.				 */				anhp->tc = 1;				len = resplen - anssiz;				while (len != 0) {					char junk[PACKETSZ];					n = (len > sizeof(junk)					     ? sizeof(junk)					     : len);					n = read(statp->_sock,						 junk, (unsigned)n);					if (n > 0)						len -= n;					else						break;				}			}			/*			 * The calling applicating has bailed out of			 * a previous call and failed to arrange to have			 * the circuit closed or the server has got			 * itself confused. Anyway drop the packet and			 * wait for the correct one.			 */			if (hp->id != anhp->id) {				DprintQ((statp->options & RES_DEBUG) ||					(statp->pfcode & RES_PRF_REPLY),					(stdout,					 ";; old answer (unexpected):\n"),					ans, (resplen>anssiz)?anssiz:resplen);				goto read_len;			}		} else {			/*			 * Use datagrams.			 */			int start, timeout, finish;			fd_set dsmask;			struct sockaddr_in from;			SOCKLEN_T fromlen;			int seconds;			if (statp->_sock < 0 ||			    (statp->_flags & RES_F_VC) != 0) {				if ((statp->_flags & RES_F_VC) != 0)					res_nclose(statp);				statp->_sock = socket(PF_INET, SOCK_DGRAM, 0);				if (statp->_sock < 0 ||				    statp->_sock > highestFD) {#ifndef CAN_RECONNECT bad_dg_sock:#endif					terrno = uerr2isc (errno);					Perror(statp, stderr,					       "socket(dg)", errno);					return terrno;				}				statp->_flags &= ~RES_F_CONN;			}#ifndef CANNOT_CONNECT_DGRAM			/*			 * On a 4.3BSD+ machine (client and server,			 * actually), sending to a nameserver datagram			 * port with no nameserver will cause an			 * ICMP port unreachable message to be returned.			 * If our datagram socket is "connected" to the			 * server, we get an ECONNREFUSED error on the next			 * socket operation, and select returns if the			 * error message is received.  We can thus detect			 * the absence of a nameserver without timing out.			 * If we have sent queries to at least two servers,			 * however, we don't want to remain connected,			 * as we wish to receive answers from the first			 * server to respond.			 */			if (statp->nscount == 1 || (try == 0 && ns == 0)) {				/*				 * Connect only if we are sure we won't				 * receive a response from another server.				 */				if ((statp->_flags & RES_F_CONN) == 0) {					if (connect(statp->_sock,						    (struct sockaddr *)nsap,						    sizeof *nsap) < 0) {						Aerror(statp, stderr,						       "connect(dg)",						       errno, *nsap);						badns |= (1 << ns);						res_nclose(statp);						goto next_ns;					}					statp->_flags |= RES_F_CONN;				}                              if (send(statp->_sock,				       (const char*)buf, (unsigned)buflen, 0)				  != buflen) {					Perror(statp, stderr, "send", errno);					badns |= (1 << ns);					res_nclose(statp);					goto next_ns;				}			} else {				/*				 * Disconnect if we want to listen				 * for responses from more than one server.				 */				if ((statp->_flags & RES_F_CONN) != 0) {#ifdef CAN_RECONNECT					struct sockaddr_in no_addr;					no_addr.sin_family = AF_INET;					no_addr.sin_addr.s_addr = INADDR_ANY;					no_addr.sin_port = 0;					(void) connect(statp->_sock,						       (struct sockaddr *)						        &no_addr,						       sizeof no_addr);#else					struct sockaddr_in local_addr;					SOCKLEN_T len;					int result, s1;					len = sizeof(local_addr);					s1 = socket(PF_INET, SOCK_DGRAM, 0);					result = getsockname(statp->_sock,						(struct sockaddr *)&local_addr,							     &len);					if (s1 < 0)						goto bad_dg_sock;					(void) dup2(s1, statp->_sock);					(void) close(s1);					if (result == 0) {						/*						 * Attempt to rebind to old						 * port.  Note connected socket						 * has an sin_addr set.						 */						local_addr.sin_addr.s_addr =							htonl(0);						(void)bind(statp->_sock,							   (struct sockaddr *)							   &local_addr,							   (unsigned)len);					}					Dprint(statp->options & RES_DEBUG,					       (stdout, ";; new DG socket\n"));#endif /* CAN_RECONNECT */					statp->_flags &= ~RES_F_CONN;					errno = 0;				}#endif /* !CANNOT_CONNECT_DGRAM */				if (sendto(statp->_sock,					   (const char *)buf, buflen, 0,					   (struct sockaddr *)nsap,					   sizeof *nsap)				    != buflen) {					Aerror(statp, stderr, "sendto", errno, *nsap);					badns |= (1 << ns);					res_nclose(statp);					goto next_ns;				}#ifndef CANNOT_CONNECT_DGRAM			}#endif /* !CANNOT_CONNECT_DGRAM */			if (statp->_sock < 0 || statp->_sock > highestFD) {				Perror(statp, stderr,				       "fd out-of-bounds", EMFILE);				res_nclose(statp);				goto next_ns;			}			/*			 * Wait for reply			 */			seconds = (statp->retrans << try);			if (try > 0)				seconds /= statp->nscount;			if (seconds <= 0)				seconds = 1;			start = cur_time;			timeout = seconds;			finish = start + timeout; wait:			FD_ZERO(&dsmask);			FD_SET(statp->_sock, &dsmask);			{				struct timeval t;				t.tv_sec = timeout;				t.tv_usec = 0;				n = select(statp->_sock + 1,					   &dsmask, NULL, NULL, &t);			}			if (n == 0) {				Dprint(statp->options & RES_DEBUG,				       (stdout, ";; timeout\n"));				gotsomewhere = 1;				goto next_ns;			}			if (n < 0) {				if (errno == EINTR) {					if (finish >= cur_time) {						timeout = finish - cur_time;						goto wait;					}				}				Perror(statp, stderr, "select", errno);				res_nclose(statp);				goto next_ns;			}			errno = 0;			fromlen = sizeof(struct sockaddr_in);			resplen = recvfrom(statp->_sock,					   (char *)ans, anssiz, 0,					   (struct sockaddr *)&from, &fromlen);			if (resplen <= 0) {				Perror(statp, stderr, "recvfrom", errno);				res_nclose(statp);				goto next_ns;			}			gotsomewhere = 1;			if (resplen < HFIXEDSZ) {				/*				 * Undersized message.				 */				Dprint(statp->options & RES_DEBUG,				       (stdout, ";; undersized: %d\n",					resplen));				terrno = ISC_R_NOSPACE;				badns |= (1 << ns);				res_nclose(statp);				goto next_ns;			}			if (hp->id != anhp->id) {				/*				 * response from old query, ignore it.				 * XXX - potential security hazard could				 *	 be detected here.				 */				DprintQ((statp->options & RES_DEBUG) ||					(statp->pfcode & RES_PRF_REPLY),					(stdout, ";; old answer:\n"),					ans, (resplen>anssiz)?anssiz:resplen);				goto wait;			}#ifdef CHECK_SRVR_ADDR			if (!(statp->options & RES_INSECURE1) &&			    !res_ourserver_p(statp, &from)) {				/*				 * response from wrong server? ignore it.				 * XXX - potential security hazard could				 *	 be detected here.				 */				DprintQ((statp->options & RES_DEBUG) ||					(statp->pfcode & RES_PRF_REPLY),					(stdout, ";; not our server:\n"),					ans, (resplen>anssiz)?anssiz:resplen);				goto wait;			}#endif			if (!(statp->options & RES_INSECURE2) &&			    !res_queriesmatch((u_char *)buf,					      ((u_char *)buf) + buflen,					      (u_char *)ans,					      ((u_char *)ans) + anssiz)) {				/*				 * response contains wrong query? ignore it.				 * XXX - potential security hazard could				 *	 be detected here.				 */				DprintQ((statp->options & RES_DEBUG) ||					(statp->pfcode & RES_PRF_REPLY),					(stdout, ";; wrong query name:\n"),					ans, (resplen>anssiz)?anssiz:resplen);				goto wait;			}			if (anhp->rcode == SERVFAIL ||			    anhp->rcode == NOTIMP ||			    anhp->rcode == REFUSED) {				DprintQ(statp->options & RES_DEBUG,					(stdout, "server rejected query:\n"),					ans, (resplen>anssiz)?anssiz:resplen);				badns |= (1 << ns);				res_nclose(statp);				/* don't retry if called from dig */				if (!statp->pfcode)					goto next_ns;			}			if (!(statp->options & RES_IGNTC) && anhp->tc) {				/*				 * get rest of answer;				 * use TCP with same server.				 */				Dprint(statp->options & RES_DEBUG,				       (stdout, ";; truncated answer\n"));				v_circuit = 1;				res_nclose(statp);				goto same_ns;			}		} /*if vc/dg*/		Dprint((statp->options & RES_DEBUG) ||		       ((statp->pfcode & RES_PRF_REPLY) &&			(statp->pfcode & RES_PRF_HEAD1)),		       (stdout, ";; got answer:\n"));		DprintQ((statp->options & RES_DEBUG) ||			(statp->pfcode & RES_PRF_REPLY),			(stdout, ""),			ans, (resplen>anssiz)?anssiz:resplen);		/*		 * If using virtual circuits, we assume that the first server		 * is preferred over the rest (i.e. it is on the local		 * machine) and only keep that one open.		 * If we have temporarily opened a virtual circuit,		 * or if we haven't been asked to keep a socket open,		 * close the socket.		 */		if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) ||		    !(statp->options & RES_STAYOPEN)) {			res_nclose(statp);		}		if (statp->rhook) {			int done = 0, loops = 0;			do {				res_sendhookact act;				act = (*statp->rhook)(nsap, buf, buflen,						      ans, anssiz, &resplen);				switch (act) {				case res_goahead:				case res_done:					done = 1;					break;				case res_nextns:					res_nclose(statp);					goto next_ns;				case res_modified:					/* give the hook another try */					if (++loops < 42) /*doug adams*/						break;					/*FALLTHROUGH*/				case res_error:					/*FALLTHROUGH*/				default:					return ISC_R_UNEXPECTED;				}			} while (!done);		}		*ansret = resplen;		return ISC_R_SUCCESS; next_ns: ;	   } /*foreach ns*/	} /*foreach retry*/	res_nclose(statp);	if (!v_circuit) {		if (!gotsomewhere)			terrno = ISC_R_CONNREFUSED;  /* no nameservers found */		else			errno = ISC_R_TIMEDOUT;	/* no answer obtained */	}	return terrno;}/* * This routine is for closing the socket if a virtual circuit is used and * the program wants to close it.  This provides support for endhostent() * which expects to close the socket. * * This routine is not expected to be user visible. */voidres_nclose(res_state statp) {	if (statp->_sock >= 0) {		(void) close(statp->_sock);		statp->_sock = -1;		statp->_flags &= ~(RES_F_VC | RES_F_CONN);	}}/* Private */static intcmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) {	return ((a1->sin_family == a2->sin_family) &&		(a1->sin_port == a2->sin_port) &&		(a1->sin_addr.s_addr == a2->sin_addr.s_addr));}#ifdef NEED_PSELECT/* XXX needs to move to the porting library. */static intpselect(int nfds, void *rfds, void *wfds, void *efds,	struct timespec *tsp,	const sigset_t *sigmask){	struct timeval tv, *tvp;	sigset_t sigs;	int n;	if (tsp) {		tvp = &tv;		tv = evTimeVal(*tsp);	} else		tvp = NULL;	if (sigmask)		sigprocmask(SIG_SETMASK, sigmask, &sigs);	n = select(nfds, rfds, wfds, efds, tvp);	if (sigmask)		sigprocmask(SIG_SETMASK, &sigs, NULL);	if (tsp)		*tsp = evTimeSpec(tv);	return (n);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -