/** * Close current socket * for last socket close entire connection * for MARS send FIN request */ void tds_close_socket(TDSSOCKET * tds) { if (!IS_TDSDEAD(tds)) { #if ENABLE_ODBC_MARS TDSCONNECTION *conn = tds->conn; unsigned n = 0, count = 0; tds_mutex_lock(&conn->list_mtx); for (; n < conn->num_sessions; ++n) if (TDSSOCKET_VALID(conn->sessions[n])) ++count; if (count > 1) tds_append_fin(tds); tds_mutex_unlock(&conn->list_mtx); if (count <= 1) { tds_disconnect(tds); tds_connection_close(conn); } else { tds_set_state(tds, TDS_DEAD); } #else tds_disconnect(tds); if (CLOSESOCKET(tds_get_s(tds)) == -1) tdserror(tds_get_ctx(tds), tds, TDSECLOS, sock_errno); tds_set_s(tds, INVALID_SOCKET); tds_set_state(tds, TDS_DEAD); #endif } }
static void unfinished_query_test(TDSSOCKET *tds) { int char_len; char *buf, *p; int i, len; union { TDS_USMALLINT si; TDS_UINT i; TDS_INT8 i8; char buf[8]; } conv; if (IS_TDS72_PLUS(tds->conn)) return; tds_init_write_buf(tds); /* try to build an invalid (unfinished) query split in two packets */ char_len = IS_TDS7_PLUS(tds->conn) ? 2 : 1; buf = calloc(1, tds->out_buf_max + 200); memset(buf, '-', tds->out_buf_max + 200); strcpy(buf + (tds->out_buf_max - 8) / char_len - strlen(select_query) + 1, select_query); memset(strchr(buf, 0), 0, 16); /* convert if needed */ len = strlen(buf); for (i = len; --i >= 0; ) { char c = buf[i]; buf[i * char_len + 0] = c; if (IS_TDS7_PLUS(tds->conn)) buf[i * char_len + 1] = 0; } len *= char_len; /* send the query using tds_put_int8, non allineati */ tds->out_flag = TDS_QUERY; if (tds_set_state(tds, TDS_WRITING) != TDS_WRITING) exit(1); p = buf; memcpy(conv.buf, p, 2); tds_put_smallint(tds, conv.si); p += 2; for (; p < buf + len; p += 8) { CHECK_TDS_EXTRA(tds); memcpy(conv.buf, p, 8); tds_put_int8(tds, conv.i8); } tds_flush_packet(tds); tds_set_state(tds, TDS_PENDING); /* check result was fine */ if (TDS_FAILED(tds_process_simple_query(tds))) { fprintf(stderr, "Error in prepared query\n"); exit(1); } free(buf); }
TDSRET tds_append_fin(TDSSOCKET *tds) { TDS72_SMP_HEADER mars; TDSPACKET *packet; if (!tds->conn->mars || tds->sid < 0) return TDS_SUCCESS; mars.signature = TDS72_SMP; mars.type = TDS_SMP_FIN; TDS_PUT_A2LE(&mars.sid, tds->sid); mars.size = TDS_HOST4LE(16); TDS_PUT_A4LE(&mars.seq, tds->send_seq); tds->recv_wnd = tds->recv_seq + 4; TDS_PUT_A4LE(&mars.wnd, tds->recv_wnd); /* do not use tds_get_packet as it require no lock ! */ packet = tds_alloc_packet(&mars, sizeof(mars)); if (!packet) return TDS_FAIL; /* TODO check result */ packet->sid = tds->sid; /* we already hold lock so do not lock */ tds_append_packet(&tds->conn->send_packets, packet); /* now is no more an active session */ tds->conn->sessions[tds->sid] = BUSY_SOCKET; tds_set_state(tds, TDS_DEAD); tds->sid = -1; return TDS_SUCCESS; }
int tds_close_socket(TDSSOCKET * tds) { int rc = -1; if (!IS_TDSDEAD(tds)) { rc = CLOSESOCKET(tds->s); tds->s = INVALID_SOCKET; tds_set_state(tds, TDS_DEAD); } return rc; }
void tds_connection_close(TDSCONNECTION *conn) { unsigned n = 0; if (!TDS_IS_SOCKET_INVALID(conn->s)) { /* TODO check error ?? how to return it ?? */ CLOSESOCKET(conn->s); conn->s = INVALID_SOCKET; } tds_mutex_lock(&conn->list_mtx); for (; n < conn->num_sessions; ++n) if (TDSSOCKET_VALID(conn->sessions[n])) tds_set_state(conn->sessions[n], TDS_DEAD); tds_mutex_unlock(&conn->list_mtx); }
int main(int argc, char **argv) { TDSLOGIN *login; TDSSOCKET *tds; int ret; int verbose = 0; TDS_INT8 i8; unsigned limit; fprintf(stdout, "%s: Testing login, logout\n", __FILE__); ret = try_tds_login(&login, &tds, __FILE__, verbose); if (ret != TDS_SUCCESS) { fprintf(stderr, "try_tds_login() failed\n"); return 1; } unfinished_query_test(tds); tds->out_flag = TDS_QUERY; if (tds_set_state(tds, TDS_WRITING) != TDS_WRITING) { return 1; } tds_put_n(tds, "aaa", 3); limit = tds->out_buf_max / 8 + 100; for (i8 = 0; i8 < limit; ++i8) { CHECK_TDS_EXTRA(tds); tds_put_int8(tds, i8); } tds_send_cancel(tds); tds_process_simple_query(tds); try_tds_logout(login, tds, verbose); return 0; }
/** * Send one row of data to server * \tds * \param bcpinfo BCP information * \param get_col_data function to call to retrieve data to be sent * \param ignored function to call if we try to send NULL if not allowed (not used) * \param offset passed to get_col_data and null_error to specify the row to get * \return TDS_SUCCESS or TDS_FAIL. */ TDSRET tds_bcp_send_record(TDSSOCKET *tds, TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset) { TDSCOLUMN *bindcol; int i, start_col = bcpinfo->next_col; TDSRET rc; tdsdump_log(TDS_DBG_FUNC, "tds_bcp_send_bcp_record(%p, %p, %p, %p, %d)\n", tds, bcpinfo, get_col_data, null_error, offset); if (tds->out_flag != TDS_BULK || tds_set_state(tds, TDS_WRITING) != TDS_WRITING) return TDS_FAIL; if (start_col > 0) { bindcol = bcpinfo->bindinfo->columns[start_col - 1]; *bindcol->column_lenbind = MIN((TDS_INT) bindcol->column_bindlen - bcpinfo->text_sent, *bindcol->column_lenbind); tds_put_n(tds, bindcol->column_varaddr, *bindcol->column_lenbind); bcpinfo->text_sent += *bindcol->column_lenbind; if ((TDS_UINT) bcpinfo->text_sent < bindcol->column_bindlen) { return TDS_SUCCESS; /* That's all for now. */ } else if (!IS_TDS7_PLUS(tds->conn)) { bcpinfo->blob_cols++; } bcpinfo->next_col = 0; bcpinfo->text_sent = 0; } if (IS_TDS7_PLUS(tds->conn)) { if (start_col == 0) { tds_put_byte(tds, TDS_ROW_TOKEN); /* 0xd1 */ } for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) { TDS_INT save_size; unsigned char *save_data; TDSBLOB blob; int /* bool */ has_text = 0; bindcol = bcpinfo->bindinfo->columns[i]; /* * Don't send the (meta)data for timestamp columns or * identity columns unless indentity_insert is enabled. */ if ((!bcpinfo->identity_insert_on && bindcol->column_identity) || bindcol->column_timestamp || !tds_bcp_is_bound(bcpinfo, bindcol)) { continue; } rc = get_col_data(bcpinfo, bindcol, offset); if (rc == TDS_FAIL) { tdsdump_log(TDS_DBG_INFO1, "get_col_data (column %d) failed\n", i + 1); goto cleanup; } else if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */ has_text = 1; } tdsdump_log(TDS_DBG_INFO1, "gotten column %d length %d null %d\n", i + 1, bindcol->bcp_column_data->datalen, bindcol->bcp_column_data->is_null); save_size = bindcol->column_cur_size; save_data = bindcol->column_data; assert(bindcol->column_data == NULL); if (bindcol->bcp_column_data->is_null) { if ( !bindcol->column_nullable && !is_nullable_type(bindcol->on_server.column_type) ) { return TDS_FAIL; } bindcol->column_cur_size = -1; } else if (has_text) { bindcol->column_cur_size = bindcol->bcp_column_data->datalen; } else if (is_blob_col(bindcol)) { bindcol->column_cur_size = bindcol->bcp_column_data->datalen; memset(&blob, 0, sizeof(blob)); blob.textvalue = (TDS_CHAR *) bindcol->bcp_column_data->data; bindcol->column_data = (unsigned char *) &blob; } else { bindcol->column_cur_size = bindcol->bcp_column_data->datalen; bindcol->column_data = bindcol->bcp_column_data->data; } rc = bindcol->funcs->put_data(tds, bindcol, 1); bindcol->column_cur_size = save_size; bindcol->column_data = save_data; if (TDS_FAILED(rc)) goto cleanup; else if (has_text) { bcpinfo->next_col = i + 1; /* bcpinfo->text_sent = 0; */ break; } } } /* IS_TDS7_PLUS */ else { if (start_col == 0) { int row_pos; int row_sz_pos; int var_cols_written = 0; TDS_INT old_record_size = bcpinfo->bindinfo->row_size; unsigned char *record = bcpinfo->bindinfo->current_row; memset(record, '\0', old_record_size); /* zero the rowbuffer */ /* * offset 0 = number of var columns * offset 1 = row number. zeroed (datasever assigns) */ row_pos = 2; rc = TDS_FAIL; if ((row_pos = tds_bcp_add_fixed_columns(bcpinfo, get_col_data, null_error, offset, record, row_pos)) < 0) goto cleanup; row_sz_pos = row_pos; /* potential variable columns to write */ if ((row_pos = tds_bcp_add_variable_columns(bcpinfo, get_col_data, null_error, offset, record, row_pos, &var_cols_written)) < 0) goto cleanup; if (var_cols_written) { TDS_PUT_UA2(&record[row_sz_pos], row_pos); record[0] = var_cols_written; } tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n", old_record_size, row_pos); tds_put_smallint(tds, row_pos); tds_put_n(tds, record, row_pos); /* row is done, now handle any text/image data */ bcpinfo->blob_cols = 0; } for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) { bindcol = bcpinfo->bindinfo->columns[i]; if (is_blob_type(bindcol->column_type)) { /* Elide trailing NULLs */ if (bindcol->bcp_column_data->is_null) { int j; for (j = i + 1; j < bcpinfo->bindinfo->num_cols; ++j) { TDSCOLUMN *bindcol2 = bcpinfo->bindinfo->columns[j]; if (is_blob_type(bindcol2->column_type) && !bindcol2->bcp_column_data->is_null) { break; } } if (j == bcpinfo->bindinfo->num_cols) { i = j; break; } } rc = get_col_data(bcpinfo, bindcol, offset); if (rc == TDS_FAIL) goto cleanup; /* unknown but zero */ tds_put_smallint(tds, 0); tds_put_byte(tds, (unsigned char) bindcol->column_type); tds_put_byte(tds, 0xff - bcpinfo->blob_cols); /* * offset of txptr we stashed during variable * column processing */ tds_put_smallint(tds, bindcol->column_textpos); tds_put_int(tds, bindcol->bcp_column_data->datalen); if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */ bcpinfo->next_col = i + 1; /* bcpinfo->text_sent = 0; */ break; } tds_put_n(tds, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen); bcpinfo->blob_cols++; } } } if (i == bcpinfo->bindinfo->num_cols) { tds_set_state(tds, TDS_SENDING); bcpinfo->next_col = 0; } return TDS_SUCCESS; cleanup: tds_set_state(tds, TDS_SENDING); return rc; }