Esempio n. 1
0
/** handle is_signal events and see if signalled */
static void _getdns_handle_signal(struct _getdns_event* ev)
{
	DWORD ret;
	//log_assert(ev->is_signal && ev->hEvent);
	/* see if the event is signalled */
	ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */,
		0 /* return immediately */, 0 /* not alertable for IOcomple*/);
	if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) {
		log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s",
			wsa_strerror(WSAGetLastError()));
		return;
	}
	if(ret == WSA_WAIT_TIMEOUT) {
		/* not signalled */
		return;
	}

	/* reset the signal */
	if(!WSAResetEvent(ev->hEvent))
		log_err("getdns: WSAResetEvent failed: %s",
			wsa_strerror(WSAGetLastError()));
	/* do the callback (which may set the signal again) */
	fptr_ok(fptr_whitelist_event(ev->ev_callback));
	(*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg);
}
Esempio n. 2
0
/** open TCP socket to svr */
static int
open_svr(const char* svr, int udp)
{
	struct sockaddr_storage addr;
	socklen_t addrlen;
	int fd = -1;
	/* svr can be ip@port */
	memset(&addr, 0, sizeof(addr));
	if(!extstrtoaddr(svr, &addr, &addrlen)) {
		printf("fatal: bad server specs '%s'\n", svr);
		exit(1);
	}
	fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
		udp?SOCK_DGRAM:SOCK_STREAM, 0);
	if(fd == -1) {
#ifndef USE_WINSOCK
		perror("socket() error");
#else
		printf("socket: %s\n", wsa_strerror(WSAGetLastError()));
#endif
		exit(1);
	}
	if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
#ifndef USE_WINSOCK
		perror("connect() error");
#else
		printf("connect: %s\n", wsa_strerror(WSAGetLastError()));
#endif
		exit(1);
	}
	return fd;
}
Esempio n. 3
0
/**
 * The main function for the service.
 * Called by the services API when starting on windows in background.
 * Arguments could have been present in the string 'path'.
 * @param argc: nr args
 * @param argv: arg text.
 */
static void 
service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv))
{
	struct cfg* cfg = NULL;
	struct svr* svr = NULL;

	service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, 
		(LPHANDLER_FUNCTION)hdlr);
	if(!service_status_handle) {
		reportev("Could not RegisterServiceCtrlHandler");
		return;
	}
	
	service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	service_status.dwServiceSpecificExitCode = 0;

	/* we are now starting up */
	report_status(SERVICE_START_PENDING, NO_ERROR, 3000);
	if(!service_init(&svr, &cfg)) {
		reportev("Could not service_init");
		report_status(SERVICE_STOPPED, NO_ERROR, 0);
		return;
	}

	/* event that gets signalled when we want to quit */
	service_stop_event = WSACreateEvent();
	if(service_stop_event == WSA_INVALID_EVENT) {
		log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError()));
		reportev("Could not WSACreateEvent");
		report_status(SERVICE_STOPPED, NO_ERROR, 0);
		return;
	}
	if(!WSAResetEvent(service_stop_event)) {
		log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError()));
	}
	wsvc_setup_worker(svr->base);

	/* SetServiceStatus SERVICE_RUNNING;*/
	report_status(SERVICE_RUNNING, NO_ERROR, 0);
	verbose(VERB_QUERY, "winservice - init complete");
	
	/* register DHCP hook and perform first sweep */
	netlist_start(svr);

	/* daemon performs work */
	svr_service(svr);

	/* exit */
	verbose(VERB_ALGO, "winservice - cleanup.");
	report_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
	netlist_stop();
	wsvc_desetup_worker();
	service_deinit(svr, cfg);
	free(service_cfgfile);
	if(service_stop_event) (void)WSACloseEvent(service_stop_event);
	verbose(VERB_QUERY, "winservice - full stop");
	report_status(SERVICE_STOPPED, NO_ERROR, 0);
}
Esempio n. 4
0
/** contact the server with TCP connect */
static int
contact_server(const char* svr, struct config_file* cfg, int statuscmd)
{
	struct sockaddr_storage addr;
	socklen_t addrlen;
	int fd;
	/* use svr or the first config entry */
	if(!svr) {
		if(cfg->control_ifs)
			svr = cfg->control_ifs->str;
		else	svr = "127.0.0.1";
		/* config 0 addr (everything), means ask localhost */
		if(strcmp(svr, "0.0.0.0") == 0)
			svr = "127.0.0.1";
		else if(strcmp(svr, "::0") == 0 ||
			strcmp(svr, "0::0") == 0 ||
			strcmp(svr, "0::") == 0 ||
			strcmp(svr, "::") == 0)
			svr = "::1";
	}
	if(strchr(svr, '@')) {
		if(!extstrtoaddr(svr, &addr, &addrlen))
			fatal_exit("could not parse IP@port: %s", svr);
	} else {
		if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen))
			fatal_exit("could not parse IP: %s", svr);
	}
	fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET, 
		SOCK_STREAM, 0);
	if(fd == -1) {
#ifndef USE_WINSOCK
		fatal_exit("socket: %s", strerror(errno));
#else
		fatal_exit("socket: %s", wsa_strerror(WSAGetLastError()));
#endif
	}
	if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
		log_addr(0, "address", &addr, addrlen);
#ifndef USE_WINSOCK
		log_err("connect: %s", strerror(errno));
		if(errno == ECONNREFUSED && statuscmd) {
			printf("unbound is stopped\n");
			exit(3);
		}
#else
		log_err("connect: %s", wsa_strerror(WSAGetLastError()));
		if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) {
			printf("unbound is stopped\n");
			exit(3);
		}
#endif
		exit(1);
	}
	return fd;
}
Esempio n. 5
0
/** send out waiting packets */
static void
service_send(struct ringbuf* ring, struct timeval* now, sldns_buffer* pkt,
	struct sockaddr_storage* srv_addr, socklen_t srv_len)
{
	struct proxy* p;
	struct timeval tv;
	ssize_t sent;
	while(!ring_empty(ring) && 
		dl_tv_smaller(ring_peek_time(ring), now)) {
		/* this items needs to be sent out */
		if(!ring_pop(ring, pkt, &tv, &p))
			fatal_exit("ringbuf error: pop failed");
		verbose(1, "send out query %d.%6.6d", 
			(unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
		log_addr(1, "from client", &p->addr, p->addr_len);
		/* send it */
		sent = sendto(p->s, (void*)sldns_buffer_begin(pkt), 
			sldns_buffer_limit(pkt), 0, 
			(struct sockaddr*)srv_addr, srv_len);
		if(sent == -1) {
#ifndef USE_WINSOCK
			log_err("sendto: %s", strerror(errno));
#else
			log_err("sendto: %s", wsa_strerror(WSAGetLastError()));
#endif
		} else if(sent != (ssize_t)sldns_buffer_limit(pkt)) {
			log_err("sendto: partial send");
		}
		p->lastuse = *now;
		p->numsent++;
	}
}
Esempio n. 6
0
/** create context functionality, but no pipes */
static struct ub_ctx* ub_ctx_create_nopipe(void)
{
	struct ub_ctx* ctx;
	unsigned int seed;
#ifdef USE_WINSOCK
	int r;
	WSADATA wsa_data;
#endif
	
	log_init(NULL, 0, NULL); /* logs to stderr */
	log_ident_set("libunbound");
#ifdef USE_WINSOCK
	if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) {
		log_err("could not init winsock. WSAStartup: %s",
			wsa_strerror(r));
		return NULL;
	}
#endif
	verbosity = 0; /* errors only */
	checklock_start();
	ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx));
	if(!ctx) {
		errno = ENOMEM;
		return NULL;
	}
	alloc_init(&ctx->superalloc, NULL, 0);
	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid();
	if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) {
		seed = 0;
		ub_randfree(ctx->seed_rnd);
		free(ctx);
		errno = ENOMEM;
		return NULL;
	}
	seed = 0;
	lock_basic_init(&ctx->qqpipe_lock);
	lock_basic_init(&ctx->rrpipe_lock);
	lock_basic_init(&ctx->cfglock);
	ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
	if(!ctx->env) {
		ub_randfree(ctx->seed_rnd);
		free(ctx);
		errno = ENOMEM;
		return NULL;
	}
	ctx->env->cfg = config_create_forlib();
	if(!ctx->env->cfg) {
		free(ctx->env);
		ub_randfree(ctx->seed_rnd);
		free(ctx);
		errno = ENOMEM;
		return NULL;
	}
	ctx->env->alloc = &ctx->superalloc;
	ctx->env->worker = NULL;
	ctx->env->need_to_validate = 0;
	modstack_init(&ctx->mods);
	rbtree_init(&ctx->queries, &context_query_cmp);
	return ctx;
}
Esempio n. 7
0
/** send new query for io */
static void
perfsend(struct perfinfo* info, size_t n, struct timeval* now)
{
	ssize_t r;
	r = sendto(info->io[n].fd, (void*)info->qlist_data[info->qlist_idx],
		info->qlist_len[info->qlist_idx], 0,
		(struct sockaddr*)&info->dest, info->destlen);
	/*log_hex("send", info->qlist_data[info->qlist_idx],
		info->qlist_len[info->qlist_idx]);*/
	if(r == -1) {
#ifndef USE_WINSOCK
		log_err("sendto: %s", strerror(errno));
#else
		log_err("sendto: %s", wsa_strerror(WSAGetLastError()));
#endif
	} else if(r != (ssize_t)info->qlist_len[info->qlist_idx]) {
		log_err("partial sendto");
	}
	info->qlist_idx = (info->qlist_idx+1) % info->qlist_size;
	info->numsent++;

	info->io[n].timeout.tv_sec = IO_TIMEOUT/1000;
	info->io[n].timeout.tv_usec = (IO_TIMEOUT%1000)*1000;
	perf_tv_add(&info->io[n].timeout, now);
}
Esempio n. 8
0
int tube_queue_item(struct tube* tube, uint8_t* msg, size_t len)
{
	struct tube_res_list* item = 
		(struct tube_res_list*)malloc(sizeof(*item));
	verbose(VERB_ALGO, "tube queue_item len %d", (int)len);
	if(!item) {
		free(msg);
		log_err("out of memory for async answer");
		return 0;
	}
	item->buf = msg;
	item->len = len;
	item->next = NULL;
	lock_basic_lock(&tube->res_lock);
	/* add at back of list, since the first one may be partially written */
	if(tube->res_last)
		tube->res_last->next = item;
	else    tube->res_list = item;
	tube->res_last = item;
	/* signal the eventhandle */
	if(!WSASetEvent(tube->event)) {
		log_err("WSASetEvent: %s", wsa_strerror(WSAGetLastError()));
	}
	lock_basic_unlock(&tube->res_lock);
	return 1;
}
/** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */
static int
remote_read(SSL* ssl, int fd, char* buf, size_t len)
{
	if(ssl) {
		int r;
		ERR_clear_error();
		if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) {
			if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
				/* EOF */
				return 0;
			}
			ssl_err("could not SSL_read");
		}
		buf[r] = 0;
	} else {
		ssize_t rr = recv(fd, buf, len-1, 0);
		if(rr <= 0) {
			if(rr == 0) {
				/* EOF */
				return 0;
			}
#ifndef USE_WINSOCK
			fatal_exit("could not recv: %s", strerror(errno));
#else
			fatal_exit("could not recv: %s", wsa_strerror(WSAGetLastError()));
#endif
		}
		buf[rr] = 0;
	}
	return 1;
}
Esempio n. 10
0
void tube_close_write(struct tube* ATTR_UNUSED(tube))
{
	verbose(VERB_ALGO, "tube close_write");
	/* wake up waiting reader with an empty queue */
	if(!WSASetEvent(tube->event)) {
		log_err("WSASetEvent: %s", wsa_strerror(WSAGetLastError()));
	}
}
Esempio n. 11
0
void tube_delete(struct tube* tube)
{
	if(!tube) return;
	tube_remove_bg_listen(tube);
	tube_remove_bg_write(tube);
	tube_close_read(tube);
	tube_close_write(tube);
	if(!WSACloseEvent(tube->event))
		log_err("WSACloseEvent: %s", wsa_strerror(WSAGetLastError()));
	lock_basic_destroy(&tube->res_lock);
	verbose(VERB_ALGO, "tube deleted");
	free(tube);
}
Esempio n. 12
0
/** setup perf test environment */
static void
perfsetup(struct perfinfo* info)
{
	size_t i;
	if(gettimeofday(&info->start, NULL) < 0)
		fatal_exit("gettimeofday: %s", strerror(errno));
	sig_info = info;
	if( signal(SIGINT, perf_sigh) == SIG_ERR || 
#ifdef SIGQUIT
		signal(SIGQUIT, perf_sigh) == SIG_ERR ||
#endif
#ifdef SIGHUP
		signal(SIGHUP, perf_sigh) == SIG_ERR ||
#endif
#ifdef SIGBREAK
		signal(SIGBREAK, perf_sigh) == SIG_ERR ||
#endif
		signal(SIGTERM, perf_sigh) == SIG_ERR)
		fatal_exit("could not bind to signal");
	info->io = (struct perfio*)calloc(sizeof(struct perfio), info->io_num);
	if(!info->io) fatal_exit("out of memory");
#ifndef S_SPLINT_S
	FD_ZERO(&info->rset);
#endif
	info->since = info->start;
	for(i=0; i<info->io_num; i++) {
		info->io[i].id = i;
		info->io[i].info = info;
		info->io[i].fd = socket(
			addr_is_ip6(&info->dest, info->destlen)?
			AF_INET6:AF_INET, SOCK_DGRAM, 0);
		if(info->io[i].fd == -1) {
#ifndef USE_WINSOCK
			fatal_exit("socket: %s", strerror(errno));
#else
			fatal_exit("socket: %s", 
				wsa_strerror(WSAGetLastError()));
#endif
		}
		if(info->io[i].fd > info->maxfd)
			info->maxfd = info->io[i].fd;
#ifndef S_SPLINT_S
		FD_SET(FD_SET_T info->io[i].fd, &info->rset);
		info->io[i].timeout.tv_usec = ((START_IO_INTERVAL*i)%1000)
						*1000;
		info->io[i].timeout.tv_sec = (START_IO_INTERVAL*i)/1000;
		perf_tv_add(&info->io[i].timeout, &info->since);
#endif
	}
}
Esempio n. 13
0
int _getdns_event_del(struct _getdns_event *ev)
{
	//verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", 
	//	ev, ev->added, ev->ev_fd, 
	//	(ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+
	//	(long long)ev->ev_timeout.tv_usec/1000:-1,
	//	(ev->ev_events&EV_READ)?" EV_READ":"",
	//	(ev->ev_events&EV_WRITE)?" EV_WRITE":"",
	//	(ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
	if(!ev->added)
		return 0;
	//log_assert(ev->added);
        if((ev->ev_events&EV_TIMEOUT))
                (void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node);
        if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
		//log_assert(ev->ev_base->max > 0);
		/* remove item and compact the list */
		ev->ev_base->items[ev->idx] = 
			ev->ev_base->items[ev->ev_base->max-1];
		ev->ev_base->items[ev->ev_base->max-1] = NULL;
		ev->ev_base->max--;
		if(ev->idx < ev->ev_base->max)
			ev->ev_base->items[ev->idx]->idx = ev->idx;
		zero_waitfor(ev->ev_base->waitfor, ev->hEvent);

		if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0)
			log_err("getdns: WSAEventSelect(disable) failed: %s",
				wsa_strerror(WSAGetLastError()));
		if(!WSACloseEvent(ev->hEvent))
			log_err("getdns: WSACloseEvent failed: %s",
				wsa_strerror(WSAGetLastError()));
	}
	ev->just_checked = 0;
        ev->added = 0;
        return 0;
}
Esempio n. 14
0
/** do proxy for one readable client */
static void
do_proxy(struct proxy* p, int retsock, sldns_buffer* pkt)
{
	int i;
	ssize_t r;
	for(i=0; i<TRIES_PER_SELECT; i++) {
		r = recv(p->s, (void*)sldns_buffer_begin(pkt), 
			sldns_buffer_capacity(pkt), 0);
		if(r == -1) {
#ifndef USE_WINSOCK
			if(errno == EAGAIN || errno == EINTR)
				return;
			log_err("recv: %s", strerror(errno));
#else
			if(WSAGetLastError() == WSAEINPROGRESS ||
				WSAGetLastError() == WSAEWOULDBLOCK)
				return;
			log_err("recv: %s", wsa_strerror(WSAGetLastError()));
#endif
			return;
		}
		sldns_buffer_set_limit(pkt, (size_t)r);
		log_addr(1, "return reply to client", &p->addr, p->addr_len);
		/* send reply back to the real client */
		p->numreturn++;
		r = sendto(retsock, (void*)sldns_buffer_begin(pkt), (size_t)r, 
			0, (struct sockaddr*)&p->addr, p->addr_len);
		if(r == -1) {
#ifndef USE_WINSOCK
			log_err("sendto: %s", strerror(errno));
#else
			log_err("sendto: %s", wsa_strerror(WSAGetLastError()));
#endif
		}
	}
}
Esempio n. 15
0
struct tube* tube_create(void)
{
	/* windows does not have forks like unix, so we only support
	 * threads on windows. And thus the pipe need only connect
	 * threads. We use a mutex and a list of datagrams. */
	struct tube* tube = (struct tube*)calloc(1, sizeof(*tube));
	if(!tube) {
		int err = errno;
		log_err("tube_create: out of memory");
		errno = err;
		return NULL;
	}
	tube->event = WSACreateEvent();
	if(tube->event == WSA_INVALID_EVENT) {
		free(tube);
		log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError()));
	}
	if(!WSAResetEvent(tube->event)) {
		log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError()));
	}
	lock_basic_init(&tube->res_lock);
	verbose(VERB_ALGO, "tube created");
	return tube;
}
Esempio n. 16
0
/** write to ssl or fd, fatalexit on error */
static void
remote_write(SSL* ssl, int fd, const char* buf, size_t len)
{
	if(ssl) {
		if(SSL_write(ssl, buf, (int)len) <= 0)
			ssl_err("could not SSL_write");
	} else {
		if(send(fd, buf, len, 0) < (ssize_t)len) {
#ifndef USE_WINSOCK
			fatal_exit("could not send: %s", strerror(errno));
#else
			fatal_exit("could not send: %s", wsa_strerror(WSAGetLastError()));
#endif
		}
	}
}
Esempio n. 17
0
/** find or else create proxy for this remote client */
static struct proxy*
find_create_proxy(struct sockaddr_storage* from, socklen_t from_len,
	fd_set* rorig, int* max, struct proxy** proxies, int serv_ip6,
	struct timeval* now, struct timeval* reuse_timeout)
{
	struct proxy* p;
	struct timeval t;
	for(p = *proxies; p; p = p->next) {
		if(sockaddr_cmp(from, from_len, &p->addr, p->addr_len)==0)
			return p;
	}
	/* possibly: reuse lapsed entries */
	for(p = *proxies; p; p = p->next) {
		if(p->numwait > p->numsent || p->numsent > p->numreturn)
			continue;
		t = *now;
		dl_tv_subtract(&t, &p->lastuse);
		if(dl_tv_smaller(&t, reuse_timeout))
			continue;
		/* yes! */
		verbose(1, "reuse existing entry");
		memmove(&p->addr, from, from_len);
		p->addr_len = from_len;
		p->numreuse++;
		return p;
	}
	/* create new */
	p = (struct proxy*)calloc(1, sizeof(*p));
	if(!p) fatal_exit("out of memory");
	p->s = socket(serv_ip6?AF_INET6:AF_INET, SOCK_DGRAM, 0);
	if(p->s == -1) {
#ifndef USE_WINSOCK
		fatal_exit("socket: %s", strerror(errno));
#else
		fatal_exit("socket: %s", wsa_strerror(WSAGetLastError()));
#endif
	}
	fd_set_nonblock(p->s);
	memmove(&p->addr, from, from_len);
	p->addr_len = from_len;
	p->next = *proxies;
	*proxies = p;
	FD_SET(FD_SET_T p->s, rorig);
	if(p->s+1 > *max)
		*max = p->s+1;
	return p;
}
Esempio n. 18
0
/**
 * Service control handler. Called by serviceControlManager when a control
 * code is sent to the service (with ControlService).
 * @param ctrl: control code
 */
static void 
hdlr(DWORD ctrl)
{
	if(ctrl == SERVICE_CONTROL_STOP) {
		report_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
		service_stop_shutdown = 1;
		/* send signal to stop */
		if(!WSASetEvent(service_stop_event))
			log_err("Could not WSASetEvent: %s",
				wsa_strerror(WSAGetLastError()));
		return;
	} else {
		/* ctrl == SERVICE_CONTROL_INTERROGATE or whatever */
		/* update status */
		report_status(service_status.dwCurrentState, NO_ERROR, 0);
	}
}
Esempio n. 19
0
/** wait for cron process to finish */
static void
waitforit(PROCESS_INFORMATION* pinfo)
{
	DWORD ret = WaitForSingleObject(pinfo->hProcess, INFINITE);
	verbose(VERB_ALGO, "cronaction done");
	if(ret != WAIT_OBJECT_0) {
		return; /* did not end successfully */
	}
	if(!GetExitCodeProcess(pinfo->hProcess, &ret)) {
		log_err("GetExitCodeProcess failed");
		return;
	}
	verbose(VERB_ALGO, "exit code is %d", (int)ret);
	if(ret != 1) {
		if(!WSASetEvent(service_stop_event))
			log_err("Could not WSASetEvent: %s",
			wsa_strerror(WSAGetLastError()));
	}
}
Esempio n. 20
0
/** got reply for io */
static void
perfreply(struct perfinfo* info, size_t n, struct timeval* now)
{
	ssize_t r;
	r = recv(info->io[n].fd, (void*)sldns_buffer_begin(info->buf),
		sldns_buffer_capacity(info->buf), 0);
	if(r == -1) {
#ifndef USE_WINSOCK
		log_err("recv: %s", strerror(errno));
#else
		log_err("recv: %s", wsa_strerror(WSAGetLastError()));
#endif
	} else {
		info->by_rcode[LDNS_RCODE_WIRE(sldns_buffer_begin(
			info->buf))]++;
		info->numrecv++;
	}
	/*sldns_buffer_set_limit(info->buf, r);
	log_buf(0, "reply", info->buf);*/
	perfsend(info, n, now);
}
Esempio n. 21
0
/** recv new waiting packets */
static void
service_recv(int s, struct ringbuf* ring, sldns_buffer* pkt, 
	fd_set* rorig, int* max, struct proxy** proxies,
	struct sockaddr_storage* srv_addr, socklen_t srv_len, 
	struct timeval* now, struct timeval* delay, struct timeval* reuse)
{
	int i;
	struct sockaddr_storage from;
	socklen_t from_len;
	ssize_t len;
	struct proxy* p;
	for(i=0; i<TRIES_PER_SELECT; i++) {
		from_len = (socklen_t)sizeof(from);
		len = recvfrom(s, (void*)sldns_buffer_begin(pkt),
			sldns_buffer_capacity(pkt), 0,
			(struct sockaddr*)&from, &from_len);
		if(len < 0) {
#ifndef USE_WINSOCK
			if(errno == EAGAIN || errno == EINTR)
				return;
			fatal_exit("recvfrom: %s", strerror(errno));
#else
			if(WSAGetLastError() == WSAEWOULDBLOCK || 
				WSAGetLastError() == WSAEINPROGRESS)
				return;
			fatal_exit("recvfrom: %s", 
				wsa_strerror(WSAGetLastError()));
#endif
		}
		sldns_buffer_set_limit(pkt, (size_t)len);
		/* find its proxy element */
		p = find_create_proxy(&from, from_len, rorig, max, proxies,
			addr_is_ip6(srv_addr, srv_len), now, reuse);
		if(!p) fatal_exit("error: cannot find or create proxy");
		p->lastuse = *now;
		ring_add(ring, pkt, now, delay, p);
		p->numwait++;
		log_addr(1, "recv from client", &p->addr, p->addr_len);
	}
}
Esempio n. 22
0
int net_lib_init(char **errstr)
{
#ifdef W32_NATIVE
    WORD wVersionRequested;
    WSADATA wsaData;
    int error_code;

    wVersionRequested = MAKEWORD(2, 0);
    if ((error_code = WSAStartup(wVersionRequested, &wsaData)) != 0)
    {
        *errstr = xasprintf("%s", wsa_strerror(error_code));
        return NET_ELIBFAILED;
    }
    else
    {
        return NET_EOK;
    }
#else /* noone else needs this... */
    (void)errstr;
    return NET_EOK;
#endif
}
Esempio n. 23
0
int 
fd_set_nonblock(int s) 
{
#ifdef HAVE_FCNTL
	int flag;
	if((flag = fcntl(s, F_GETFL)) == -1) {
		log_err("can't fcntl F_GETFL: %s", strerror(errno));
		flag = 0;
	}
	flag |= O_NONBLOCK;
	if(fcntl(s, F_SETFL, flag) == -1) {
		log_err("can't fcntl F_SETFL: %s", strerror(errno));
		return 0;
	}
#elif defined(HAVE_IOCTLSOCKET)
	unsigned long on = 1;
	if(ioctlsocket(s, FIONBIO, &on) != 0) {
		log_err("can't ioctlsocket FIONBIO on: %s", 
			wsa_strerror(WSAGetLastError()));
	}
#endif
	return 1;
}
Esempio n. 24
0
int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len, 
        int nonblock)
{
	struct tube_res_list* item = NULL;
	verbose(VERB_ALGO, "tube read_msg %s", nonblock?"nonblock":"blocking");
	*buf = NULL;
	if(!tube_poll(tube)) {
		verbose(VERB_ALGO, "tube read_msg nodata");
		/* nothing ready right now, wait if we want to */
		if(nonblock)
			return -1; /* would block waiting for items */
		if(!tube_wait(tube))
			return 0;
	}
	lock_basic_lock(&tube->res_lock);
	if(tube->res_list) {
		item = tube->res_list;
		tube->res_list = item->next;
		if(tube->res_last == item) {
			/* the list is now empty */
			tube->res_last = NULL;
			verbose(VERB_ALGO, "tube read_msg lastdata");
			if(!WSAResetEvent(tube->event)) {
				log_err("WSAResetEvent: %s", 
					wsa_strerror(WSAGetLastError()));
			}
		}
	}
	lock_basic_unlock(&tube->res_lock);
	if(!item)
		return 0; /* would block waiting for items */
	*buf = item->buf;
	*len = item->len;
	free(item);
	verbose(VERB_ALGO, "tube read_msg len %d", (int)*len);
	return 1;
}
Esempio n. 25
0
int 
fd_set_block(int s) 
{
#ifdef HAVE_FCNTL
	int flag;
	if((flag = fcntl(s, F_GETFL)) == -1) {
		log_err("cannot fcntl F_GETFL: %s", strerror(errno));
		flag = 0;
	}
	flag &= ~O_NONBLOCK;
	if(fcntl(s, F_SETFL, flag) == -1) {
		log_err("cannot fcntl F_SETFL: %s", strerror(errno));
		return 0;
	}
#elif defined(HAVE_IOCTLSOCKET)
	unsigned long off = 0;
	if(ioctlsocket(s, FIONBIO, &off) != 0) {
		if(WSAGetLastError() != WSAEINVAL || verbosity >= 4)
			log_err("can't ioctlsocket FIONBIO off: %s", 
				wsa_strerror(WSAGetLastError()));
	}
#endif	
	return 1;
}
Esempio n. 26
0
/** Main routine for unbound-control */
int main(int argc, char* argv[])
{
	int c, ret;
	const char* cfgfile = CONFIGFILE;
	char* svr = NULL;
#ifdef USE_WINSOCK
	int r;
	WSADATA wsa_data;
#endif
#ifdef USE_THREAD_DEBUG
	/* stop the file output from unbound-control, overwites the servers */
	extern int check_locking_order;
	check_locking_order = 0;
#endif /* USE_THREAD_DEBUG */
	log_ident_set("unbound-control");
	log_init(NULL, 0, NULL);
	checklock_start();
#ifdef USE_WINSOCK
	if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0)
		fatal_exit("WSAStartup failed: %s", wsa_strerror(r));
#endif

	ERR_load_crypto_strings();
	ERR_load_SSL_strings();
	OpenSSL_add_all_algorithms();
	(void)SSL_library_init();

	if(!RAND_status()) {
                /* try to seed it */
                unsigned char buf[256];
                unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid();
                size_t i;
                for(i=0; i<256/sizeof(v); i++) {
                        memmove(buf+i*sizeof(v), &v, sizeof(v));
                        v = v*seed + (unsigned int)i;
                }
                RAND_seed(buf, 256);
		log_warn("no entropy, seeding openssl PRNG with time\n");
	}

	/* parse the options */
	while( (c=getopt(argc, argv, "c:s:h")) != -1) {
		switch(c) {
		case 'c':
			cfgfile = optarg;
			break;
		case 's':
			svr = optarg;
			break;
		case '?':
		case 'h':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;
	if(argc == 0)
		usage();
	if(argc >= 1 && strcmp(argv[0], "start")==0) {
		if(execlp("unbound", "unbound", "-c", cfgfile, 
			(char*)NULL) < 0) {
			fatal_exit("could not exec unbound: %s",
				strerror(errno));
		}
	}

	ret = go(cfgfile, svr, argc, argv);

#ifdef USE_WINSOCK
        WSACleanup();
#endif
	checklock_stop();
	return ret;
}
Esempio n. 27
0
/** contact the server with TCP connect */
static int
contact_server(const char* svr, struct config_file* cfg, int statuscmd)
{
	struct sockaddr_storage addr;
	socklen_t addrlen;
	int addrfamily = 0;
	int fd;
	/* use svr or the first config entry */
	if(!svr) {
		if(cfg->control_ifs)
			svr = cfg->control_ifs->str;
		else	svr = "127.0.0.1";
		/* config 0 addr (everything), means ask localhost */
		if(strcmp(svr, "0.0.0.0") == 0)
			svr = "127.0.0.1";
		else if(strcmp(svr, "::0") == 0 ||
			strcmp(svr, "0::0") == 0 ||
			strcmp(svr, "0::") == 0 ||
			strcmp(svr, "::") == 0)
			svr = "::1";
	}
	if(strchr(svr, '@')) {
		if(!extstrtoaddr(svr, &addr, &addrlen))
			fatal_exit("could not parse IP@port: %s", svr);
#ifdef HAVE_SYS_UN_H
	} else if(svr[0] == '/') {
		struct sockaddr_un* usock = (struct sockaddr_un *) &addr;
		usock->sun_family = AF_LOCAL;
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
		usock->sun_len = (socklen_t)sizeof(usock);
#endif
		(void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path));
		addrlen = (socklen_t)sizeof(struct sockaddr_un);
		addrfamily = AF_LOCAL;
#endif
	} else {
		if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen))
			fatal_exit("could not parse IP: %s", svr);
	}

	if(addrfamily == 0)
		addrfamily = addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET;
	fd = socket(addrfamily, SOCK_STREAM, 0);
	if(fd == -1) {
#ifndef USE_WINSOCK
		fatal_exit("socket: %s", strerror(errno));
#else
		fatal_exit("socket: %s", wsa_strerror(WSAGetLastError()));
#endif
	}
	if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
#ifndef USE_WINSOCK
		log_err_addr("connect", strerror(errno), &addr, addrlen);
		if(errno == ECONNREFUSED && statuscmd) {
			printf("unbound is stopped\n");
			exit(3);
		}
#else
		log_err_addr("connect", wsa_strerror(WSAGetLastError()), &addr, addrlen);
		if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) {
			printf("unbound is stopped\n");
			exit(3);
		}
#endif
		exit(1);
	}
	return fd;
}
Esempio n. 28
0
/**
 * The main function for the service.
 * Called by the services API when starting unbound on windows in background.
 * Arguments could have been present in the string 'path'.
 * @param argc: nr args
 * @param argv: arg text.
 */
static void 
service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv))
{
	struct config_file* cfg = NULL;
	struct daemon* daemon = NULL;

	service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, 
		(LPHANDLER_FUNCTION)hdlr);
	if(!service_status_handle) {
		reportev("Could not RegisterServiceCtrlHandler");
		return;
	}
	
	service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	service_status.dwServiceSpecificExitCode = 0;

	/* see if we have root anchor update enabled */
	call_root_update();

	/* we are now starting up */
	report_status(SERVICE_START_PENDING, NO_ERROR, 3000);
	if(!service_init(0, &daemon, &cfg)) {
		reportev("Could not service_init");
		report_status(SERVICE_STOPPED, NO_ERROR, 0);
		return;
	}

	/* event that gets signalled when we want to quit; it
	 * should get registered in the worker-0 waiting loop. */
	service_stop_event = WSACreateEvent();
	if(service_stop_event == WSA_INVALID_EVENT) {
		log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError()));
		reportev("Could not WSACreateEvent");
		report_status(SERVICE_STOPPED, NO_ERROR, 0);
		return;
	}
	if(!WSAResetEvent(service_stop_event)) {
		log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError()));
	}

	/* SetServiceStatus SERVICE_RUNNING;*/
	report_status(SERVICE_RUNNING, NO_ERROR, 0);
	verbose(VERB_QUERY, "winservice - init complete");

	/* daemon performs work */
	while(!service_stop_shutdown) {
		daemon_fork(daemon);
		if(!service_stop_shutdown) {
			daemon_cleanup(daemon);
			config_delete(cfg); cfg=NULL;
			if(!service_init(1, &daemon, &cfg)) {
				reportev("Could not service_init");
				report_status(SERVICE_STOPPED, NO_ERROR, 0);
				return;
			}
		}
	}

	/* exit */
	verbose(VERB_ALGO, "winservice - cleanup.");
	report_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
	service_deinit(daemon, cfg);
	free(service_cfgfile);
	if(service_stop_event) (void)WSACloseEvent(service_stop_event);
	verbose(VERB_QUERY, "winservice - full stop");
	report_status(SERVICE_STOPPED, NO_ERROR, 0);
}
Esempio n. 29
0
/** Main routine for unbound-control */
int main(int argc, char* argv[])
{
	int c, ret;
	int quiet = 0;
	const char* cfgfile = CONFIGFILE;
	char* svr = NULL;
#ifdef USE_WINSOCK
	int r;
	WSADATA wsa_data;
#endif
#ifdef USE_THREAD_DEBUG
	/* stop the file output from unbound-control, overwrites the servers */
	extern int check_locking_order;
	check_locking_order = 0;
#endif /* USE_THREAD_DEBUG */
	log_ident_set("unbound-control");
	log_init(NULL, 0, NULL);
	checklock_start();
#ifdef USE_WINSOCK
	/* use registry config file in preference to compiletime location */
	if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
		cfgfile = CONFIGFILE;
#endif
	/* parse the options */
	while( (c=getopt(argc, argv, "c:s:qh")) != -1) {
		switch(c) {
		case 'c':
			cfgfile = optarg;
			break;
		case 's':
			svr = optarg;
			break;
		case 'q':
			quiet = 1;
			break;
		case '?':
		case 'h':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;
	if(argc == 0)
		usage();
	if(argc >= 1 && strcmp(argv[0], "start")==0) {
		if(execlp("unbound", "unbound", "-c", cfgfile, 
			(char*)NULL) < 0) {
			fatal_exit("could not exec unbound: %s",
				strerror(errno));
		}
	}
	if(argc >= 1 && strcmp(argv[0], "stats_shm")==0) {
		print_stats_shm(cfgfile);
		return 0;
	}

#ifdef USE_WINSOCK
	if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0)
		fatal_exit("WSAStartup failed: %s", wsa_strerror(r));
#endif

#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
	ERR_load_crypto_strings();
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
	ERR_load_SSL_strings();
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
	OpenSSL_add_all_algorithms();
#else
	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
		| OPENSSL_INIT_ADD_ALL_DIGESTS
		| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
	(void)SSL_library_init();
#else
	(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif

	if(!RAND_status()) {
		/* try to seed it */
		unsigned char buf[256];
		unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid();
		unsigned int v = seed;
		size_t i;
		for(i=0; i<256/sizeof(v); i++) {
			memmove(buf+i*sizeof(v), &v, sizeof(v));
			v = v*seed + (unsigned int)i;
		}
		RAND_seed(buf, 256);
		log_warn("no entropy, seeding openssl PRNG with time\n");
	}

	ret = go(cfgfile, svr, quiet, argc, argv);

#ifdef USE_WINSOCK
	WSACleanup();
#endif
	checklock_stop();
	return ret;
}
Esempio n. 30
0
int
create_udp_sock(int family, int socktype, struct sockaddr* addr,
        socklen_t addrlen, int v6only, int* inuse, int* noproto,
	int rcv, int snd)
{
	int s;
#if defined(IPV6_USE_MIN_MTU)
	int on=1;
#endif
#ifdef IPV6_MTU
	int mtu = IPV6_MIN_MTU;
#endif
#if !defined(SO_RCVBUFFORCE) && !defined(SO_RCVBUF)
	(void)rcv;
#endif
#if !defined(SO_SNDBUFFORCE) && !defined(SO_SNDBUF)
	(void)snd;
#endif
#ifndef IPV6_V6ONLY
	(void)v6only;
#endif
	if((s = socket(family, socktype, 0)) == -1) {
		*inuse = 0;
#ifndef USE_WINSOCK
		if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
			*noproto = 1;
			return -1;
		}
		log_err("can't create socket: %s", strerror(errno));
#else
		if(WSAGetLastError() == WSAEAFNOSUPPORT || 
			WSAGetLastError() == WSAEPROTONOSUPPORT) {
			*noproto = 1;
			return -1;
		}
		log_err("can't create socket: %s", 
			wsa_strerror(WSAGetLastError()));
#endif
		*noproto = 0;
		return -1;
	}
	if(rcv) {
#ifdef SO_RCVBUF
		int got;
		socklen_t slen = (socklen_t)sizeof(got);
#  ifdef SO_RCVBUFFORCE
		/* Linux specific: try to use root permission to override
		 * system limits on rcvbuf. The limit is stored in 
		 * /proc/sys/net/core/rmem_max or sysctl net.core.rmem_max */
		if(setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv, 
			(socklen_t)sizeof(rcv)) < 0) {
			if(errno != EPERM) {
#    ifndef USE_WINSOCK
				log_err("setsockopt(..., SO_RCVBUFFORCE, "
					"...) failed: %s", strerror(errno));
				close(s);
#    else
				log_err("setsockopt(..., SO_RCVBUFFORCE, "
					"...) failed: %s", 
					wsa_strerror(WSAGetLastError()));
				closesocket(s);
#    endif
				*noproto = 0;
				*inuse = 0;
				return -1;
			}
#  endif /* SO_RCVBUFFORCE */
			if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv, 
				(socklen_t)sizeof(rcv)) < 0) {
#  ifndef USE_WINSOCK
				log_err("setsockopt(..., SO_RCVBUF, "
					"...) failed: %s", strerror(errno));
				close(s);
#  else
				log_err("setsockopt(..., SO_RCVBUF, "
					"...) failed: %s", 
					wsa_strerror(WSAGetLastError()));
				closesocket(s);
#  endif
				*noproto = 0;
				*inuse = 0;
				return -1;
			}
			/* check if we got the right thing or if system
			 * reduced to some system max.  Warn if so */
			if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&got, 
				&slen) >= 0 && got < rcv/2) {
				log_warn("so-rcvbuf %u was not granted. "
					"Got %u. To fix: start with "
					"root permissions(linux) or sysctl "
					"bigger net.core.rmem_max(linux) or "
					"kern.ipc.maxsockbuf(bsd) values.",
					(unsigned)rcv, (unsigned)got);
			}
#  ifdef SO_RCVBUFFORCE
		}
#  endif
#endif /* SO_RCVBUF */
	}
	/* first do RCVBUF as the receive buffer is more important */
	if(snd) {
#ifdef SO_SNDBUF
		int got;
		socklen_t slen = (socklen_t)sizeof(got);
#  ifdef SO_SNDBUFFORCE
		/* Linux specific: try to use root permission to override
		 * system limits on sndbuf. The limit is stored in 
		 * /proc/sys/net/core/wmem_max or sysctl net.core.wmem_max */
		if(setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd, 
			(socklen_t)sizeof(snd)) < 0) {
			if(errno != EPERM) {
#    ifndef USE_WINSOCK
				log_err("setsockopt(..., SO_SNDBUFFORCE, "
					"...) failed: %s", strerror(errno));
				close(s);
#    else
				log_err("setsockopt(..., SO_SNDBUFFORCE, "
					"...) failed: %s", 
					wsa_strerror(WSAGetLastError()));
				closesocket(s);
#    endif
				*noproto = 0;
				*inuse = 0;
				return -1;
			}
#  endif /* SO_SNDBUFFORCE */
			if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&snd, 
				(socklen_t)sizeof(snd)) < 0) {
#  ifndef USE_WINSOCK
				log_err("setsockopt(..., SO_SNDBUF, "
					"...) failed: %s", strerror(errno));
				close(s);
#  else
				log_err("setsockopt(..., SO_SNDBUF, "
					"...) failed: %s", 
					wsa_strerror(WSAGetLastError()));
				closesocket(s);
#  endif
				*noproto = 0;
				*inuse = 0;
				return -1;
			}
			/* check if we got the right thing or if system
			 * reduced to some system max.  Warn if so */
			if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&got, 
				&slen) >= 0 && got < snd/2) {
				log_warn("so-sndbuf %u was not granted. "
					"Got %u. To fix: start with "
					"root permissions(linux) or sysctl "
					"bigger net.core.wmem_max(linux) or "
					"kern.ipc.maxsockbuf(bsd) values.",
					(unsigned)snd, (unsigned)got);
			}
#  ifdef SO_SNDBUFFORCE
		}
#  endif
#endif /* SO_SNDBUF */
	}
	if(family == AF_INET6) {
# if defined(IPV6_V6ONLY)
		if(v6only) {
			int val=(v6only==2)?0:1;
			if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 
				(void*)&val, (socklen_t)sizeof(val)) < 0) {
#ifndef USE_WINSOCK
				log_err("setsockopt(..., IPV6_V6ONLY"
					", ...) failed: %s", strerror(errno));
				close(s);
#else
				log_err("setsockopt(..., IPV6_V6ONLY"
					", ...) failed: %s", 
					wsa_strerror(WSAGetLastError()));
				closesocket(s);
#endif
				*noproto = 0;
				*inuse = 0;
				return -1;
			}
		}
# endif
# if defined(IPV6_USE_MIN_MTU)
		/*
		 * There is no fragmentation of IPv6 datagrams
		 * during forwarding in the network. Therefore
		 * we do not send UDP datagrams larger than
		 * the minimum IPv6 MTU of 1280 octets. The
		 * EDNS0 message length can be larger if the
		 * network stack supports IPV6_USE_MIN_MTU.
		 */
		if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
			(void*)&on, (socklen_t)sizeof(on)) < 0) {
#  ifndef USE_WINSOCK
			log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
				"...) failed: %s", strerror(errno));
			close(s);
#  else
			log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
				"...) failed: %s", 
				wsa_strerror(WSAGetLastError()));
			closesocket(s);
#  endif
			*noproto = 0;
			*inuse = 0;
			return -1;
		}
# elif defined(IPV6_MTU)
		/*
		 * On Linux, to send no larger than 1280, the PMTUD is
		 * disabled by default for datagrams anyway, so we set
		 * the MTU to use.
		 */
		if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU,
			(void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
#  ifndef USE_WINSOCK
			log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", 
				strerror(errno));
			close(s);
#  else
			log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", 
				wsa_strerror(WSAGetLastError()));
			closesocket(s);
#  endif
			*noproto = 0;
			*inuse = 0;
			return -1;
		}
# endif /* IPv6 MTU */
	} else if(family == AF_INET) {
#  if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
		int action = IP_PMTUDISC_DONT;
		if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, 
			&action, (socklen_t)sizeof(action)) < 0) {
			log_err("setsockopt(..., IP_MTU_DISCOVER, "
				"IP_PMTUDISC_DONT...) failed: %s",
				strerror(errno));
#    ifndef USE_WINSOCK
			close(s);
#    else
			closesocket(s);
#    endif
			return -1;
		}
#  elif defined(IP_DONTFRAG)
		int off = 0;
		if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG, 
			&off, (socklen_t)sizeof(off)) < 0) {
			log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s",
				strerror(errno));
#    ifndef USE_WINSOCK
			close(s);
#    else
			closesocket(s);
#    endif
			return -1;
		}
#  endif /* IPv4 MTU */
	}
	if(bind(s, (struct sockaddr*)addr, addrlen) != 0) {
		*noproto = 0;
#ifndef USE_WINSOCK
#ifdef EADDRINUSE
		*inuse = (errno == EADDRINUSE);
		/* detect freebsd jail with no ipv6 permission */
		if(family==AF_INET6 && errno==EINVAL)
			*noproto = 1;
		else if(errno != EADDRINUSE) {
			log_err("can't bind socket: %s", strerror(errno));
			log_addr(0, "failed address",
				(struct sockaddr_storage*)addr, addrlen);
		}
#endif /* EADDRINUSE */
		close(s);
#else /* USE_WINSOCK */
		if(WSAGetLastError() != WSAEADDRINUSE &&
			WSAGetLastError() != WSAEADDRNOTAVAIL) {
			log_err("can't bind socket: %s", 
				wsa_strerror(WSAGetLastError()));
			log_addr(0, "failed address",
				(struct sockaddr_storage*)addr, addrlen);
		}
		closesocket(s);
#endif
		return -1;
	}
	if(!fd_set_nonblock(s)) {
		*noproto = 0;
		*inuse = 0;
#ifndef USE_WINSOCK
		close(s);
#else
		closesocket(s);
#endif
		return -1;
	}
	return s;
}