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; }
/* * 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; }
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; }
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; }
/* * 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; }
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); }
/* * 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; }
/* * 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; }