Ejemplo n.º 1
0
/**
 * Read from an OS socket
 * @TODO remove tds, save error somewhere, report error in another way
 * @returns 0 if blocking, <0 error >0 bytes read
 */
static int
tds_socket_read(TDSCONNECTION * conn, TDSSOCKET *tds, unsigned char *buf, int buflen)
{
	int len, err;

#if ENABLE_EXTRA_CHECKS
	/* this simulate the fact that recv can return less bytes */
	if (buflen >= 5) {
		static int cnt = 0;
		if (++cnt == 5) {
			cnt = 0;
			buflen -= 3;
		}
	}
#endif

	/* read directly from socket*/
	len = READSOCKET(conn->s, buf, buflen);
	if (len > 0)
		return len;

	err = sock_errno;
	if (len < 0 && TDSSOCK_WOULDBLOCK(err))
		return 0;

	/* detect connection close */
	tds_connection_close(conn);
	tdserror(conn->tds_ctx, tds, len == 0 ? TDSESEOF : TDSEREAD, len == 0 ? 0 : err);
	return -1;
}
Ejemplo n.º 2
0
/*
 * pool_main_loop
 * Accept new connections from clients, and handle all input from clients and
 * pool members.
 */
static void
pool_main_loop(TDS_POOL * pool)
{
	TDS_POOL_MEMBER *pmbr;
	TDS_POOL_USER *puser;
	TDS_SYS_SOCKET s, wakeup;
	SELECT_INFO sel;

	s = pool->listen_fd;
	wakeup = pool->wakeup_fd;

	while (!got_sigterm) {

		FD_ZERO(&sel.rfds);
		FD_ZERO(&sel.wfds);
		/* add the listening socket to the read list */
		FD_SET(s, &sel.rfds);
		FD_SET(wakeup, &sel.rfds);
		sel.maxfd = s > wakeup ? s : wakeup;

		/* add the user sockets to the read list */
		DLIST_FOREACH(dlist_user, &pool->users, puser)
			pool_select_add_socket(&sel, &puser->sock);

		/* add the pool member sockets to the read list */
		DLIST_FOREACH(dlist_member, &pool->active_members, pmbr)
			pool_select_add_socket(&sel, &pmbr->sock);

		/* FIXME check return value */
		select(sel.maxfd + 1, &sel.rfds, &sel.wfds, NULL, NULL);
		if (TDS_UNLIKELY(got_sigterm))
			break;

		if (TDS_UNLIKELY(got_sighup)) {
			got_sighup = 0;
			pool_open_logfile(pool);
		}

		/* process events */
		if (FD_ISSET(wakeup, &sel.rfds)) {
			char buf[32];
			READSOCKET(wakeup, buf, sizeof(buf));

			pool_process_events(pool);
		}

		/* process the sockets */
		if (FD_ISSET(s, &sel.rfds)) {
			pool_user_create(pool, s);
		}
		pool_process_users(pool, &sel.rfds, &sel.wfds);
		pool_process_members(pool, &sel.rfds, &sel.wfds);

		/* back from members */
		if (dlist_user_first(&pool->waiters))
			pool_schedule_waiters(pool);
	}			/* while !got_sigterm */
	tdsdump_log(TDS_DBG_INFO2, "Shutdown Requested\n");
}
Ejemplo n.º 3
0
/**
 * Loops until we have received some characters
 * return -1 on failure
 */
int
tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen)
{
	if (tds == NULL || buf == NULL || buflen < 1)
		return -1;

	for (;;) {
		int len, err;

		/* FIXME this block writing from other sessions */
		len = tds_select(tds, TDSSELREAD, tds->query_timeout);
#if !ENABLE_ODBC_MARS
		if (len > 0 && (len & TDSPOLLURG)) {
			char buf[32];
			READSOCKET(tds->conn->s_signaled, buf, sizeof(buf));
			/* send cancel */
			if (!tds->in_cancel)
				tds_put_cancel(tds);
			continue;
		}
#endif
		if (len > 0) {
			len = tds_socket_read(tds->conn, tds, buf, buflen);
			if (len == 0)
				continue;
			return len;
		}

		/* error */
		if (len < 0) {
			if (TDSSOCK_WOULDBLOCK(sock_errno)) /* shouldn't happen, but OK */
				continue;
			err = sock_errno;
			tds_connection_close(tds->conn);
			tdserror(tds_get_ctx(tds), tds, TDSEREAD, err);
			return -1;
		}

		/* timeout */
		switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
		case TDS_INT_CONTINUE:
			break;
		default:
		case TDS_INT_CANCEL:
			tds_close_socket(tds);
			return -1;
		}
	}
}
Ejemplo n.º 4
0
/* accept a socket and read data as much as you can */
static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg)
{
	TDS_SYS_SOCKET s = ptr2int(arg), sock;
	socklen_t len;
	char buf[128];
	struct sockaddr_in sin;
	struct pollfd fd;

	memset(&sin, 0, sizeof(sin));
	len = sizeof(sin);

	fd.fd = s;
	fd.events = POLLIN;
	fd.revents = 0;
	if (poll(&fd, 1, 30000) <= 0) {
		perror("poll");
		exit(1);
	}

	if (TDS_IS_SOCKET_INVALID(sock = tds_accept(s, (struct sockaddr *) &sin, &len))) {
		perror("accept");
		exit(1);
	}
	tds_mutex_lock(&mtx);
	fake_sock = sock;
	tds_mutex_unlock(&mtx);
	CLOSESOCKET(s);

	for (;;) {
		int len;

		fd.fd = sock;
		fd.events = POLLIN;
		fd.revents = 0;
		if (poll(&fd, 1, 30000) <= 0) {
			perror("poll");
			exit(1);
		}

		/* just read and discard */
		len = READSOCKET(sock, buf, sizeof(buf));
		if (len == 0)
			break;
		if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS)
			break;
	}
	return NULL;
}
Ejemplo n.º 5
0
/* read data from a nonblocking socket 
	Inputs:
		<fd> socket
		<buf> point to the buffer which stores data 
		<len> size of the buffer
	Returns:
		< 0 on failure
		otherwise the number of bytes read
*/
int
tcp_nonblocking_read(int fd, char *buf, int len, void *dummy)
{
	int n;

	(void) dummy;

	n = READSOCKET (fd, buf, len);
	if (n == -1)
    {
		return (NET_ERRNO != EWOULDBLOCK)? -1:0;
	}
	else if (n == 0) /* probable socket close */
	{
		return -1;
	}
	return n;
}
Ejemplo n.º 6
0
static int
tds_connection_signaled(TDSCONNECTION *conn)
{
	int len;
	char to_cancel[16];

#if defined(__linux__) && HAVE_EVENTFD
	if (conn->wakeup.s_signal == -1)
		return read(conn->wakeup.s_signaled, to_cancel, 8) > 0;
#endif

	len = READSOCKET(conn->wakeup.s_signaled, to_cancel, sizeof(to_cancel));
	do {
		/* no cancel found */
		if (len <= 0)
			return 0;
	} while(!to_cancel[--len]);
	return 1;
}
Ejemplo n.º 7
0
static void
tds_check_cancel(TDSCONNECTION *conn)
{
	TDSSOCKET *tds;
	int rc, len;
	char to_cancel[16];

	len = READSOCKET(conn->s_signaled, to_cancel, sizeof(to_cancel));
	do {
		/* no cancel found */
		if (len <= 0) return;
	} while(!to_cancel[--len]);

	do {
		unsigned n = 0;

		rc = TDS_SUCCESS;
		tds_mutex_lock(&conn->list_mtx);
		/* Here we scan all list searching for sessions that should send cancel packets */
		for (; n < conn->num_sessions; ++n)
			if (TDSSOCKET_VALID(tds=conn->sessions[n]) && tds->in_cancel == 1) {
				/* send cancel */
				tds->in_cancel = 2;
				tds_mutex_unlock(&conn->list_mtx);
				rc = tds_append_cancel(tds);
				tds_mutex_lock(&conn->list_mtx);
				if (rc != TDS_SUCCESS)
					break;
			}
		tds_mutex_unlock(&conn->list_mtx);
		/* for all failed */
		/* this must be done outside loop cause it can alter list */
		/* this must be done unlocked cause it can lock again */
		if (rc != TDS_SUCCESS)
			tds_close_socket(tds);
	} while(rc != TDS_SUCCESS);
}
Ejemplo n.º 8
0
/**
 * Loops until we have received buflen characters
 * return -1 on failure
 */
static int
tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen, unsigned char unfinished)
{
	double start, global_start;
	int got = 0;
    int canceled = 0;

	if (buf == NULL || buflen < 1 || IS_TDSDEAD(tds))
		return 0;

	global_start = start = GetTimeMark();

	while (buflen > 0) {
		int len;
		double now;

		if (IS_TDSDEAD(tds))
			return -1;

        if ((len = tds_select(tds, TDSSELREAD, tds->query_timeout,
                              global_start)) > 0) {

			len = READSOCKET(tds->s, buf + got, buflen);

			if (len < 0 && TDSSOCK_WOULDBLOCK(sock_errno))
				continue;
			/* detect connection close */
			if (len <= 0) {
                tds_close_socket(tds);
                if (len == 0) {
                    tds_client_msg(tds->tds_ctx, tds, 20011, 6, 0, 0,
                                   "EOF in the socket.");
                } else {
                    tds_report_error(tds->tds_ctx, tds, sock_errno, 20012,
                                     "recv finished with an error.");
                }
				return -1;
			}
		} else if (len < 0) {
			if (TDSSOCK_WOULDBLOCK(sock_errno)) /* shouldn't happen, but OK */
				continue;
            tds_close_socket(tds);
            tds_report_error(tds->tds_ctx, tds, sock_errno, 20012,
                             "recv finished with an error.");
			return -1;
		} else { /* timeout */
    		now = GetTimeMark();
            if (tds->query_timeout > 0 && now - start >= tds->query_timeout) {
    
                int timeout_action = TDS_INT_CONTINUE;
    
                if (canceled)
                    return got ? got : -1;
    
                if (tds->query_timeout_func && tds->query_timeout)
                    timeout_action = (*tds->query_timeout_func)
                        (tds->query_timeout_param, (int)(now - global_start));
    
                switch (timeout_action) {
                case TDS_INT_EXIT:
                    exit(EXIT_FAILURE);
                    break;
                case TDS_INT_CANCEL:
                    tds_send_cancel(tds);
                    canceled = 1;
                    /* fall through to wait while cancelling happens */
                case TDS_INT_CONTINUE:
                    start = now;
                default:
                    break;
                }
            }
		}

		buflen -= len;
		got += len;

		if (unfinished && got)
			return got;
	}
	return got;
}
Ejemplo n.º 9
0
static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg)
{
	TDS_SYS_SOCKET s = ptr2int(arg), server_sock;
	socklen_t sock_len;
	int len;
	char buf[128];
	struct sockaddr_in sin;
	fd_set fds_read, fds_write, fds_error;
	TDS_SYS_SOCKET max_fd = 0;

	memset(&sin, 0, sizeof(sin));
	sock_len = sizeof(sin);
	alarm(30);
	fprintf(stderr, "waiting connect...\n");
	if ((fake_sock = tds_accept(s, (struct sockaddr *) &sin, &sock_len)) < 0) {
		perror("accept");
		exit(1);
	}
	CLOSESOCKET(s);

	if (TDS_IS_SOCKET_INVALID(server_sock = socket(remote_addr.sa.sa_family, SOCK_STREAM, 0))) {
		perror("socket");
		exit(1);
	}

	fprintf(stderr, "connecting to server...\n");
	if (remote_addr.sa.sa_family == AF_INET) {
		fprintf(stderr, "connecting to %x:%d\n", remote_addr.sin.sin_addr.s_addr, ntohs(remote_addr.sin.sin_port));
	}
	if (connect(server_sock, &remote_addr.sa, remote_addr_len)) {
		perror("connect");
		exit(1);
	}
	alarm(0);

	if (fake_sock > max_fd) max_fd = fake_sock;
	if (server_sock > max_fd) max_fd = server_sock;

	for (;;) {
		int res;

		FD_ZERO(&fds_read);
		FD_SET(fake_sock, &fds_read);
		FD_SET(server_sock, &fds_read);

		FD_ZERO(&fds_write);

		FD_ZERO(&fds_error);
		FD_SET(fake_sock, &fds_error);
		FD_SET(server_sock, &fds_error);

		alarm(30);
		res = select(max_fd + 1, &fds_read, &fds_write, &fds_error, NULL);
		alarm(0);
		if (res < 0) {
			if (sock_errno == TDSSOCK_EINTR)
				continue;
			perror("select");
			exit(1);
		}

		if (FD_ISSET(fake_sock, &fds_error) || FD_ISSET(server_sock, &fds_error)) {
			fprintf(stderr, "error in select\n");
			exit(1);
		}

		/* just read and forward */
		if (FD_ISSET(fake_sock, &fds_read)) {
			if (flow != sending) {
				tds_mutex_lock(&mtx);
				++round_trips;
				tds_mutex_unlock(&mtx);
			}
			flow = sending;

			len = READSOCKET(fake_sock, buf, sizeof(buf));
			if (len == 0) {
				fprintf(stderr, "client connection closed\n");
				break;
			}
			if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS) {
				fprintf(stderr, "read client error %d\n", sock_errno);
				break;
			}
			count_insert(buf, len);
			write_all(server_sock, buf, len);
		}

		if (FD_ISSET(server_sock, &fds_read)) {
			if (flow != receiving) {
				tds_mutex_lock(&mtx);
				++round_trips;
				tds_mutex_unlock(&mtx);
			}
			flow = receiving;

			len = READSOCKET(server_sock, buf, sizeof(buf));
			if (len == 0) {
				fprintf(stderr, "server connection closed\n");
				break;
			}
			if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS) {
				fprintf(stderr, "read server error %d\n", sock_errno);
				break;
			}
			write_all(fake_sock, buf, len);
		}
	}
	CLOSESOCKET(fake_sock);
	CLOSESOCKET(server_sock);
	return NULL;
}