Ejemplo n.º 1
0
void
pool_user_destroy(TDS_POOL * pool)
{
	while (dlist_user_first(&pool->users))
		pool_free_user(pool, dlist_user_first(&pool->users));
	while (dlist_user_first(&pool->waiters))
		pool_free_user(pool, dlist_user_first(&pool->waiters));

	tds_free_context(pool->ctx);
	pool->ctx = NULL;
}
Ejemplo n.º 2
0
/*
 * pool_user_read
 * checks the packet type of data coming from the client and allocates a 
 * pool member if necessary.
 */
static bool
pool_user_read(TDS_POOL * pool, TDS_POOL_USER * puser)
{
	TDSSOCKET *tds = puser->sock.tds;
	TDS_POOL_MEMBER *pmbr = NULL;

	for (;;) {
		if (pool_packet_read(tds))
			break;
		if (tds->in_len == 0) {
			tdsdump_log(TDS_DBG_INFO1, "user disconnected\n");
			pool_free_user(pool, puser);
			return false;
		} else {
			TDS_UCHAR in_flag = tds->in_buf[0];

			tdsdump_dump_buf(TDS_DBG_NETWORK, "Got packet from client:", tds->in_buf, tds->in_len);

			switch (in_flag) {
			case TDS_QUERY:
			case TDS_NORMAL:
			case TDS_RPC:
			case TDS_BULK:
			case TDS_CANCEL:
			case TDS7_TRANS:
				if (!pool_write_data(&puser->sock, &puser->assigned_member->sock)) {
					pool_reset_member(pool, puser->assigned_member);
					return false;
				}
				pmbr = puser->assigned_member;
				break;

			default:
				tdsdump_log(TDS_DBG_ERROR, "Unrecognized packet type, closing user\n");
				pool_free_user(pool, puser);
				return false;
			}
		}
	}
	if (pmbr && !pmbr->sock.poll_send)
		tds_socket_flush(tds_get_s(pmbr->sock.tds));
	return true;
}
Ejemplo n.º 3
0
void
pool_free_member(TDS_POOL_MEMBER * pmbr)
{
	if (!IS_TDSDEAD(pmbr->tds)) {
		tds_close_socket(pmbr->tds);
	}
	pmbr->tds = NULL;
	/*
	 * if he is allocated disconnect the client 
	 * otherwise we end up with broken client.
	 */
	if (pmbr->current_user) {
		pool_free_user(pmbr->current_user);
		pmbr->current_user = NULL;
	}
	pmbr->state = TDS_IDLE;
}
Ejemplo n.º 4
0
void
pool_free_member(TDS_POOL_MEMBER * pmbr)
{
	TDSSOCKET *tds = pmbr->tds;
	if (!IS_TDSDEAD(tds))
		tds_close_socket(tds);
	if (tds)
		tds_free_socket(tds);
	pmbr->tds = NULL;
	/*
	 * if he is allocated disconnect the client 
	 * otherwise we end up with broken client.
	 */
	if (pmbr->current_user) {
		pmbr->current_user->assigned_member = NULL;
		pool_free_user(pmbr->current_user);
		pmbr->current_user = NULL;
	}
	memset(pmbr, 0, sizeof(*pmbr));
	pmbr->state = TDS_IDLE;
}
Ejemplo n.º 5
0
/*
 * if a dead connection on the client side left this member in a questionable
 * state, let's bring in a correct one
 * We are not sure what the client did so we must try to clean as much as
 * possible.
 * Use pool_free_member if the state is really broken.
 */
void
pool_reset_member(TDS_POOL_MEMBER * pmbr)
{
	// FIXME not wait for server !!! asyncronous
	TDSSOCKET *tds = pmbr->tds;

	if (pmbr->current_user) {
		pmbr->current_user->assigned_member = NULL;
		pool_free_user(pmbr->current_user);
		pmbr->current_user = NULL;
	}

	/* cancel whatever pending */
	tds->state = TDS_IDLE;
	tds_init_write_buf(tds);
	tds->out_flag = TDS_CANCEL;
	tds_flush_packet(tds);
	tds->state = TDS_PENDING;

	if (tds_read_packet(tds) < 0) {
		pool_free_member(pmbr);
		return;
	}

	if (IS_TDS71_PLUS(tds->conn)) {
		/* this 0x9 final reset the state from mssql 2000 */
		tds_init_write_buf(tds);
		tds->out_flag = TDS_QUERY;
		tds_write_packet(tds, 0x9);
		tds->state = TDS_PENDING;

		if (tds_read_packet(tds) < 0) {
			pool_free_member(pmbr);
			return;
		}
	}

	pmbr->state = TDS_IDLE;
}
Ejemplo n.º 6
0
static void
login_execute(TDS_POOL_EVENT *base_event)
{
	LOGIN_EVENT *ev = (LOGIN_EVENT *) base_event;
	TDS_POOL_USER *puser = ev->puser;
	TDS_POOL *pool = ev->pool;

	if (!ev->success) {
		/* login failed...free socket */
		pool_free_user(pool, puser);
		return;
	}

	puser->sock.poll_recv = true;

	/* try to assign a member, connection can have transactions
	 * and so on so deassign only when disconnected */
	pool_user_query(pool, puser);

	tdsdump_log(TDS_DBG_INFO1, "user state %d\n", puser->user_state);

	assert(puser->login || puser->user_state == TDS_SRV_QUERY);
}
Ejemplo n.º 7
0
/*
 * pool_user_create
 * accepts a client connection and adds it to the users list and returns it
 */
TDS_POOL_USER *
pool_user_create(TDS_POOL * pool, TDS_SYS_SOCKET s)
{
	TDS_POOL_USER *puser;
	TDS_SYS_SOCKET fd;
	TDSSOCKET *tds;
	LOGIN_EVENT *ev;

	tdsdump_log(TDS_DBG_NETWORK, "accepting connection\n");
	if (TDS_IS_SOCKET_INVALID(fd = tds_accept(s, NULL, NULL))) {
		char *errstr = sock_strerror(errno);
		tdsdump_log(TDS_DBG_ERROR, "error calling assert :%s\n", errstr);
		sock_strerror_free(errstr);
		return NULL;
	}

	if (tds_socket_set_nonblocking(fd) != 0) {
		CLOSESOCKET(fd);
		return NULL;
	}

	puser = pool_user_find_new(pool);
	if (!puser) {
		CLOSESOCKET(fd);
		return NULL;
	}

	tds = tds_alloc_socket(pool->ctx, BLOCKSIZ);
	if (!tds) {
		CLOSESOCKET(fd);
		return NULL;
	}
	ev = (LOGIN_EVENT *) calloc(1, sizeof(*ev));
	if (!ev || TDS_FAILED(tds_iconv_open(tds->conn, "UTF-8", 0))) {
		free(ev);
		tds_free_socket(tds);
		CLOSESOCKET(fd);
		return NULL;
	}
	/* FIX ME - little endian emulation should be config file driven */
	tds->conn->emul_little_endian = 1;
	tds_set_s(tds, fd);
	tds->state = TDS_IDLE;
	tds->out_flag = TDS_LOGIN;

	puser->sock.tds = tds;
	puser->user_state = TDS_SRV_QUERY;
	puser->sock.poll_recv = false;
	puser->sock.poll_send = false;

	/* launch login asyncronously */
	ev->puser = puser;
	ev->pool = pool;

	if (tds_thread_create_detached(login_proc, ev) != 0) {
		pool_free_user(pool, puser);
		fprintf(stderr, "error creating thread\n");
		return NULL;
	}

	return puser;
}
Ejemplo n.º 8
0
/* 
 * pool_process_members
 * check the fd_set for members returning data to the client, lookup the 
 * client holding this member and forward the results.
 */
int
pool_process_members(TDS_POOL * pool, fd_set * fds)
{
	TDS_POOL_MEMBER *pmbr;
	TDS_POOL_USER *puser;
	TDSSOCKET *tds;
	int i, age, ret;
	int cnt = 0;
	unsigned char *buf;
	time_t time_now;

	for (i = 0; i < pool->num_members; i++) {
		pmbr = (TDS_POOL_MEMBER *) & pool->members[i];

		if (!pmbr->tds)
			break;	/* dead connection */

		tds = pmbr->tds;
		time_now = time(NULL);
		if (FD_ISSET(tds->s, fds)) {
			pmbr->last_used_tm = time_now;
			cnt++;
			/* tds->in_len = read(tds->s, tds->in_buf, BLOCKSIZ); */
			if (pool_packet_read(pmbr))
				continue;

			if (tds->in_len == 0) {
				fprintf(stderr, "Uh oh! member %d disconnected\n", i);
				/* mark as dead */
				pool_free_member(pmbr);
			} else if (tds->in_len == -1) {
				fprintf(stderr, "Uh oh! member %d disconnected\n", i);
				perror("read");
				pool_free_member(pmbr);
			} else {
				/* fprintf(stderr, "read %d bytes from member %d\n", tds->in_len, i); */
				if (pmbr->current_user) {
					puser = pmbr->current_user;
					buf = tds->in_buf;
					/* 
					 * check the netlib final packet flag
					 * instead of looking for done tokens.
					 * It's more efficient and generic to 
					 * all protocol versions. -- bsb 
					 * 2004-12-12 
					 */
					if (buf[1]) {
					/* if (pool_find_end_token(pmbr, buf + 8, tds->in_len - 8)) { */
						/* we are done...deallocate member */
						fprintf(stdout, "deassigning user from member %d\n",i);
						pool_deassign_member(pmbr);

						pmbr->state = TDS_IDLE;
						puser->user_state = TDS_SRV_IDLE;
					}
					/* cf. net.c for better technique.  */
					ret = WRITESOCKET(puser->tds->s, buf, tds->in_len);
					if (ret < 0) { /* couldn't write, ditch the user */
						fprintf(stdout, "member %d received error while writing\n",i);
						pool_free_user(pmbr->current_user);
						pool_deassign_member(pmbr);
						pool_reset_member(pmbr);
					}
				}
			}
		}
		age = time_now - pmbr->last_used_tm;
		if (age > pool->max_member_age && i >= pool->min_open_conn) {
			fprintf(stderr, "member %d is %d seconds old...closing\n", i, age);
			pool_free_member(pmbr);
		}
	}
	return cnt;
}