Esempio n. 1
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");
}
Esempio n. 2
0
static int
tds_connection_put_packet(TDSSOCKET *tds, TDSPACKET *packet)
{
	TDSCONNECTION *conn = tds->conn;

	if (TDS_UNLIKELY(!packet)) {
		tds_close_socket(tds);
		return TDS_FAIL;
	}
	tds->out_pos = 0;

	tds_mutex_lock(&conn->list_mtx);
	for (;;) {
		int wait_res;

		if (IS_TDSDEAD(tds)) {
			tdsdump_log(TDS_DBG_NETWORK, "Write attempt when state is TDS_DEAD");
			break;
		}

		/* limit packet sending looking at sequence/window */
		if (tds->send_seq <= tds->send_wnd) {
			/* append packet */
			tds_append_packet(&conn->send_packets, packet);
			packet = NULL;
		}

		/* network ok ? process network */
		if (!conn->in_net_tds) {
			tds_connection_network(conn, tds, packet ? 0 : 1);
			if (packet) continue;
			/* FIXME we are not sure we sent the packet !!! */
			break;
		}

		/* signal thread processing network to handle our packet */
		/* TODO check result */
		tds_wakeup_send(&conn->wakeup, 0);

		/* wait local condition */
		wait_res = tds_cond_timedwait(&tds->packet_cond, &conn->list_mtx, tds->query_timeout);
		if (wait_res == ETIMEDOUT
		    && tdserror(tds_get_ctx(tds), tds, TDSETIME, ETIMEDOUT) != TDS_INT_CONTINUE) {
			tds_mutex_unlock(&conn->list_mtx);
			tds_close_socket(tds);
			tds_free_packets(packet);
			return TDS_FAIL;
		}
	}
	tds_mutex_unlock(&conn->list_mtx);
	if (TDS_UNLIKELY(packet)) {
		tds_free_packets(packet);
		return TDS_FAIL;
	}
	if (IS_TDSDEAD(tds))
		return TDS_FAIL;
	return TDS_SUCCESS;
}
Esempio n. 3
0
/**
 * Get N bytes from the buffer and return them in the already allocated space  
 * given to us.  We ASSUME that the person calling this function has done the  
 * bounds checking for us since they know how many bytes they want here.
 * dest of NULL means we just want to eat the bytes.   ([email protected])
 */
void *
tds_get_n(TDSSOCKET * tds, void *dest, size_t need)
{
	for (;;) {
		unsigned int have = tds->in_len - tds->in_pos;

		if (need <= have)
			break;
		/* We need more than is in the buffer, copy what is there */
		if (dest != NULL) {
			memcpy((char *) dest, tds->in_buf + tds->in_pos, have);
			dest = (char *) dest + have;
		}
		need -= have;
		if (TDS_UNLIKELY(tds_read_packet(tds) < 0))
			return NULL;
	}
	if (need > 0) {
		/* get the remainder if there is any */
		if (dest != NULL) {
			memcpy((char *) dest, tds->in_buf + tds->in_pos, need);
		}
		tds->in_pos += need;
	}
	return dest;
}
Esempio n. 4
0
/**
 * Fetch character data the wire.
 * Output is NOT null terminated.
 * If \a char_conv is not NULL, convert data accordingly.
 * \param tds         state information for the socket and the TDS protocol
 * \param row_buffer  destination buffer in current_row. Can't be NULL
 * \param wire_size   size to read from wire (in bytes)
 * \param curcol      column information
 * \return TDS_SUCCESS or TDS_FAIL (probably memory error on text data)
 */
TDSRET
tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol)
{
	size_t in_left;

	assert(curcol->char_conv);

	/*
	 * row_buffer is a column buffer, allocated when the column's metadata are processed
	 * and reused for each row.
	 */

	/* silly case, empty string */
	if (wire_size == 0) {
		curcol->column_cur_size = 0;
		return TDS_SUCCESS;
	}

	in_left = curcol->column_size;
	curcol->column_cur_size = read_and_convert(tds, curcol->char_conv, &wire_size, row_buffer, in_left);
	if (TDS_UNLIKELY(wire_size > 0)) {
		tds_get_n(tds, NULL, wire_size);
		tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n",
						 (unsigned int) wire_size, curcol->column_cur_size);
		return TDS_FAIL;
	}
	return TDS_SUCCESS;
}
Esempio n. 5
0
static int
get_utf8(const unsigned char *p, size_t len, ICONV_CHAR *out)
{
	ICONV_CHAR uc;
	size_t l;

	l = utf8_lengths[p[0]];
	if (TDS_UNLIKELY(l == 0))
		return -EILSEQ;
	if (TDS_UNLIKELY(len < l))
		return -EINVAL;

	len = l;
	uc = *p++ & utf8_masks[l];
	while(--l)
		uc = (uc << 6) | (*p++ & 0x3f);
	*out = uc;
	return len;
}
Esempio n. 6
0
/** 
 * Inputs are FreeTDS canonical names, no other. No alias list is consulted.  
 */
iconv_t 
tds_sys_iconv_open (const char* tocode, const char* fromcode)
{
	int i;
	unsigned int fromto;
	const char *enc_name;
	unsigned char encodings[2];

	static char first_time = 1;

	if (TDS_UNLIKELY(first_time)) {
		first_time = 0;
		tdsdump_log(TDS_DBG_INFO1, "Using trivial iconv\n");
	}

	/* match both inputs to our canonical names */
	enc_name = fromcode;
	for (i=0; i < 2; ++i) {
		unsigned char encoding;

		if (strcmp(enc_name, "ISO-8859-1") == 0)
			encoding = 0;
		else if (strcmp(enc_name, "US-ASCII") == 0)
			encoding = 1;
		else if (strcmp(enc_name, "UCS-2LE") == 0 || strcmp(enc_name, "UTF-16LE") == 0)
			encoding = 2;
		else if (strcmp(enc_name, "UCS-2BE") == 0 || strcmp(enc_name, "UTF-16BE") == 0)
			encoding = 3;
		else if (strcmp(enc_name, "UCS-4LE") == 0)
			encoding = 4;
		else if (strcmp(enc_name, "UCS-4BE") == 0)
			encoding = 5;
		else if (strcmp(enc_name, "UTF-8") == 0)
			encoding = 6;
		else {
			errno = EINVAL;
			return (iconv_t)(-1);
		}
		encodings[i] = encoding;

		enc_name = tocode;
	}

	fromto = (encodings[0] << 4) | (encodings[1] & 0x0F);

	/* like to like */
	if (encodings[0] == encodings[1]) {
		fromto = Like_to_Like;
	}

	return (iconv_t) (TDS_INTPTR) fromto;
} 
Esempio n. 7
0
/**
 * allocate space for length char
 * @param s        dynamic string
 * @param length   new length 
 * @return string allocated or NULL on memory error
 */
DSTR*
tds_dstr_alloc(DSTR *s, size_t length)
{
	struct tds_dstr *p = (struct tds_dstr *) malloc(length + TDS_OFFSET(struct tds_dstr, dstr_s) + 1);
	if (TDS_UNLIKELY(!p))
		return NULL;

	if (*s != EMPTY)
		free(*s);
	p->dstr_s[0] = 0;
	p->dstr_size = length;
	*s = p;
	return s;
}
Esempio n. 8
0
static int
put_utf16be(unsigned char *buf, size_t buf_len, ICONV_CHAR c)
{
	if (c < 0x10000u) {
		if (buf_len < 2)
			return -E2BIG;
		TDS_PUT_A2BE(buf, c);
		return 2;
	}
	if (TDS_UNLIKELY(c >= 0x110000u))
		return -EILSEQ;
	if (buf_len < 4)
		return -E2BIG;
	TDS_PUT_A2BE(buf,   0xd7c0 + (c >> 10));
	TDS_PUT_A2BE(buf+2, 0xdc00 + (c & 0x3ffu));
	return 4;
}
Esempio n. 9
0
/**
 * Reads a string from wire and put in a DSTR.
 * On error we read the bytes from the wire anyway.
 * \tds
 * \param[out] s output string
 * \param[in] len string length (in characters)
 * \return string or NULL on error
 */
DSTR*
tds_dstr_get(TDSSOCKET * tds, DSTR * s, size_t len)
{
	size_t out_len;

	CHECK_TDS_EXTRA(tds);

	/* assure sufficient space for every conversion */
	if (TDS_UNLIKELY(!tds_dstr_alloc(s, len * 4))) {
		tds_get_n(tds, NULL, len);
		return NULL;
	}

	out_len = tds_get_string(tds, len, tds_dstr_buf(s), len * 4);
	tds_dstr_setlen(s, out_len);
	return s;
}
Esempio n. 10
0
/**
 * Set string to a given buffer of characters
 * @param s      dynamic string
 * @param src    source buffer
 * @param length length of source buffer
 * @return string copied or NULL on memory error
 */
DSTR*
tds_dstr_copyn(DSTR * s, const char *src, size_t length)
{
	if (!length) {
		if (*s != EMPTY) {
			free(*s);
			*s = EMPTY;
		}
	} else {
		struct tds_dstr *p = (struct tds_dstr *) malloc(length + TDS_OFFSET(struct tds_dstr, dstr_s) + 1);
		if (TDS_UNLIKELY(!p))
			return NULL;
		memcpy(p->dstr_s, src, length);
		p->dstr_s[length] = 0;
		p->dstr_size = length;
		if (*s != EMPTY)
			free(*s);
		*s = p;
	}
	return s;
}
Esempio n. 11
0
size_t 
tds_sys_iconv (iconv_t cd, const char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft)
{
	const unsigned char *ib;
	unsigned char *ob;
	size_t il, ol;
	int local_errno;

#undef CD
#define CD ((int) (TDS_INTPTR) cd)

	/* iconv defines valid semantics for NULL inputs, but we don't support them. */
	if (!inbuf || !*inbuf || !inbytesleft || !outbuf || !*outbuf || !outbytesleft)
		return 0;
	
	/* 
	 * some optimizations
	 * - do not use errno directly only assign a time
	 *   (some platform define errno as a complex macro)
	 * - some processors have few registers, deference and copy input variable
	 *   (this make also compiler optimize more due to removed aliasing)
	 *   also we use unsigned to remove required unsigned casts
	 */
	local_errno = 0;
	il = *inbytesleft;
	ol = *outbytesleft;
	ib = (const unsigned char*) *inbuf;
	ob = (unsigned char*) *outbuf;

	if (CD == Like_to_Like) {
		size_t copybytes = (il < ol)? il : ol;

		memcpy(ob, ib, copybytes);
		ob += copybytes;
		ol -= copybytes;
		ib += copybytes;
		il -= copybytes;
	} else if (CD & ~0x77) {
		local_errno = EINVAL;
	} else {
		iconv_get_t get_func = iconv_gets[(CD>>4) & 7];
		iconv_put_t put_func = iconv_puts[ CD     & 7];

		while (il) {
			ICONV_CHAR out_c;
			int readed = get_func(ib, il, &out_c), written;

			if (TDS_UNLIKELY(readed < 0)) {
				local_errno = -readed;
				break;
			}

			written = put_func(ob, ol, out_c);
			if (TDS_UNLIKELY(written < 0)) {
				local_errno = -written;
				break;
			}
			il -= readed;
			ib += readed;
			ol -= written;
			ob += written;
		}
	}

	/* back to source */
	*inbytesleft = il;
	*outbytesleft = ol;
	*inbuf = (const char*) ib;
	*outbuf = (char*) ob;

	if (il && !local_errno)
		local_errno = E2BIG;
	
	if (local_errno) {
		errno = local_errno;
		return (size_t)(-1);
	}
	
	return 0;
}
Esempio n. 12
0
/**
 * Read in one 'packet' from the server.  This is a wrapped outer packet of
 * the protocol (they bundle result packets into chunks and wrap them at
 * what appears to be 512 bytes regardless of how that breaks internal packet
 * up.   (tetherow\@nol.org)
 * @return bytes read or -1 on failure
 */
int
tds_read_packet(TDSSOCKET * tds)
{
#if ENABLE_ODBC_MARS
	TDSCONNECTION *conn = tds->conn;

	tds_mutex_lock(&conn->list_mtx);

	for (;;) {
		int wait_res;
		TDSPACKET **p_packet;

		if (IS_TDSDEAD(tds)) {
			tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD\n");
			break;
		}

		/* if there is a packet for me return it */
		for (p_packet = &conn->packets; *p_packet; p_packet = &(*p_packet)->next)
			if ((*p_packet)->sid == tds->sid)
				break;

		if (*p_packet) {
			size_t hdr_size;

			/* remove our packet from list */
			TDSPACKET *packet = *p_packet;
			*p_packet = packet->next;
			tds_packet_cache_add(conn, tds->recv_packet);
			tds_mutex_unlock(&conn->list_mtx);

			packet->next = NULL;
			tds->recv_packet = packet;

			hdr_size = packet->buf[0] == TDS72_SMP ? sizeof(TDS72_SMP_HEADER) : 0;
			tds->in_buf = packet->buf + hdr_size;
			tds->in_len = packet->len - hdr_size;
			tds->in_pos  = 8;
			tds->in_flag = tds->in_buf[0];

			/* send acknowledge if needed */
			if (tds->recv_seq + 2 >= tds->recv_wnd)
				tds_update_recv_wnd(tds, tds->recv_seq + 4);

			return tds->in_len;
		}

		/* network ok ? process network */
		if (!conn->in_net_tds) {
			tds_connection_network(conn, tds, 0);
			continue;
		}

		/* wait local condition */
		wait_res = tds_cond_timedwait(&tds->packet_cond, &conn->list_mtx, tds->query_timeout);
		if (wait_res == ETIMEDOUT
		    && tdserror(tds_get_ctx(tds), tds, TDSETIME, ETIMEDOUT) != TDS_INT_CONTINUE) {
			tds_mutex_unlock(&conn->list_mtx);
			tds_close_socket(tds);
			return -1;
		}
	}

	tds_mutex_unlock(&conn->list_mtx);
	return -1;
#else /* !ENABLE_ODBC_MARS */
	unsigned char *pkt = tds->in_buf, *p, *end;

	if (IS_TDSDEAD(tds)) {
		tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD");
		return -1;
	}

	tds->in_len = 0;
	tds->in_pos = 0;
	for (p = pkt, end = p+8; p < end;) {
		int len = tds_connection_read(tds, p, end - p);
		if (len <= 0) {
			tds_close_socket(tds);
			return -1;
		}

		p += len;
		if (p - pkt >= 4) {
			unsigned pktlen = TDS_GET_A2BE(pkt+2);
			/* packet must at least contains header */
			if (TDS_UNLIKELY(pktlen < 8)) {
				tds_close_socket(tds);
				return -1;
			}
			if (TDS_UNLIKELY(pktlen > tds->recv_packet->capacity)) {
				TDSPACKET *packet = tds_realloc_packet(tds->recv_packet, pktlen);
				if (TDS_UNLIKELY(!packet)) {
					tds_close_socket(tds);
					return -1;
				}
				tds->recv_packet = packet;
				pkt = packet->buf;
				p = pkt + (p-tds->in_buf);
				tds->in_buf = pkt;
			}
			end = pkt + pktlen;
		}
	}

	/* set the received packet type flag */
	tds->in_flag = pkt[0];

	/* Set the length and pos (not sure what pos is used for now */
	tds->in_len = p - pkt;
	tds->in_pos = 8;
	tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", tds->in_buf, tds->in_len);

	return tds->in_len;
#endif /* !ENABLE_ODBC_MARS */
}
Esempio n. 13
0
/**
 * Read part of packet. Function does not block.
 * @return true if packet is not complete and we must call again,
 *         false on full packet or error.
 */
bool
pool_packet_read(TDSSOCKET *tds)
{
	int packet_len;
	int readed, err;

	tdsdump_log(TDS_DBG_INFO1, "tds in_len %d in_pos %d\n", tds->in_len, tds->in_pos);

	// TODO MARS

	/* determine packet size */
	packet_len = tds->in_len >= 4 ? TDS_GET_A2BE(&tds->in_buf[2]) : 8;
	if (TDS_UNLIKELY(packet_len < 8)) {
		tds->in_len = 0;
		return false;
	}

	/* get another packet */
	if (tds->in_len >= packet_len) {
		tds->in_pos = 0;
		tds->in_len = 0;
	}

	for (;;) {
		/* determine packet size */
		packet_len = 8;
		if (tds->in_len >= 4) {
			packet_len = TDS_GET_A2BE(&tds->in_buf[2]);
			if (packet_len < 8)
				break;
			tdsdump_log(TDS_DBG_INFO1, "packet_len %d in_len %d\n", packet_len, tds->in_len);
			/* resize packet if not enough */
			if (packet_len > tds->recv_packet->capacity) {
				TDSPACKET *packet;

				packet = tds_realloc_packet(tds->recv_packet, packet_len);
				if (!packet)
					break;
				tds->in_buf = packet->buf;
				tds->recv_packet = packet;
			}
			CHECK_TDS_EXTRA(tds);
			if (tds->in_len >= packet_len)
				return false;
		}

		assert(packet_len > tds->in_len);
		assert(packet_len <= tds->recv_packet->capacity);
		assert(tds->in_len < tds->recv_packet->capacity);

		readed = read(tds_get_s(tds), &tds->in_buf[tds->in_len], packet_len - tds->in_len);
		tdsdump_log(TDS_DBG_INFO1, "readed %d\n", readed);

		/* socket closed */
		if (readed == 0)
			break;

		/* error */
		if (readed < 0) {
			err = sock_errno;
			if (err == EINTR)
				continue;
			if (TDSSOCK_WOULDBLOCK(err))
				return true;
			break;
		}

		/* got some data */
		tds->in_len += readed;
	}

	/* failure */
	tds->in_len = 0;
	return false;
}