?? namecachemain.c
字號:
signal(sig, SIG_IGN);}#else/* This thread waits for TERM and INT signals, and when they are found, sets the shutdown_flag */void* sig_handler_th(void* arg) { DNSIO *pdnsio = glob_pdnsio; sigset_t signal_set; int sig; /* we loop forever (and the main thread does not join() on this thread) because under GNU Pth signal blocking doesn't seem to work; a signal issued when no sigwait() is waiting for it always terminates the process... So we leave this thread to sigwait() till the process' exit. */ for(;;) { /* wait for these signal (they are all already blocked) */ sigemptyset(&signal_set); sigaddset(&signal_set, SIGTERM); sigaddset(&signal_set, SIGINT); sigwait(&signal_set, &sig); /* here we've caught a signal! */ pthread_mutex_lock(&pdnsio->mutex);#ifdef DEBUG KadC_log("Signal %d caught, shutdown_flag set to 1\n", sig);#endif pdnsio->shutdown_flag = 1; pthread_mutex_unlock(&pdnsio->mutex); } return NULL;}#endifint main(int ac, char *av[]) { char *kadcinifile = NULL; int leafmode = 1; /* default: leaf mode */ KadC_status kcs; processing_thread_params ptp = {0}; /* don't forget to init to all 0's... */ pthread_t udprecv; pthread_t proc; pthread_t publish; char c; DNSIO dnsio = {0}; KadCcontext kcc = {0}; int status; unsigned long int ip;#ifndef __WIN32__ char *user = NULL; char *group = NULL;#endif#ifndef OLD_STYLE_SIGNAL sigset_t signal_set; pthread_t sig_thread;#endif KadC_log("namecache - KadC library version: %d.%d.%d\n", KadC_version.major, KadC_version.minor, KadC_version.patchlevel); dnsio.mutex = mutex_initializer; glob_pdnsio = &dnsio; ptp.cache_maxentries = -1; dnsio.port = DNS_PORT; /* default */#ifndef __WIN32__ /* if UNIX */ while( (c = getopt( ac, av, "k:c:t:s:d:li:p:u:g:h")) != EOF ) {#else while( (c = getopt( ac, av, "k:c:t:s:d:li:p:h")) != EOF ) {#endif switch(c) { case 'k': kadcinifile = optarg; break; case 'c': ptp.cache_maxentries = atoi(optarg); break; case 't': if(ptp.ntlpd >= arraysize(ptp.tlpd)) { KadC_log("Can't handle more than %d \"-t\" options\n", arraysize(ptp.tlpd)); exit(1); } ptp.tlpd[ptp.ntlpd++] = optarg; break; case 's': if(dnsio.nupstream >= arraysize(dnsio.upstream)) { KadC_log("Can't specify more than %d upstream servers with \"-s\" options\n", arraysize(dnsio.upstream)); exit(1); } ip = inet_addr(optarg); if(ip == -1) { KadC_log("Invalid IP address %s in \"-s\" option\n", optarg); exit(1); } dnsio.upstream[dnsio.nupstream++] = ntohl(ip); break; case 'd': if(ptp.nmy_pseudo >= arraysize(ptp.my_pseudo)) { KadC_log("Can't handle more than %d \"-d\" options\n", arraysize(ptp.my_pseudo)); exit(1); } ptp.my_pseudo[ptp.nmy_pseudo++] = optarg; break;/* case 'l': leafmode = 1; break; */ case 'i': /* IP address to bind to */ ip = inet_addr(optarg); if(ip == -1) { KadC_log("Invalid IP address %s in \"-b\" option\n", optarg); exit(1); } dnsio.ip = ntohl(ip); break; case 'p': /* UDP port to bind to */ dnsio.port = atoi(optarg); break;#ifndef __WIN32__ case 'u': user = optarg; break; case 'g': group = optarg; break;#endif case 'h': default: usage(av[0]); return 1; } } /* a few consistency checks between options: */#if !defined(__WIN32__) && !defined(__CYGWIN__) if(user != NULL) { dnsio.uid = user2uid(user); if(dnsio.uid < 0) { KadC_log("Could not retrieve the UID of the user %s\n", user); return 1; } dnsio.gid = user2gid(user); if(dnsio.gid < 0) { KadC_log("Could not retrieve the GID of the user %s\n", user); return 1; } } else { /* "-u" option not present: no good if we are root! */ if(we_have_root_privilege()) { /* ###### FIXME: detect privilege here */ KadC_log("For security reasons, this program must drop root privilege after startup.\n"); KadC_log("Please use the \"-u\" option to define a non-privileged user (e.g., \"-u nobody\")\n"); return 1; } } if(group != NULL) { dnsio.gid = group2gid(group); if(dnsio.gid < 0) { KadC_log("Could not retrieve the GID of the group %s\n", group); return 1; } }#endif if(kadcinifile == NULL && ptp.ntlpd > 0) { KadC_log("Can't resolve queries via P2P for the %d pseudo-domains specified with \"-t\" options if a KadC ini file is not specified\n", ptp.ntlpd); usage(av[0]); return 1; } if(kadcinifile == NULL && ptp.nmy_pseudo != 0) { KadC_log("Can't publish via P2P with \"-d\" record associating names to IP addresses if a KadC ini file is not specified\n"); usage(av[0]); return 1; } if(ptp.ntlpd == 0 && dnsio.nupstream == 0) { KadC_log("Can't resolve queries either via DNS or P2P: at least one of -s or -t must be specified.\n"); usage(av[0]); return 1; } if(kadcinifile != NULL && ptp.ntlpd == 0 && ptp.nmy_pseudo == 0) { KadC_log("Warning: if we neither resolve (-t) nor publish (-p) via P2P, what's the point of specifying \"-k %s\" and running KadC?\n", kadcinifile); } if(ptp.cache_maxentries == -1) ptp.cache_maxentries = 4096; /* default */ /* if we are under WIN32, this will call WSAStartup() and put in place an atexit hook to WSACleanup() */ KadC_init_network(); /* open UDP socket and prepare UDP I/O */ dnsio.fifo = new_queue(8); /* not more than 8 outstanding requests */ assert(dnsio.fifo != NULL); if(udp_dns_init(&dnsio) < 1) { KadC_log("dns_udp_recv_thread reports socket error %d\n", dnsio.err); dnsio.fifo->destroy(dnsio.fifo); goto exit; }/* Drop root privileges, if under some flavour of *NIX */#if !defined(__WIN32__) && !defined(__CYGWIN__) if((status = droppriv(dnsio.uid, dnsio.gid)) != 0) { KadC_log("FATAL: Couldn't drop root privilege: "); if(status == -1) KadC_log("suppl. group IDs reset to non-root GID failed\n"); else if(status == -2) KadC_log("couldn't change to non-privileged GID %d\n", dnsio.gid); else if(status == -3) KadC_log("couldn't change to non-root UID %d\n", dnsio.uid); else if(status == -4) KadC_log("once non-root, setuid(0) managed to restore root UID!\n"); exit(1); }#endif/* Install signal handlers */#ifdef OLD_STYLE_SIGNAL signal(SIGTERM, sighandler); /* for the TERM signal (15, default for kill command)... */ signal(SIGINT, sighandler); /* .. the INT signal... (Ctrl-C hit on keyboard) */#else /* block signals we'll wait for */ sigemptyset(&signal_set); sigaddset(&signal_set, SIGTERM); sigaddset(&signal_set, SIGINT);#ifdef __WIN32__ sigaddset(&signal_set, SIGBREAK);#endif pthread_sigmask(SIG_BLOCK, &signal_set, NULL); /* create the signal handling thread */ pthread_create(&sig_thread, NULL, sig_handler_th, NULL);#endif/* Start KadC engine, if the -k option was present */ if(kadcinifile != NULL) { kcc = KadC_start(kadcinifile, leafmode, 0); if(kcc.s != KADC_OK) { KadC_log("KadC_start(%s, %d) returned error %d:\n", kadcinifile, leafmode, kcc.s); KadC_log("%s %s", kcc.errmsg1, kcc.errmsg2); return 2; } KadC_log("Our hash ID: %s "); KadC_int128flog(stdout, KadC_getourhashID(&kcc)); KadC_log("\nour UDP port: %u, our TCP port: %u\n", KadC_getourUDPport(&kcc), KadC_getourTCPport(&kcc)); } /* spawn the UDP init & listener loop thread */ pthread_create(&udprecv, NULL, dns_udp_recv_thread, &dnsio); /* go to process requests posted by UDP listener to pdnsio->fifo, spawning threads as needed, and send UDP replies with sendto() to pdnsio->fd */ ptp.pkcc = &kcc; ptp.pdnsio = &dnsio; /* create the pending questions table - ID is significant! */ ptp.pending_q_rbt = rbt_new((rbtcomp *)&DNSpacket_qi_lt, (rbtcomp *)&DNSpacket_qi_eq); assert(ptp.pending_q_rbt != NULL); /* create the raw_qa cache. ID is NOT significant */ ptp.cache_q_rbt = rbt_new((rbtcomp *)&DNSpacket_q_lt, (rbtcomp *)&DNSpacket_q_eq); assert(ptp.cache_q_rbt != NULL); ptp.mutex = mutex_initializer; /* start the processing thread, which reads incoming DNS data from FIFO queue */ pthread_create(&proc, NULL, processing_thread, &ptp); /* start the publishing thread, which every two hours republishes records for our domain names */ pthread_create(&publish, NULL, publishing_thread, &ptp); ConsoleLoop(&ptp); KadC_log("Shutting down, please wait...\n");/* sig_thread never returns (see comments in processing_thread() ).#ifndef OLD_STYLE_SIGNAL pthread_join(sig_thread, NULL);#endif */ pthread_join(publish, NULL); pthread_join(proc, NULL); pthread_mutex_destroy(&ptp.mutex); pthread_join(udprecv, NULL); pthread_mutex_destroy(&dnsio.mutex); status = qa_rbt_destroy(ptp.cache_q_rbt, 1); /* also destroy data */ assert(status == 0); status = qa_rbt_destroy(ptp.pending_q_rbt, 1); /* also destroy data */ assert(status == 0); dnsio.fifo->destroy(dnsio.fifo); /* destroy queue used to communicate with udprecv */ if(kadcinifile != NULL) { kcs = KadC_stop(&kcc); if(kcs != KADC_OK) { KadC_log("KadC_stop(&kcc) returned error %d:\n", kcc.s); KadC_log("%s %s", kcc.errmsg1, kcc.errmsg2); return 3; } }exit: KadC_list_outstanding_mallocs(10); return 0;}/* converts "4.3.2.1.in-addr.arpa" into the IP address 1.2.3.4 */unsigned long int reverse_inet_addr(char *s) { unsigned int b1, b2, b3, b4; char *p; int n; if(s == NULL) return -1; n = sscanf(s, "%u.%u.%u.%u.in-addr.arpa%s", &b4, &b3, &b2, &b1, p); if(n<4) return -1; if(n == 5 && strcmp(p, ".") != 0) return -1; return(b1<<24) + (b2<<16) + (b3<<8) + b4;}/* we are authoritative: - for PTR queries resolving to an address on some interface; the proper answer is "cachehost.cachedomain", replied immedately - for A queries relative to our pseudo-domain the proper answer is our external IP, replied immediately - for A queries under some tlpd the proper answer is a KadC search, replied later */static void ConsoleLoop(processing_thread_params *pptp) { for(;;){ int sf; pthread_mutex_lock(&pptp->pdnsio->mutex); /* \\\\\\ LOCK \\\\\\ */ sf = pptp->pdnsio->shutdown_flag; pthread_mutex_unlock(&pptp->pdnsio->mutex); /* ///// UNLOCK ///// */ if(sf) break;#if 0 /* suppress console input when not in debug mode */ KadCcontext *pkcc = pptp->pkcc; char line[80]; int linesize = sizeof(line)-1; char *s; int fwstatus = KadC_getfwstatus(pkcc); KadC_log("%4d/%4d%s ", KadC_getnknodes(pkcc), KadC_getncontacts(pkcc), (fwstatus>0 ? (fwstatus>1 ? ">" : "]") : "?")); s = KadC_getsn(line, linesize); if(s == NULL) break;#else /* KadC_log("."); */ millisleep(1000);#endif }}/* create an entry in the pending queries rbt, unless already there This is the single point where raw_qa objects are created. They are then converted in cached qa's in the processing thread by adding the reply, when it arrives. */static int create_pending_entry(processing_thread_params *pptp, DNSpacket *pdnp, void *threadcode(void *)) { void *iter; rbt_StatusEnum rbt_status = rbt_find(pptp->pending_q_rbt, pdnp, &iter); if(rbt_status == RBT_STATUS_KEY_NOT_FOUND) { /* this is the only place where a raw_qa is created */ raw_qa *pending_qa = calloc(1, sizeof(raw_qa)); assert(pending_qa != NULL); pending_qa->q = pdnp; pending_qa->a = NULL; /* answer is void, of course */ pending_qa->last_accessed = time(NULL); /* informational, actually unused in pending_q_rbt */ pending_qa->expiry = pending_qa->last_accessed + 300; pending_qa->being_refreshed = 0; /* unused in pending_q_rbt */ pending_qa->mutex = mutex_initializer; pending_qa->pptp = pptp; rbt_status = rbt_insert(pptp->pending_q_rbt, pending_qa->q, pending_qa, 0); assert(rbt_status == RBT_STATUS_OK); /* can't be already there now... */#ifdef VERBOSE_DEBUG KadC_log("create_pending_entry() created a pending_query entry \n");#endif if(threadcode != NULL) {#ifdef DEBUG KadC_log("create_pending_entry() also started a p2pquery thread\n");#endif pending_qa->isdetached = 1; pthread_create(&pending_qa->thread, NULL, threadcode, pending_qa);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -