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

📄 event.c

📁 adns for unix/linux, adns-1.3.tar.gz
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * event.c * - event loop core * - TCP connection management * - user-visible check/wait and event-loop-related functions *//* *  This file is part of adns, which is *    Copyright (C) 1997-2000,2003,2006  Ian Jackson *    Copyright (C) 1999-2000,2003,2006  Tony Finch *    Copyright (C) 1991 Massachusetts Institute of Technology *  (See the file INSTALL for full details.) *   *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *   *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. *   *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software Foundation, *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#include <errno.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/time.h>#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "internal.h"#include "tvarith.h"/* TCP connection management. */static void tcp_close(adns_state ads) {  int serv;    serv= ads->tcpserver;  close(ads->tcpsocket);  ads->tcpsocket= -1;  ads->tcprecv.used= ads->tcprecv_skip= ads->tcpsend.used= 0;}void adns__tcp_broken(adns_state ads, const char *what, const char *why) {  int serv;  adns_query qu;    assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);  serv= ads->tcpserver;  if (what) adns__warn(ads,serv,0,"TCP connection failed: %s: %s",what,why);  if (ads->tcpstate == server_connecting) {    /* Counts as a retry for all the queries waiting for TCP. */    for (qu= ads->tcpw.head; qu; qu= qu->next)      qu->retries++;  }  tcp_close(ads);  ads->tcpstate= server_broken;  ads->tcpserver= (serv+1)%ads->nservers;}static void tcp_connected(adns_state ads, struct timeval now) {  adns_query qu, nqu;    adns__debug(ads,ads->tcpserver,0,"TCP connected");  ads->tcpstate= server_ok;  for (qu= ads->tcpw.head; qu && ads->tcpstate == server_ok; qu= nqu) {    nqu= qu->next;    assert(qu->state == query_tcpw);    adns__querysend_tcp(qu,now);  }}static void tcp_broken_events(adns_state ads) {  adns_query qu, nqu;    assert(ads->tcpstate == server_broken);  for (qu= ads->tcpw.head; qu; qu= nqu) {    nqu= qu->next;    assert(qu->state == query_tcpw);    if (qu->retries > ads->nservers) {      LIST_UNLINK(ads->tcpw,qu);      adns__query_fail(qu,adns_s_allservfail);    }  }  ads->tcpstate= server_disconnected;}void adns__tcp_tryconnect(adns_state ads, struct timeval now) {  int r, fd, tries;  struct sockaddr_in addr;  struct protoent *proto;  for (tries=0; tries<ads->nservers; tries++) {    switch (ads->tcpstate) {    case server_connecting:    case server_ok:    case server_broken:      return;    case server_disconnected:      break;    default:      abort();    }        assert(!ads->tcpsend.used);    assert(!ads->tcprecv.used);    assert(!ads->tcprecv_skip);    proto= getprotobyname("tcp");    if (!proto) {      adns__diag(ads,-1,0,"unable to find protocol no. for TCP !");      return;    }    fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);    if (fd<0) {      adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno));      return;    }    r= adns__setnonblock(ads,fd);    if (r) {      adns__diag(ads,-1,0,"cannot make TCP socket nonblocking:"		 " %s",strerror(r));      close(fd);      return;    }    memset(&addr,0,sizeof(addr));    addr.sin_family= AF_INET;    addr.sin_port= htons(DNS_PORT);    addr.sin_addr= ads->servers[ads->tcpserver].addr;    r= connect(fd,(const struct sockaddr*)&addr,sizeof(addr));    ads->tcpsocket= fd;    ads->tcpstate= server_connecting;    if (r==0) { tcp_connected(ads,now); return; }    if (errno == EWOULDBLOCK || errno == EINPROGRESS) {      ads->tcptimeout= now;      timevaladd(&ads->tcptimeout,TCPCONNMS);      return;    }    adns__tcp_broken(ads,"connect",strerror(errno));    tcp_broken_events(ads);  }}/* Timeout handling functions. */void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,			     struct timeval *tv_buf) {  const struct timeval *now;  int r;  now= *now_io;  if (now) return;  r= gettimeofday(tv_buf,0); if (!r) { *now_io= tv_buf; return; }  adns__diag(ads,-1,0,"gettimeofday failed: %s",strerror(errno));  adns_globalsystemfailure(ads);  return;}static void inter_immed(struct timeval **tv_io, struct timeval *tvbuf) {  struct timeval *rbuf;  if (!tv_io) return;  rbuf= *tv_io;  if (!rbuf) { *tv_io= rbuf= tvbuf; }  timerclear(rbuf);}    static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,			struct timeval maxto) {  struct timeval *rbuf;  if (!tv_io) return;  rbuf= *tv_io;  if (!rbuf) {    *tvbuf= maxto; *tv_io= tvbuf;  } else {    if (timercmp(rbuf,&maxto,>)) *rbuf= maxto;  }/*fprintf(stderr,"inter_maxto maxto=%ld.%06ld result=%ld.%06ld\n",	maxto.tv_sec,maxto.tv_usec,(**tv_io).tv_sec,(**tv_io).tv_usec);*/}static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf,			   struct timeval now, struct timeval maxtime) {  /* tv_io may be 0 */  ldiv_t dr;/*fprintf(stderr,"inter_maxtoabs now=%ld.%06ld maxtime=%ld.%06ld\n",	now.tv_sec,now.tv_usec,maxtime.tv_sec,maxtime.tv_usec);*/  if (!tv_io) return;  maxtime.tv_sec -= (now.tv_sec+2);  maxtime.tv_usec -= (now.tv_usec-2000000);  dr= ldiv(maxtime.tv_usec,1000000);  maxtime.tv_sec += dr.quot;  maxtime.tv_usec -= dr.quot*1000000;  if (maxtime.tv_sec<0) timerclear(&maxtime);  inter_maxto(tv_io,tvbuf,maxtime);}static void timeouts_queue(adns_state ads, int act,			   struct timeval **tv_io, struct timeval *tvbuf,			   struct timeval now, struct query_queue *queue) {  adns_query qu, nqu;    for (qu= queue->head; qu; qu= nqu) {    nqu= qu->next;    if (!timercmp(&now,&qu->timeout,>)) {      inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);    } else {      if (!act) { inter_immed(tv_io,tvbuf); return; }      LIST_UNLINK(*queue,qu);      if (qu->state != query_tosend) {	adns__query_fail(qu,adns_s_timeout);      } else {	adns__query_send(qu,now);      }      nqu= queue->head;    }  }}static void tcp_events(adns_state ads, int act,		       struct timeval **tv_io, struct timeval *tvbuf,		       struct timeval now) {  for (;;) {    switch (ads->tcpstate) {    case server_broken:      if (!act) { inter_immed(tv_io,tvbuf); return; }      tcp_broken_events(ads);    case server_disconnected: /* fall through */      if (!ads->tcpw.head) return;      if (!act) { inter_immed(tv_io,tvbuf); return; }      adns__tcp_tryconnect(ads,now);      break;    case server_ok:      if (ads->tcpw.head) return;      if (!ads->tcptimeout.tv_sec) {	assert(!ads->tcptimeout.tv_usec);	ads->tcptimeout= now;	timevaladd(&ads->tcptimeout,TCPIDLEMS);      }    case server_connecting: /* fall through */      if (!act || !timercmp(&now,&ads->tcptimeout,>)) {	inter_maxtoabs(tv_io,tvbuf,now,ads->tcptimeout);	return;      } {	/* TCP timeout has happened */	switch (ads->tcpstate) {	case server_connecting: /* failed to connect */	  adns__tcp_broken(ads,"unable to make connection","timed out");	  break;	case server_ok: /* idle timeout */	  tcp_close(ads);	  ads->tcpstate= server_disconnected;	  return;	default:	  abort();	}      }      break;    default:      abort();    }  }  return;}void adns__timeouts(adns_state ads, int act,		    struct timeval **tv_io, struct timeval *tvbuf,		    struct timeval now) {  timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->udpw);  timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->tcpw);  tcp_events(ads,act,tv_io,tvbuf,now);}void adns_firsttimeout(adns_state ads,		       struct timeval **tv_io, struct timeval *tvbuf,		       struct timeval now) {  adns__consistency(ads,0,cc_entex);  adns__timeouts(ads, 0, tv_io,tvbuf, now);  adns__consistency(ads,0,cc_entex);}void adns_processtimeouts(adns_state ads, const struct timeval *now) {  struct timeval tv_buf;  adns__consistency(ads,0,cc_entex);  adns__must_gettimeofday(ads,&now,&tv_buf);  if (now) adns__timeouts(ads, 1, 0,0, *now);  adns__consistency(ads,0,cc_entex);}/* fd handling functions.  These are the top-level of the real work of * reception and often transmission. */int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {  /* Returns the number of entries filled in.  Always zeroes revents. */  assert(MAX_POLLFDS==2);  pollfds_buf[0].fd= ads->udpsocket;  pollfds_buf[0].events= POLLIN;  pollfds_buf[0].revents= 0;  switch (ads->tcpstate) {  case server_disconnected:  case server_broken:    return 1;  case server_connecting:    pollfds_buf[1].events= POLLOUT;    break;  case server_ok:    pollfds_buf[1].events=      ads->tcpsend.used ? POLLIN|POLLOUT|POLLPRI : POLLIN|POLLPRI;    break;  default:    abort();  }  pollfds_buf[1].fd= ads->tcpsocket;  return 2;}int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {  int want, dgramlen, r, udpaddrlen, serv, old_skip;  byte udpbuf[DNS_MAXUDP];  struct sockaddr_in udpaddr;    adns__consistency(ads,0,cc_entex);  switch (ads->tcpstate) {  case server_disconnected:  case server_broken:  case server_connecting:    break;  case server_ok:    if (fd != ads->tcpsocket) break;    assert(!ads->tcprecv_skip);    do {      if (ads->tcprecv.used >= ads->tcprecv_skip+2) {	dgramlen= ((ads->tcprecv.buf[ads->tcprecv_skip]<<8) |	           ads->tcprecv.buf[ads->tcprecv_skip+1]);	if (ads->tcprecv.used >= ads->tcprecv_skip+2+dgramlen) {	  old_skip= ads->tcprecv_skip;	  ads->tcprecv_skip += 2+dgramlen;	  adns__procdgram(ads, ads->tcprecv.buf+old_skip+2,			  dgramlen, ads->tcpserver, 1,*now);	  continue;	} else {	  want= 2+dgramlen;	}      } else {	want= 2;      }      ads->tcprecv.used -= ads->tcprecv_skip;      memmove(ads->tcprecv.buf, ads->tcprecv.buf+ads->tcprecv_skip,	      ads->tcprecv.used);

⌨️ 快捷键说明

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