login.c
来自「在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动」· C语言 代码 · 共 1,031 行 · 第 1/2 页
C
1,031 行
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns * Copyright (C) 2005, 2006, 2007 Ziglio Frediano * * 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 /* HAVE_CONFIG_H */#include <stdarg.h>#include <stdio.h>#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#include <assert.h>#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#if HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#ifdef WIN32#include <process.h>#endif#include "tds.h"#include "tdsiconv.h"#include "tdsstring.h"#include "replacements.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: login.c,v 1.172 2007/12/31 10:06:50 freddy77 Exp $");static int tds_send_login(TDSSOCKET * tds, TDSCONNECTION * connection);static int tds8_do_login(TDSSOCKET * tds, TDSCONNECTION * connection);static int tds7_send_login(TDSSOCKET * tds, TDSCONNECTION * connection);voidtds_set_version(TDSLOGIN * tds_login, TDS_TINYINT major_ver, TDS_TINYINT minor_ver){ tds_login->major_version = major_ver; tds_login->minor_version = minor_ver;}voidtds_set_packet(TDSLOGIN * tds_login, int packet_size){ tds_login->block_size = packet_size;}voidtds_set_port(TDSLOGIN * tds_login, int port){ tds_login->port = port;}voidtds_set_passwd(TDSLOGIN * tds_login, const char *password){ if (password) { tds_dstr_zero(&tds_login->password); tds_dstr_copy(&tds_login->password, password); }}voidtds_set_bulk(TDSLOGIN * tds_login, TDS_TINYINT enabled){ tds_login->bulk_copy = enabled ? 0 : 1;}voidtds_set_user(TDSLOGIN * tds_login, const char *username){ tds_dstr_copy(&tds_login->user_name, username);}voidtds_set_host(TDSLOGIN * tds_login, const char *hostname){ tds_dstr_copy(&tds_login->client_host_name, hostname);}voidtds_set_app(TDSLOGIN * tds_login, const char *application){ tds_dstr_copy(&tds_login->app_name, application);}/** * \brief Set the servername in a TDSLOGIN structure * * Normally copies \a server into \a tds_login. If \a server does not point to a plausible name, the environment * variables TDSQUERY and DSQUERY are used, in that order. If they don't exist, the "default default" servername * is "SYBASE" (although the utility of that choice is a bit murky). * * \param tds_login points to a TDSLOGIN structure * \param server the servername, or NULL, or a zero-length string * \todo open the log file earlier, so these messages can be seen. */voidtds_set_server(TDSLOGIN * tds_login, const char *server){ if (!server || strlen(server) == 0) { server = getenv("TDSQUERY"); tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' from $TDSQUERY.\n", server); } if (!server || strlen(server) == 0) { server = getenv("DSQUERY"); tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' from $DSQUERY.\n", server); } if (!server || strlen(server) == 0) { server = "SYBASE"; tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' (compiled-in default).\n", server); } tds_dstr_copy(&tds_login->server_name, server);}voidtds_set_server_addr(TDSLOGIN * tds_login, const char *server_addr){ if (server_addr) { tds_dstr_copy(&tds_login->server_addr, server_addr); }}voidtds_set_library(TDSLOGIN * tds_login, const char *library){ tds_dstr_copy(&tds_login->library, library);}voidtds_set_client_charset(TDSLOGIN * tds_login, const char *charset){ tds_dstr_copy(&tds_login->client_charset, charset);}voidtds_set_language(TDSLOGIN * tds_login, const char *language){ tds_dstr_copy(&tds_login->language, language);}voidtds_set_capabilities(TDSLOGIN * tds_login, unsigned char *capabilities, int size){ memcpy(tds_login->capabilities, capabilities, size > TDS_MAX_CAPABILITY ? TDS_MAX_CAPABILITY : size);}struct tds_save_msg{ TDSMESSAGE msg; char type;};struct tds_save_env{ char *oldval; char *newval; int type;};typedef struct tds_save_context{ /* must be first !!! */ TDSCONTEXT ctx; unsigned num_msg; struct tds_save_msg msgs[10]; unsigned num_env; struct tds_save_env envs[10];} TDSSAVECONTEXT;static voidtds_save(TDSSAVECONTEXT *ctx, char type, TDSMESSAGE *msg){ struct tds_save_msg *dest_msg; if (ctx->num_msg >= TDS_VECTOR_SIZE(ctx->msgs)) return; dest_msg = &ctx->msgs[ctx->num_msg]; dest_msg->type = type; dest_msg->msg = *msg;#define COPY(name) if (msg->name) dest_msg->msg.name = strdup(msg->name); COPY(server); COPY(message); COPY(proc_name); COPY(sql_state);#undef COPY ++ctx->num_msg;}static inttds_save_msg(const TDSCONTEXT *ctx, TDSSOCKET *tds, TDSMESSAGE *msg){ tds_save((TDSSAVECONTEXT *) ctx, 0, msg); return 0;}static inttds_save_err(const TDSCONTEXT *ctx, TDSSOCKET *tds, TDSMESSAGE *msg){ tds_save((TDSSAVECONTEXT *) ctx, 1, msg); return TDS_INT_CANCEL;}static voidtds_save_env(TDSSOCKET * tds, int type, char *oldval, char *newval){ TDSSAVECONTEXT *ctx; struct tds_save_env *env; if (tds->tds_ctx->msg_handler != tds_save_msg) return; ctx = (TDSSAVECONTEXT *) tds->tds_ctx; if (ctx->num_env >= TDS_VECTOR_SIZE(ctx->envs)) return; env = &ctx->envs[ctx->num_env]; env->type = type; env->oldval = oldval ? strdup(oldval) : NULL; env->newval = newval ? strdup(newval) : NULL; ++ctx->num_env;}static voidinit_save_context(TDSSAVECONTEXT *ctx, const TDSCONTEXT *old_ctx){ memset(ctx, 0, sizeof(*ctx)); ctx->ctx.locale = old_ctx->locale; ctx->ctx.msg_handler = tds_save_msg; ctx->ctx.err_handler = tds_save_err;}static voidreplay_save_context(TDSSOCKET *tds, TDSSAVECONTEXT *ctx){ unsigned n; /* replay all recorded messages */ for (n = 0; n < ctx->num_msg; ++n) if (ctx->msgs[n].type == 0) { if (tds->tds_ctx->msg_handler) tds->tds_ctx->msg_handler(tds->tds_ctx, tds, &ctx->msgs[n].msg); } else { if (tds->tds_ctx->err_handler) tds->tds_ctx->err_handler(tds->tds_ctx, tds, &ctx->msgs[n].msg); } /* replay all recorded envs */ for (n = 0; n < ctx->num_env; ++n) if (tds->env_chg_func) tds->env_chg_func(tds, ctx->envs[n].type, ctx->envs[n].oldval, ctx->envs[n].newval);}static voidreset_save_context(TDSSAVECONTEXT *ctx){ unsigned n; /* free all messages */ for (n = 0; n < ctx->num_msg; ++n) tds_free_msg(&ctx->msgs[n].msg); ctx->num_msg = 0; /* free all envs */ for (n = 0; n < ctx->num_env; ++n) { free(ctx->envs[n].oldval); free(ctx->envs[n].newval); } ctx->num_env = 0;}static voidfree_save_context(TDSSAVECONTEXT *ctx){ reset_save_context(ctx);}/** * Do a connection to socket * @param tds connection structure. This should be a non-connected connection. * @param connection info for connection * @return TDS_FAIL or TDS_SUCCEED */inttds_connect(TDSSOCKET * tds, TDSCONNECTION * connection){ int retval; int connect_timeout = 0; int db_selected = 0; char version[64]; char *str; int len; /* * A major version of 0 means try to guess the TDS version. * We try them in an order that should work. */ const static struct tdsver { TDS_TINYINT major_version; TDS_TINYINT minor_version; } versions[] = { { 8, 0 } , { 7, 0 } , { 5, 0 } , { 4, 2 } }; if (connection->major_version == 0) { unsigned int i; TDSSAVECONTEXT save_ctx; const TDSCONTEXT *old_ctx = tds->tds_ctx; typedef void (*env_chg_func_t) (TDSSOCKET * tds, int type, char *oldval, char *newval); env_chg_func_t old_env_chg = tds->env_chg_func; init_save_context(&save_ctx, old_ctx); tds->tds_ctx = &save_ctx.ctx; tds->env_chg_func = tds_save_env; for (i=0; i < TDS_VECTOR_SIZE(versions); ++i) { connection->major_version = versions[i].major_version; connection->minor_version = versions[i].minor_version; /* fprintf(stdout, "trying TDSVER %d.%d\n", connection->major_version, connection->minor_version); */ reset_save_context(&save_ctx); retval = tds_connect(tds, connection); if (TDS_SUCCEED == retval) break; tds_close_socket(tds); } tds->env_chg_func = old_env_chg; tds->tds_ctx = old_ctx; replay_save_context(tds, &save_ctx); free_save_context(&save_ctx); return retval; } /* * If a dump file has been specified, start logging */ if (!tds_dstr_isempty(&connection->dump_file)) { if (connection->debug_flags) tds_debug_flags = connection->debug_flags; tdsdump_open(tds_dstr_cstr(&connection->dump_file)); } tds->connection = connection; tds->major_version = connection->major_version; tds->minor_version = connection->minor_version; tds->emul_little_endian = connection->emul_little_endian;#ifdef WORDS_BIGENDIAN if (IS_TDS7_PLUS(tds)) { /* TDS 7/8 only supports little endian */ tds->emul_little_endian = 1; }#endif /* set up iconv if not already initialized*/ if (tds->char_convs[client2ucs2]->to_wire == (iconv_t) -1) { if (!tds_dstr_isempty(&connection->client_charset)) { tds_iconv_open(tds, tds_dstr_cstr(&connection->client_charset)); } } /* specified a date format? */ /* * if (connection->date_fmt) { * tds->date_fmt=strdup(connection->date_fmt); * } */ connect_timeout = connection->connect_timeout; /* Jeff's hack - begin */ tds->query_timeout = connect_timeout ? connect_timeout : connection->query_timeout; /* end */ /* verify that ip_addr is not empty */ if (tds_dstr_isempty(&connection->ip_addr)) { tdsdump_log(TDS_DBG_ERROR, "IP address pointer is empty\n"); if (!tds_dstr_isempty(&connection->server_name)) { tdsdump_log(TDS_DBG_ERROR, "Server %s not found!\n", tds_dstr_cstr(&connection->server_name)); } else { tdsdump_log(TDS_DBG_ERROR, "No server specified!\n"); } return TDS_FAIL; } if (!IS_TDS50(tds) && !tds_dstr_isempty(&connection->instance_name)) connection->port = tds7_get_instance_port(tds_dstr_cstr(&connection->ip_addr), tds_dstr_cstr(&connection->instance_name)); if (connection->port < 1) { tdsdump_log(TDS_DBG_ERROR, "invalid port number\n"); return TDS_FAIL; } memcpy(tds->capabilities, connection->capabilities, TDS_MAX_CAPABILITY); retval = tds_version(tds, version); if (!retval) version[0] = '\0'; if (tds_open_socket(tds, tds_dstr_cstr(&connection->ip_addr), connection->port, connect_timeout) != TDS_SUCCEED) return TDS_FAIL; tds_set_state(tds, TDS_IDLE); if (IS_TDS8_PLUS(tds)) { retval = tds8_do_login(tds, connection); db_selected = 1; } else if (IS_TDS7_PLUS(tds)) { retval = tds7_send_login(tds, connection); db_selected = 1; } else { tds->out_flag = TDS_LOGIN; retval = tds_send_login(tds, connection); } if (retval == TDS_FAIL || !tds_process_login_tokens(tds)) { tds_close_socket(tds); tdserror(tds->tds_ctx, tds, TDSEFCON, 0); /* "Adaptive Server connection failed" */ /* If it's a bad login, the server will send that mesasge */ return TDS_FAIL; } if (connection->text_size || (!db_selected && !tds_dstr_isempty(&connection->database))) { len = 64 + tds_quote_id(tds, NULL, tds_dstr_cstr(&connection->database),-1); if ((str = (char *) malloc(len)) == NULL) return TDS_FAIL; str[0] = 0; if (connection->text_size) { sprintf(str, "set textsize %d ", connection->text_size); } if (!db_selected && !tds_dstr_isempty(&connection->database)) { strcat(str, "use "); tds_quote_id(tds, strchr(str, 0), tds_dstr_cstr(&connection->database), -1); } retval = tds_submit_query(tds, str); free(str); if (retval != TDS_SUCCEED) return TDS_FAIL; if (tds_process_simple_query(tds) != TDS_SUCCEED) return TDS_FAIL; } tds->query_timeout = connection->query_timeout; tds->connection = NULL; return TDS_SUCCEED;}static inttds_put_login_string(TDSSOCKET * tds, const char *buf, int n){ int buf_len = (buf ? strlen(buf) : 0); return tds_put_buf(tds, (const unsigned char *) buf, n, buf_len);}static inttds_send_login(TDSSOCKET * tds, TDSCONNECTION * connection){#ifdef WORDS_BIGENDIAN static const unsigned char be1[] = { 0x02, 0x00, 0x06, 0x04, 0x08, 0x01 };#endif static const unsigned char le1[] = { 0x03, 0x01, 0x06, 0x0a, 0x09, 0x01 }; static const unsigned char magic2[] = { 0x00, 0x00 }; static const unsigned char magic3[] = { 0x00, 0x00, 0x00 }; /* these seem to endian flags as well 13,17 on intel/alpha 12,16 on power */#ifdef WORDS_BIGENDIAN static const unsigned char be2[] = { 0x00, 12, 16 };#endif static const unsigned char le2[] = { 0x00, 13, 17 }; /* * the former byte 0 of magic5 causes the language token and message to be * absent from the login acknowledgement if set to 1. There must be a way * of setting this in the client layer, but I am not aware of any thing of * the sort -- bsb 01/17/99 */ static const unsigned char magic5[] = { 0x00, 0x00 }; static const unsigned char magic6[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const unsigned char magic42[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const unsigned char magic50[] = { 0x00, 0x00, 0x00, 0x00 }; /* * capabilities are now part of the tds structure. * unsigned char capabilities[]= {0x01,0x07,0x03,109,127,0xFF,0xFF,0xFF,0xFE,0x02,0x07,0x00,0x00,0x0A,104,0x00,0x00,0x00};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?