Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns
3 : * Copyright (C) 2005 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 : #include <assert.h>
26 :
27 : #if HAVE_ERRNO_H
28 : #include <errno.h>
29 : #endif /* HAVE_ERRNO_H */
30 :
31 : #if HAVE_STDLIB_H
32 : #include <stdlib.h>
33 : #endif /* HAVE_STDLIB_H */
34 :
35 : #if HAVE_STRING_H
36 : #include <string.h>
37 : #endif /* HAVE_STRING_H */
38 :
39 : #if HAVE_UNISTD_H
40 : #include <unistd.h>
41 : #endif /* HAVE_UNISTD_H */
42 :
43 : #include <freetds/tds.h>
44 : #include <freetds/iconv.h>
45 : #include <freetds/bytes.h>
46 : #include <freetds/stream.h>
47 : #include <freetds/checks.h>
48 :
49 : #if TDS_ADDITIONAL_SPACE < 8
50 : #error Not supported
51 : #endif
52 :
53 : /**
54 : * \addtogroup network
55 : * @{
56 : */
57 :
58 : /*
59 : * CRE 01262002 making buf a void * means we can put any type without casting
60 : * much like read() and memcpy()
61 : */
62 : int
63 156852 : tds_put_n(TDSSOCKET * tds, const void *buf, size_t n)
64 : {
65 : size_t left;
66 156852 : const unsigned char *bufp = (const unsigned char *) buf;
67 :
68 473754 : for (; n;) {
69 160050 : if (tds->out_pos >= tds->out_buf_max) {
70 2698 : tds_write_packet(tds, 0x0);
71 2698 : continue;
72 : }
73 157352 : left = tds->out_buf_max - tds->out_pos;
74 157352 : if (left > n)
75 154666 : left = n;
76 157352 : if (bufp) {
77 92163 : memcpy(tds->out_buf + tds->out_pos, bufp, left);
78 92163 : bufp += left;
79 : } else {
80 65189 : memset(tds->out_buf + tds->out_pos, 0, left);
81 : }
82 157352 : tds->out_pos += (unsigned int)left;
83 157352 : n -= left;
84 : }
85 156852 : return 0;
86 : }
87 :
88 : /**
89 : * Output a string to wire
90 : * automatic translate string to unicode if needed
91 : * \return bytes written to wire
92 : * \param tds state information for the socket and the TDS protocol
93 : * \param s string to write
94 : * \param len length of string in characters, or -1 for null terminated
95 : */
96 : int
97 77036 : tds_put_string(TDSSOCKET * tds, const char *s, int len)
98 : {
99 : int res;
100 : TDSSTATICINSTREAM r;
101 : TDSDATAOUTSTREAM w;
102 : enum TDS_ICONV_ENTRY iconv_entry;
103 :
104 77036 : if (len < 0) {
105 : TDS_ENCODING *client;
106 21338 : client = &tds->conn->char_convs[client2ucs2]->from.charset;
107 :
108 21338 : if (client->min_bytes_per_char == 1) { /* ascii or UTF-8 */
109 21338 : len = (int)strlen(s);
110 0 : } else if (client->min_bytes_per_char == 2) { /* UCS-2 or variant */
111 : const char *p = s;
112 :
113 0 : while (p[0] || p[1])
114 0 : p += 2;
115 0 : len = (int)(p - s);
116 :
117 0 : } else if (client->min_bytes_per_char == 4) { /* UCS-4 or variant */
118 : const char *p = s;
119 :
120 0 : while (p[0] || p[1] || p[2] || p[3])
121 0 : p += 4;
122 0 : len = (int)(p - s);
123 : } else {
124 0 : assert(client->min_bytes_per_char < 3); /* FIXME */
125 : }
126 : }
127 :
128 77036 : assert(len >= 0);
129 :
130 : /* valid test only if client and server share a character set. TODO conversions for Sybase */
131 77036 : if (IS_TDS7_PLUS(tds->conn)) {
132 : iconv_entry = client2ucs2;
133 15312 : } else if (IS_TDS50(tds->conn)) {
134 : iconv_entry = client2server_chardata;
135 : } else {
136 0 : tds_put_n(tds, s, len);
137 0 : return len;
138 : }
139 :
140 77036 : tds_staticin_stream_init(&r, s, len);
141 77036 : tds_dataout_stream_init(&w, tds);
142 :
143 77036 : res = tds_convert_stream(tds, tds->conn->char_convs[iconv_entry], to_server, &r.stream, &w.stream);
144 77036 : return w.written;
145 : }
146 :
147 : int
148 7160 : tds_put_buf(TDSSOCKET * tds, const unsigned char *buf, int dsize, int ssize)
149 : {
150 : int cpsize;
151 :
152 7160 : cpsize = ssize > dsize ? dsize : ssize;
153 7160 : tds_put_n(tds, buf, cpsize);
154 7160 : dsize -= cpsize;
155 7160 : tds_put_n(tds, NULL, dsize);
156 14320 : return tds_put_byte(tds, cpsize);
157 : }
158 :
159 : int
160 7706 : tds_put_int8(TDSSOCKET * tds, TDS_INT8 i)
161 : {
162 : TDS_UCHAR *p;
163 :
164 7706 : if (tds->out_pos >= tds->out_buf_max)
165 8 : tds_write_packet(tds, 0x0);
166 :
167 7706 : p = &tds->out_buf[tds->out_pos];
168 7706 : TDS_PUT_UA4LE(p, (TDS_UINT) i);
169 7706 : TDS_PUT_UA4LE(p+4, (TDS_UINT) (i >> 32));
170 7706 : tds->out_pos += 8;
171 7706 : return 0;
172 : }
173 :
174 : int
175 80423 : tds_put_int(TDSSOCKET * tds, TDS_INT i)
176 : {
177 : TDS_UCHAR *p;
178 :
179 80423 : if (tds->out_pos >= tds->out_buf_max)
180 0 : tds_write_packet(tds, 0x0);
181 :
182 80423 : p = &tds->out_buf[tds->out_pos];
183 80423 : TDS_PUT_UA4LE(p, i);
184 80423 : tds->out_pos += 4;
185 80423 : return 0;
186 : }
187 :
188 : int
189 107801 : tds_put_smallint(TDSSOCKET * tds, TDS_SMALLINT si)
190 : {
191 : TDS_UCHAR *p;
192 :
193 107801 : if (tds->out_pos >= tds->out_buf_max)
194 0 : tds_write_packet(tds, 0x0);
195 :
196 107801 : p = &tds->out_buf[tds->out_pos];
197 107801 : TDS_PUT_UA2LE(p, si);
198 107801 : tds->out_pos += 2;
199 107801 : return 0;
200 : }
201 :
202 : int
203 191483 : tds_put_byte(TDSSOCKET * tds, unsigned char c)
204 : {
205 198643 : if (tds->out_pos >= tds->out_buf_max)
206 0 : tds_write_packet(tds, 0x0);
207 198643 : tds->out_buf[tds->out_pos++] = c;
208 191483 : return 0;
209 : }
210 :
211 : int
212 4695 : tds_init_write_buf(TDSSOCKET * tds)
213 : {
214 4695 : TDS_MARK_UNDEFINED(tds->out_buf, tds->out_buf_max);
215 4695 : tds->out_pos = 8;
216 4695 : return 0;
217 : }
218 :
219 : /**
220 : * Flush packet to server
221 : * @return TDS_FAIL or TDS_SUCCESS
222 : */
223 : TDSRET
224 69755 : tds_flush_packet(TDSSOCKET * tds)
225 : {
226 69755 : TDSRET result = TDS_FAIL;
227 :
228 : /* GW added check for tds->s */
229 69755 : if (!IS_TDSDEAD(tds)) {
230 69722 : if (tds->out_pos > tds->out_buf_max)
231 18 : TDS_PROPAGATE(tds_write_packet(tds, 0x00));
232 69722 : result = tds_write_packet(tds, 0x01);
233 : }
234 : return result;
235 : }
236 :
237 : /** @} */
|