📄 server.c
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#if HAVE_CONFIG_H#include <config.h>#endif#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#include <assert.h>#include "tds.h"#include "tdssrv.h"static char software_version[] = "$Id: server.c,v 1.24 2008/01/07 14:07:21 freddy77 Exp $";static void *no_unused_var_warn[] = { software_version, no_unused_var_warn };voidtds_env_change(TDSSOCKET * tds, int type, const char *oldvalue, const char *newvalue){ TDS_SMALLINT totsize; /* If oldvalue is NULL, treat it like "" */ if (oldvalue == NULL) oldvalue = ""; /* * NOTE: I don't know why each type of environment value has a different * format. According to the TDS5 specifications, they should all use * the same format. The code for the TDS_ENV_CHARSET case *should* * work for all environment values. -- Steve Kirkendall */ switch (type) { case TDS_ENV_DATABASE: case TDS_ENV_LANG: case TDS_ENV_PACKSIZE: case TDS_ENV_CHARSET: tds_put_byte(tds, TDS_ENVCHANGE_TOKEN); /* totsize = type + newlen + newvalue + oldlen + oldvalue */ totsize = strlen(oldvalue) + strlen(newvalue) + 3; tds_put_smallint(tds, totsize); tds_put_byte(tds, type); tds_put_byte(tds, strlen(newvalue)); /* FIXME this assume singlebyte -> ucs2 for mssql */ tds_put_string(tds, newvalue, strlen(newvalue)); tds_put_byte(tds, strlen(oldvalue)); /* FIXME this assume singlebyte -> ucs2 for mssql */ tds_put_string(tds, oldvalue, strlen(oldvalue)); break; case TDS_ENV_LCID: case TDS_ENV_SQLCOLLATION:#if 1 tds_put_byte(tds, TDS_ENVCHANGE_TOKEN); /* totsize = type + len + oldvalue + len + newvalue */ totsize = 3 + strlen(newvalue) + strlen(oldvalue); tds_put_smallint(tds, totsize); tds_put_byte(tds, type); tds_put_byte(tds, strlen(newvalue)); tds_put_n(tds, newvalue, strlen(newvalue)); tds_put_byte(tds, strlen(oldvalue)); tds_put_n(tds, oldvalue, strlen(oldvalue)); break;#endif default: tdsdump_log(TDS_DBG_WARN, "tds_env_change() ignoring unsupported environment code #%d", type); }}voidtds_send_eed(TDSSOCKET * tds, int msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line){ int totsize; tds_put_byte(tds, TDS_EED_TOKEN); totsize = 7 + strlen(procname) + 5 + strlen(msgtext) + 2 + strlen(srvname) + 3; tds_put_smallint(tds, totsize); tds_put_smallint(tds, msgno); tds_put_smallint(tds, 0); /* unknown */ tds_put_byte(tds, msgstate); tds_put_byte(tds, severity); tds_put_byte(tds, strlen(procname)); tds_put_n(tds, procname, strlen(procname)); tds_put_byte(tds, 0); /* unknown */ tds_put_byte(tds, 1); /* unknown */ tds_put_byte(tds, 0); /* unknown */ tds_put_smallint(tds, strlen(msgtext) + 1); tds_put_n(tds, msgtext, strlen(msgtext)); tds_put_byte(tds, severity); tds_put_byte(tds, strlen(srvname)); tds_put_n(tds, srvname, strlen(srvname)); tds_put_byte(tds, 0); /* unknown */ tds_put_byte(tds, 1); /* unknown */ tds_put_byte(tds, 0); /* unknown */}voidtds_send_msg(TDSSOCKET * tds, int msgno, int msgstate, int severity, const char *msgtext, const char *srvname, const char *procname, int line){ int msgsz; tds_put_byte(tds, TDS_INFO_TOKEN); msgsz = 4 /* msg no */ + 1 /* msg state */ + 1 /* severity */ /* FIXME ucs2 */ + (IS_TDS7_PLUS(tds) ? 2 : 1) * (strlen(msgtext) + 1 + strlen(srvname) + 1 + strlen(procname)) + 1 + 2; /* line number */ tds_put_smallint(tds, msgsz); tds_put_int(tds, msgno); tds_put_byte(tds, msgstate); tds_put_byte(tds, severity); tds_put_smallint(tds, strlen(msgtext)); /* FIXME ucs2 */ tds_put_string(tds, msgtext, strlen(msgtext)); tds_put_byte(tds, strlen(srvname)); /* FIXME ucs2 */ tds_put_string(tds, srvname, strlen(srvname)); if (procname && strlen(procname)) { tds_put_byte(tds, strlen(procname)); /* FIXME ucs2 */ tds_put_string(tds, procname, strlen(procname)); } else { tds_put_byte(tds, 0); } tds_put_smallint(tds, line);}voidtds_send_err(TDSSOCKET * tds, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr){ tds_put_byte(tds, TDS_ERROR_TOKEN);}voidtds_send_login_ack(TDSSOCKET * tds, const char *progname){ tds_put_byte(tds, TDS_LOGINACK_TOKEN); tds_put_smallint(tds, 10 + (IS_TDS7_PLUS(tds)? 2 : 1) * strlen(progname)); /* length of message */ if (IS_TDS50(tds)) { tds_put_byte(tds, 5); tds_put_byte(tds, 5); tds_put_byte(tds, 0); } else { tds_put_byte(tds, 1); tds_put_byte(tds, tds->major_version); tds_put_byte(tds, tds->minor_version); } tds_put_byte(tds, 0); /* unknown */ tds_put_byte(tds, 0); /* unknown */ tds_put_byte(tds, strlen(progname)); /* FIXME ucs2 */ tds_put_string(tds, progname, strlen(progname)); /* server version, for mssql 1.0.1 */ tds_put_byte(tds, 1); /* unknown */ tds_put_byte(tds, 0); /* unknown */ tds_put_byte(tds, 0); /* unknown */ tds_put_byte(tds, 1); /* unknown */}voidtds_send_capabilities_token(TDSSOCKET * tds){ tds_put_byte(tds, TDS_CAPABILITY_TOKEN); tds_put_smallint(tds, 18); tds_put_byte(tds, 1); tds_put_byte(tds, 7); tds_put_byte(tds, 7); tds_put_byte(tds, 97); tds_put_byte(tds, 65); tds_put_byte(tds, 207); tds_put_byte(tds, 255); tds_put_byte(tds, 255); tds_put_byte(tds, 230); tds_put_byte(tds, 2); tds_put_byte(tds, 7); tds_put_byte(tds, 0); tds_put_byte(tds, 0); tds_put_byte(tds, 2); tds_put_byte(tds, 0); tds_put_byte(tds, 0); tds_put_byte(tds, 0); tds_put_byte(tds, 0);}/** * Send a "done" token, marking the end of a table, stored procedure, or query. * \param tds Where the token will be written to. * \param token The appropriate type of "done" token for this context: * TDS_DONE_TOKEN outside a stored procedure, * TDS_DONEINPROC_TOKEN inside a stored procedure, or * TDS_DONEPROC_TOKEN at the end of a stored procedure. * \param flags Bitwise-OR of flags in the "enum tds_end" data type. * TDS_DONE_FINAL for the last statement in a query, * TDS_DONE_MORE_RESULTS if not the last statement, * TDS_DONE_ERROR if the statement had an error, * TDS_DONE_INXACT if a transaction is pending, * TDS_DONE_PROC inside a stored procedure, * TDS_DONE_COUNT if a table was sent (and rows counted) * TDS_DONE_CANCELLED if the query was canceled, and * TDS_DONE_EVENT if the token marks an event. * \param numrows Number of rows, if flags has TDS_DONE_COUNT. */voidtds_send_done(TDSSOCKET * tds, int token, TDS_SMALLINT flags, TDS_INT numrows){ tds_put_byte(tds, token); tds_put_smallint(tds, flags); tds_put_smallint(tds, 2); /* are these two bytes the transaction status? */ if (IS_TDS90(tds)) tds_put_int8(tds, numrows); else tds_put_int(tds, numrows);}voidtds_send_done_token(TDSSOCKET * tds, TDS_SMALLINT flags, TDS_INT numrows){ tds_send_done(tds, TDS_DONE_TOKEN, flags, numrows);}voidtds_send_control_token(TDSSOCKET * tds, TDS_SMALLINT numcols){ int i; tds_put_byte(tds, TDS_CONTROL_TOKEN); tds_put_smallint(tds, numcols); for (i = 0; i < numcols; i++) { tds_put_byte(tds, 0); }}voidtds_send_col_name(TDSSOCKET * tds, TDSRESULTINFO * resinfo){ int col, hdrsize = 0; TDSCOLUMN *curcol; tds_put_byte(tds, TDS_COLNAME_TOKEN); for (col = 0; col < resinfo->num_cols; col++) { curcol = resinfo->columns[col]; assert(strlen(curcol->column_name) == curcol->column_namelen); hdrsize += curcol->column_namelen + 1; } tds_put_smallint(tds, hdrsize); for (col = 0; col < resinfo->num_cols; col++) { curcol = resinfo->columns[col]; tds_put_byte(tds, curcol->column_namelen); /* exclude the null */ tds_put_n(tds, curcol->column_name, curcol->column_namelen); }}voidtds_send_col_info(TDSSOCKET * tds, TDSRESULTINFO * resinfo){ int col, hdrsize = 0; TDSCOLUMN *curcol; tds_put_byte(tds, TDS_COLFMT_TOKEN); for (col = 0; col < resinfo->num_cols; col++) { curcol = resinfo->columns[col]; hdrsize += 5; if (!is_fixed_type(curcol->column_type)) { hdrsize++; } } tds_put_smallint(tds, hdrsize); for (col = 0; col < resinfo->num_cols; col++) { curcol = resinfo->columns[col]; tds_put_n(tds, "\0\0\0\0", 4); tds_put_byte(tds, curcol->column_type); if (!is_fixed_type(curcol->column_type)) { tds_put_byte(tds, curcol->column_size); } }}voidtds_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo){ TDSCOLUMN *curcol; int i, totlen; tds_put_byte(tds, TDS_RESULT_TOKEN); totlen = 2; for (i = 0; i < resinfo->num_cols; i++) { curcol = resinfo->columns[i]; totlen += 8; assert(strlen(curcol->column_name) == curcol->column_namelen); totlen += curcol->column_namelen; curcol = resinfo->columns[i]; if (!is_fixed_type(curcol->column_type)) { totlen++; } } tds_put_smallint(tds, totlen); tds_put_smallint(tds, resinfo->num_cols); for (i = 0; i < resinfo->num_cols; i++) { curcol = resinfo->columns[i]; tds_put_byte(tds, curcol->column_namelen); tds_put_n(tds, curcol->column_name, curcol->column_namelen); tds_put_byte(tds, '0'); tds_put_int(tds, curcol->column_usertype); tds_put_byte(tds, curcol->column_type); if (!is_fixed_type(curcol->column_type)) { tds_put_byte(tds, curcol->column_size); } tds_put_byte(tds, 0); }}voidtds7_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo){ int i, j; TDSCOLUMN *curcol; /* TDS7+ uses TDS7_RESULT_TOKEN to send column names and info */ tds_put_byte(tds, TDS7_RESULT_TOKEN); /* send the number of columns */ tds_put_smallint(tds, resinfo->num_cols); /* send info about each column */ for (i = 0; i < resinfo->num_cols; i++) { /* usertype, flags, and type */ curcol = resinfo->columns[i]; tds_put_smallint(tds, curcol->column_usertype); tds_put_smallint(tds, curcol->column_flags); tds_put_byte(tds, curcol->column_type); /* smallint? */ /* bytes in "size" field varies */ if (is_blob_type(curcol->column_type)) { tds_put_int(tds, curcol->column_size); } else if (curcol->column_type>=128) { /*is_large_type*/ tds_put_smallint(tds, curcol->column_size); } else { tds_put_tinyint(tds, curcol->column_size); } /* some types have extra info */ if (is_numeric_type(curcol->column_type)) { tds_put_tinyint(tds, curcol->column_prec); tds_put_tinyint(tds, curcol->column_scale); } else if (is_blob_type(curcol->column_type)) { tds_put_smallint(tds, 2 * strlen(curcol->table_name)); for (j = 0; curcol->table_name[j] != '\0'; j++){ tds_put_byte(tds, curcol->table_name[j]); tds_put_byte(tds, 0); } } /* finally the name, in UCS16 format */ assert(strlen(curcol->column_name) == curcol->column_namelen); tds_put_byte(tds, curcol->column_namelen); for (j = 0; j < curcol->column_namelen; j++) { tds_put_byte(tds, curcol->column_name[j]); tds_put_byte(tds, 0); } }}/** * Send any tokens that mark the start of a table. This automatically chooses * the right tokens for this client's version of the TDS protocol. In other * words, it is a wrapper around tds_send_col_name(), tds_send_col_info(), * tds_send_result(), and tds7_send_result(). * \param tds The socket to which the tokens will be written. Also, * it contains the TDS protocol version number. * \param resinfo Describes the table to be send, especially the number * of columns and the names & data types of each column. */void tds_send_table_header(TDSSOCKET * tds, TDSRESULTINFO * resinfo){ switch (tds->major_version) { case 4: /* * TDS4 uses TDS_COLNAME_TOKEN to send column names, and * TDS_COLFMT_TOKEN to send column info. The number of columns * is implied by the number of column names. */ tds_send_col_name(tds, resinfo); tds_send_col_info(tds, resinfo); break; case 5: /* TDS5 uses a TDS_RESULT_TOKEN to send all column information */ tds_send_result(tds, resinfo); break; case 7: case 8: case 9: /* * TDS7+ uses a TDS7_RESULT_TOKEN to send all column * information. */ tds7_send_result(tds, resinfo); break; }}voidtds_send_row(TDSSOCKET * tds, TDSRESULTINFO * resinfo){ TDSCOLUMN *curcol; int colsize, i; tds_put_byte(tds, TDS_ROW_TOKEN); for (i = 0; i < resinfo->num_cols; i++) { curcol = resinfo->columns[i]; if (!is_fixed_type(curcol->column_type)) { /* FIX ME -- I have no way of knowing the actual length of non character variable data (eg nullable int) */ colsize = strlen((char *) curcol->column_data); tds_put_byte(tds, colsize); tds_put_n(tds, curcol->column_data, colsize); } else { tds_put_n(tds, curcol->column_data, tds_get_size_by_type(curcol->column_type)); } }}voidtds8_send_prelogin(TDSSOCKET * tds){ static const unsigned char prelogin[] = { 0x00, 0x00, 0x15, 0x00, 0x06, 0x01, 0x00, 0x1b, 0x00, 0x01, 0x02, 0x00, 0x1c, 0x00, 0x01, 0x03, 0x00, 0x1d, 0x00, 0x00, 0xff, 0x08, 0x00, 0x01, 0x55, 0x00, 0x00, 0x02, 0x00 }; tds_put_n(tds, prelogin, sizeof(prelogin));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -