Example #1
0
static void
_getdns_cancel_reply(getdns_context *context, connection *conn)
{
	struct mem_funcs *mf;

	if (!conn)
		return;

	if (context && context->server &&
	    _getdns_rbtree_search(&context->server->connections_set, conn)
	    != &conn->super)
		return;

	if (conn->l->transport == GETDNS_TRANSPORT_TCP) {
		tcp_connection *tcp_conn = (tcp_connection *)conn;

		if (tcp_conn->to_answer > 0 && --tcp_conn->to_answer == 0 &&
		    tcp_conn->fd == -1)
			tcp_connection_destroy(tcp_conn);

	} else if (conn->l->transport == GETDNS_TRANSPORT_UDP &&
	    (mf = &conn->l->set->context->mf)) {
		listen_set *set = conn->l->set;

		/* Unlink this connection */
		(void) _getdns_rbtree_delete(
		    &set->connections_set, conn);
		DEBUG_SERVER("[connection del] count: %d\n",
		    (int)set->connections_set.count);
		if ((*conn->prev_next = conn->next))
			conn->next->prev_next = conn->prev_next;
		GETDNS_FREE(*mf, conn);
		free_listen_set_when_done(set);
	}
}
Example #2
0
static void tcp_connection_destroy(tcp_connection *conn)
{
	struct mem_funcs *mf;
	getdns_eventloop *loop;

	tcp_to_write *cur, *next;

	mf = &conn->super.l->set->context->mf;
	if (getdns_context_get_eventloop(conn->super.l->set->context, &loop))
		return;

	if (conn->event.ev)
		loop->vmt->clear(loop, &conn->event);

	if (conn->event.read_cb||conn->event.write_cb||conn->event.timeout_cb) {
		conn->event.read_cb    = conn->event.write_cb =
		conn->event.timeout_cb = NULL;
	}
	if (conn->fd >= 0) {
		(void) _getdns_closesocket(conn->fd);
		conn->fd = -1;
	}
	if (conn->read_buf) {
		GETDNS_FREE(*mf, conn->read_buf);
		conn->read_buf = conn->read_pos = NULL;
		conn->to_read = 0;
	}
	if ((cur = conn->to_write)) {
		while (cur) {
			next = cur->next;
			GETDNS_FREE(*mf, cur);
			cur = next;
		}
		conn->to_write = NULL;
	}
	if (conn->to_answer > 0)
		return;

	/* Unlink this connection */
	(void) _getdns_rbtree_delete(
	    &conn->super.l->set->connections_set, conn);
	DEBUG_SERVER("[connection del] count: %d\n",
	    (int)conn->super.l->set->connections_set.count);
	if ((*conn->super.prev_next = conn->super.next))
		conn->super.next->prev_next = conn->super.prev_next;

	free_listen_set_when_done(conn->super.l->set);
	GETDNS_FREE(*mf, conn);
}
Example #3
0
/** call timeouts handlers, and return how long to wait for next one or -1 */
void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now,
        struct timeval* wait)
{
        struct _getdns_event* p;
#ifndef S_SPLINT_S
        wait->tv_sec = (time_t)-1;
#endif
	//verbose(VERB_CLIENT, "winsock_event handle_timeouts");

        while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times))
                !=RBTREE_NULL) {
#ifndef S_SPLINT_S
                if(p->ev_timeout.tv_sec > now->tv_sec ||
                        (p->ev_timeout.tv_sec==now->tv_sec &&
                        p->ev_timeout.tv_usec > now->tv_usec)) {
                        /* there is a next larger timeout. wait for it */
                        wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
                        if(now->tv_usec > p->ev_timeout.tv_usec) {
                                wait->tv_sec--;
                                wait->tv_usec = 1000000 - (now->tv_usec -
                                        p->ev_timeout.tv_usec);
                        } else {
                                wait->tv_usec = p->ev_timeout.tv_usec
                                        - now->tv_usec;
                        }
			//verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d",
			//	(long long)wait->tv_sec, (int)wait->tv_usec);
                        return;
                }
#endif
                /* event times out, remove it */
                (void)_getdns_rbtree_delete(base->times, p);
                p->ev_events &= ~EV_TIMEOUT;
                fptr_ok(fptr_whitelist_event(p->ev_callback));
                (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
        }
	//verbose(VERB_CLIENT, "winsock_event wait=(-1)");
}
Example #4
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;
}
Example #5
0
getdns_return_t
getdns_reply(getdns_context *context,
    const getdns_dict *reply, getdns_transaction_t request_id)
{
	/* TODO: Check request_id at context->outbound_requests */
	connection *conn = (connection *)(intptr_t)request_id;
	struct mem_funcs *mf;
	getdns_eventloop *loop;
	uint8_t buf[65536];
	size_t len;
	getdns_return_t r;

	if (!conn)
		return GETDNS_RETURN_INVALID_PARAMETER;

	if (!context || !context->server) {
		if (!context)
			context = conn->l->set->context;

	} else if (_getdns_rbtree_search(&context->server->connections_set, conn)
	    != &conn->super)
		return GETDNS_RETURN_NO_SUCH_LIST_ITEM;

	if (!reply) {
		_getdns_cancel_reply(context, conn);
		return GETDNS_RETURN_GOOD;
	}
	if (!(mf = &conn->l->set->context->mf))
		return GETDNS_RETURN_GENERIC_ERROR;;

	if ((r = getdns_context_get_eventloop(conn->l->set->context, &loop)))
		return r;

	len = sizeof(buf);
	if ((r = getdns_msg_dict2wire_buf(reply, buf, &len)))
		return r;

	else if (conn->l->transport == GETDNS_TRANSPORT_UDP) {
		listener *l = conn->l;

		if (conn->l->fd >= 0 && sendto(conn->l->fd, (void *)buf, len, 0,
		    (struct sockaddr *)&conn->remote_in, conn->addrlen) == -1) {
			/* TODO: handle _getdns_socketerror_wants_retry() */

			/* IO error, never cleanup a listener because of I/O error */
			DEBUG_SERVER("I/O error from sendto(): %s\n",
				     _getdns_errnostr());
		}
		/* Unlink this connection */
		(void) _getdns_rbtree_delete(
		    &l->set->connections_set, conn);
		DEBUG_SERVER("[connection del] count: %d\n",
		    (int)l->set->connections_set.count);
		if ((*conn->prev_next = conn->next))
			conn->next->prev_next = conn->prev_next;

		GETDNS_FREE(*mf, conn);
		if (l->fd < 0)
			free_listen_set_when_done(l->set);

	} else if (conn->l->transport == GETDNS_TRANSPORT_TCP) {
		tcp_connection *conn = (tcp_connection *)(intptr_t)request_id;
		tcp_to_write **to_write_p;
		tcp_to_write *to_write;

		if (conn->fd == -1) {
			if (conn->to_answer > 0)
				--conn->to_answer;
			tcp_connection_destroy(conn);
			return GETDNS_RETURN_GOOD;
		}
		if (!(to_write = (tcp_to_write *)GETDNS_XMALLOC(
		    *mf, uint8_t, sizeof(tcp_to_write) + len + 2))) {
			tcp_connection_destroy(conn);
			return GETDNS_RETURN_MEMORY_ERROR;
		}

		to_write->write_buf_len = len + 2;
		to_write->write_buf[0] = (len >> 8) & 0xFF;
		to_write->write_buf[1] = len & 0xFF;
		to_write->written = 0;
		to_write->next = NULL;
		(void) memcpy(to_write->write_buf + 2, buf, len);

		/* Append to_write to conn->to_write list */
		for ( to_write_p = &conn->to_write
		    ; *to_write_p
		    ; to_write_p = &(*to_write_p)->next)
			; /* pass */
		*to_write_p = to_write;

		if (conn->to_answer > 0)
			conn->to_answer--;

		/* When event is scheduled, and doesn't have tcp_write_cb:
		 * reschedule.
		 */
		if (conn->event.write_cb == NULL) {
			if (conn->event.ev)
				loop->vmt->clear(loop, &conn->event);
			conn->event.write_cb = tcp_write_cb;
			(void) loop->vmt->schedule(loop,
			    conn->fd, DOWNSTREAM_IDLE_TIMEOUT,
			    &conn->event);
		}
	}