read.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:10k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: read.c,v $
  4.  * PRODUCTION Revision 1000.0  2003/10/29 20:35:18  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R1.2
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
  10.  * Copyright (C) 1998-1999  Brian Bruns
  11.  *
  12.  * This library is free software; you can redistribute it and/or
  13.  * modify it under the terms of the GNU Library General Public
  14.  * License as published by the Free Software Foundation; either
  15.  * version 2 of the License, or (at your option) any later version.
  16.  *
  17.  * This library is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20.  * Library General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU Library General Public
  23.  * License along with this library; if not, write to the
  24.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  25.  * Boston, MA 02111-1307, USA.
  26.  */
  27. #include <tds_config.h>
  28. #include "tds.h"
  29. #ifdef DMALLOC
  30. #include <dmalloc.h>
  31. #endif
  32. #ifdef WIN32
  33. #define CLOSE(a) closesocket(a)
  34. #define READ(a,b,c) recv (a, b, c, 0L);
  35. #else
  36. #define CLOSE(a) close(a)
  37. #define READ(a,b,c) read (a, b, c);
  38. #endif
  39. #include "tdsutil.h"
  40. static char  software_version[]   = "$Id: read.c,v 1000.0 2003/10/29 20:35:18 gouriano Exp $";
  41. static void *no_unused_var_warn[] = {software_version,
  42.                                      no_unused_var_warn};
  43. /** 
  44.  * Loops until we have received buflen characters 
  45.  * return -1 on failure 
  46.  */
  47. static int
  48. goodread (TDSSOCKET *tds, unsigned char *buf, int buflen)
  49. {
  50. int got = 0;
  51. int len, retcode;
  52. fd_set fds;
  53. time_t start, now;
  54. struct timeval selecttimeout;
  55. FD_ZERO (&fds);
  56. if (tds->timeout > 0) {
  57. start = time(NULL);
  58. now = start;
  59. /* FIXME return even if not finished read if timeout */
  60. while ((buflen > 0) && ((now-start) < tds->timeout)) {
  61. int timeleft = tds->timeout;
  62. len = 0;
  63. retcode = 0;
  64. do {
  65. FD_SET (tds->s, &fds);
  66. selecttimeout.tv_sec = timeleft;
  67. selecttimeout.tv_usec = 0;
  68. retcode = select (tds->s + 1, &fds, NULL, NULL, &selecttimeout);
  69. /* ignore EINTR errors */
  70. if (retcode < 0 && errno == EINTR)
  71. retcode = 0;
  72. now = time (NULL);
  73. timeleft = tds->timeout - (now-start);
  74. } while((retcode == 0) && timeleft > 0);
  75. len = READ(tds->s, buf+got, buflen);
  76. if (len <= 0) {
  77. if (len < 0 && errno == EINTR) len = 0;
  78. else return (-1); /* SOCKET_ERROR); */
  79. }
  80. buflen -= len;
  81. got += len;
  82. now = time (NULL);
  83. if (tds->queryStarttime && tds->longquery_timeout) {
  84. if ((now-(tds->queryStarttime)) >= tds->longquery_timeout) {
  85. (*tds->longquery_func)(tds->longquery_param);
  86. }
  87. }
  88. } /* while buflen... */
  89. } else {
  90. /* got = READ(tds->s, buf, buflen); */
  91. while (got < buflen) {
  92. int len;
  93. FD_SET (tds->s, &fds);
  94. select (tds->s + 1, &fds, NULL, NULL, NULL);
  95. len = READ(tds->s, buf + got, buflen - got);
  96. if (len <= 0) {
  97. if (len < 0 && (errno == EINTR || errno == EINPROGRESS)) len = 0;
  98. else return (-1); /* SOCKET_ERROR); */
  99. }  
  100. got += len;
  101. }
  102. }
  103. return (got);
  104. }
  105. /*
  106. ** Return a single byte from the input buffer
  107. */
  108. unsigned char tds_get_byte(TDSSOCKET *tds)
  109. {
  110. int rc;
  111. if (tds->in_pos >= tds->in_len) {
  112. while (tds->s && (rc = tds_read_packet(tds)) == 0) ;
  113. if(!tds->s || rc == -1) {
  114. return 0;
  115. }
  116. }
  117. return tds->in_buf[tds->in_pos++];
  118. }
  119. /*
  120. ** Unget will always work as long as you don't call it twice in a row.  It
  121. ** it may work if you call it multiple times as long as you don't backup
  122. ** over the beginning of network packet boundary which can occur anywhere in
  123. ** the token stream.
  124. */
  125. void tds_unget_byte(TDSSOCKET *tds)
  126. {
  127. /* this is a one trick pony...don't call it twice */
  128. tds->in_pos--;
  129. }
  130. unsigned char tds_peek(TDSSOCKET *tds)
  131. {
  132.    unsigned char   result = tds_get_byte(tds);
  133.    tds_unget_byte(tds);
  134.    return result;
  135. } /* tds_peek()  */
  136. /*
  137. ** Get an int16 from the server.
  138. */
  139. TDS_SMALLINT tds_get_smallint(TDSSOCKET *tds)
  140. {
  141. unsigned char bytes[2];
  142. tds_get_n(tds, bytes, 2);
  143. #if WORDS_BIGENDIAN
  144. if (tds->emul_little_endian) {
  145. return TDS_BYTE_SWAP16(*(TDS_SMALLINT *)bytes);
  146. }
  147. #endif
  148. return *(TDS_SMALLINT *)bytes;
  149. }
  150. /*
  151. ** Get an int32 from the server.
  152. */
  153. TDS_INT tds_get_int(TDSSOCKET *tds)
  154. {
  155. unsigned char bytes[4];
  156. tds_get_n(tds, bytes, 4);
  157. #if WORDS_BIGENDIAN
  158. if (tds->emul_little_endian) {
  159. return TDS_BYTE_SWAP32(*(TDS_INT *)bytes);
  160. }
  161. #endif
  162. return *(TDS_INT *)bytes;
  163. }
  164. /*
  165.  * fetches a null terminated ascii string
  166.  */
  167. char *tds_get_ntstring(TDSSOCKET *tds, char *dest, int max)
  168. {
  169. int i = 0;
  170. char c;
  171. while ((c = tds_get_byte(tds))) {
  172. if (i < (max - 1) && dest)
  173. dest[i++] = c;
  174. }
  175. if (dest) dest[i]='';
  176. return dest;
  177. }
  178. char *tds_get_string(TDSSOCKET *tds, void *dest, int need)
  179. {
  180. char *temp;
  181. /*
  182. ** FIX: 02-Jun-2000 by Scott C. Gray (SCG)
  183. **
  184. ** Bug to malloc(0) on some platforms.
  185. */
  186. if (need == 0) {
  187. return dest;
  188. }
  189. if (IS_TDS70(tds) || IS_TDS80(tds)) {
  190. if (dest==NULL) {
  191. tds_get_n(tds,NULL,need*2);
  192. return(NULL);
  193. }
  194. temp = (char *) malloc(need*2);
  195. tds_get_n(tds,temp,need*2);
  196. tds7_unicode2ascii(tds,temp,dest,need);
  197. free(temp);
  198. return(dest);
  199. } else {
  200. return tds_get_n(tds,dest,need);
  201. }
  202. }
  203. /*
  204. ** Get N bytes from the buffer and return them in the already allocated space  
  205. ** given to us.  We ASSUME that the person calling this function has done the  
  206. ** bounds checking for us since they know how many bytes they want here.
  207. ** dest of NULL means we just want to eat the bytes.   (tetherow@nol.org)
  208. */
  209. char *tds_get_n(TDSSOCKET *tds, void *dest, int need)
  210. {
  211. int pos,have;
  212. pos = 0;
  213. have=(tds->in_len-tds->in_pos);
  214. while (need>have) {
  215. /* We need more than is in the buffer, copy what is there */
  216. if (dest!=NULL) {
  217. memcpy((char*)dest+pos, tds->in_buf+tds->in_pos, have);
  218. }
  219. pos+=have;
  220. need-=have;
  221. #ifdef NCBI_FTDS
  222. if(tds_read_packet(tds) < 0) return dest;
  223. #else
  224. tds_read_packet(tds);
  225. #endif
  226. have=tds->in_len;
  227. }
  228. if (need>0) {
  229. /* get the remainder if there is any */
  230. if (dest!=NULL) {
  231. memcpy((char*)dest+pos, tds->in_buf+tds->in_pos, need);
  232. }
  233. tds->in_pos+=need;
  234. }
  235. return dest;
  236. }
  237. /*
  238. ** Return the number of bytes needed by specified type.
  239. */
  240. int get_size_by_type(int servertype)
  241. {
  242.    switch(servertype)
  243.    {
  244.       case SYBINT1:        return 1;  break;
  245.       case SYBINT2:        return 2;  break;
  246.       case SYBINT4:        return 4;  break;
  247.       case SYBINT8:        return 8;  break;
  248.       case SYBREAL:        return 4;  break;
  249.       case SYBFLT8:        return 8;  break;
  250.       case SYBDATETIME:    return 8;  break;
  251.       case SYBDATETIME4:   return 4;  break;
  252.       case SYBBIT:         return 1;  break;
  253.       case SYBBITN:        return 1;  break;
  254.       case SYBMONEY:       return 8;  break;
  255.       case SYBMONEY4:      return 4;  break;
  256.  case SYBUNIQUE:      return 16; break;
  257.       default:             return -1; break;
  258.    }
  259. }
  260. /*
  261. ** Read in one 'packet' from the server.  This is a wrapped outer packet of
  262. ** the protocol (they bundle resulte packets into chunks and wrap them at
  263. ** what appears to be 512 bytes regardless of how that breaks internal packet
  264. ** up.   (tetherow@nol.org)
  265. */
  266. int tds_read_packet (TDSSOCKET *tds)
  267. {
  268. unsigned char header[8];
  269. int           len;
  270. int           x = 0, have, need;
  271. /* Read in the packet header.  We use this to figure out our packet 
  272. ** length */
  273. /* Cast to int are needed because some compiler seem to convert
  274.  * len to unsigned (as FreeBSD 4.5 one)*/
  275. if ((len = goodread(tds, header, sizeof(header))) < (int)sizeof(header) ) {
  276. /* GW ADDED */
  277. if (len<0) {
  278. /* FIX ME -- get the exact err num and text */
  279. tds_client_msg(tds->tds_ctx, tds,10018, 9, 0, 0, "The connection was closed");
  280. CLOSE(tds->s);
  281. tds->s=0;
  282.                  tds->in_len=0;
  283. tds->in_pos=0;
  284. return -1;
  285. }
  286. /* GW ADDED */
  287. /*  Not sure if this is the best way to do the error 
  288. **  handling here but this is the way it is currently 
  289. **  being done. */
  290.                 tds->in_len=0;
  291. tds->in_pos=0;
  292. tds->last_packet=1;
  293. if (len==0) {
  294. CLOSE(tds->s);
  295. tds->s=0;
  296. }
  297. return -1;
  298. }
  299. tdsdump_log(TDS_DBG_NETWORK, "Received header @ %Ln%Dn", header, sizeof(header));
  300. /* Note:
  301. ** this was done by Gregg, I don't think its the real solution (it breaks
  302. ** under 5.0, but I haven't gotten a result big enough to test this yet.
  303. */
  304. if (IS_TDS42(tds)) {
  305. if (header[0]!=0x04 && header[0]!=0x0f) {
  306. tdsdump_log(TDS_DBG_ERROR, "Invalid packet header %dn", header[0]);
  307. /*  Not sure if this is the best way to do the error 
  308. **  handling here but this is the way it is currently 
  309. **  being done. */
  310. tds->in_len=0;
  311. tds->in_pos=0;
  312. tds->last_packet=1;
  313. return(-1);
  314. }
  315. }
  316.  
  317.         /* Convert our packet length from network to host byte order */
  318.         len = ((((unsigned int)header[2])<<8)|header[3])-8;
  319.         need=len;
  320.         /* If this packet size is the largest we have gotten allocate 
  321. ** space for it */
  322. if (len > tds->in_buf_max) {
  323. unsigned char *p;
  324. if (! tds->in_buf) {
  325. p = (unsigned char*)malloc(len);
  326. } else {
  327. p = (unsigned char*)realloc(tds->in_buf, len);
  328. }
  329. if (!p) return -1; /* FIXME should close socket too */
  330. tds->in_buf = p;
  331. /* Set the new maximum packet size */
  332. tds->in_buf_max = len;
  333. }
  334. /* Clean out the in_buf so we don't use old stuff by mistake */
  335. memset(tds->in_buf, 0, tds->in_buf_max);
  336. /* Now get exactly how many bytes the server told us to get */
  337. have=0;
  338. while(need>0) {
  339. if ((x=goodread(tds, tds->in_buf+have, need))<1) {
  340. /*  Not sure if this is the best way to do the error 
  341. **  handling here but this is the way it is currently 
  342. **  being done. */
  343. tds->in_len=0;
  344. tds->in_pos=0;
  345. tds->last_packet=1;
  346. if (len==0) {
  347. CLOSE(tds->s);
  348. tds->s=0;
  349. }
  350. return(-1);
  351. }
  352. have+=x;
  353. need-=x;
  354. }
  355. if (x < 1 ) {
  356. /*  Not sure if this is the best way to do the error handling 
  357. **  here but this is the way it is currently being done. */
  358. tds->in_len=0;
  359. tds->in_pos=0;
  360. tds->last_packet=1;
  361. /* return 0 if header found but no payload */
  362. return len ? -1 : 0;
  363. }
  364. /* Set the last packet flag */
  365. if (header[1]) { tds->last_packet = 1; }
  366. else           { tds->last_packet = 0; }
  367. /* Set the length and pos (not sure what pos is used for now */
  368. tds->in_len = have;
  369. tds->in_pos = 0;
  370. tdsdump_log(TDS_DBG_NETWORK, "Received packet @ %Ln%Dn", tds->in_buf, tds->in_len);
  371. return (tds->in_len);
  372. }