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 /**
50 * \addtogroup network
51 * @{
52 */
53
54 /*
55 * CRE 01262002 making buf a void * means we can put any type without casting
56 * much like read() and memcpy()
57 */
58 int
tds_put_n(TDSSOCKET * tds,const void * buf,size_t n)59 tds_put_n(TDSSOCKET * tds, const void *buf, size_t n)
60 {
61 size_t left;
62 const unsigned char *bufp = (const unsigned char *) buf;
63
64 for (; n;) {
65 if (tds->out_buf_max <= tds->out_pos) {
66 tds_write_packet(tds, 0x0);
67 continue;
68 }
69 left = tds->out_buf_max - tds->out_pos;
70 if (left > n)
71 left = n;
72 if (bufp) {
73 memcpy(tds->out_buf + tds->out_pos, bufp, left);
74 bufp += left;
75 } else {
76 memset(tds->out_buf + tds->out_pos, 0, left);
77 }
78 tds->out_pos += (unsigned int)left;
79 n -= left;
80 }
81 return 0;
82 }
83
84 /**
85 * Output a string to wire
86 * automatic translate string to unicode if needed
87 * \return bytes written to wire
88 * \param tds state information for the socket and the TDS protocol
89 * \param s string to write
90 * \param len length of string in characters, or -1 for null terminated
91 */
92 int
tds_put_string(TDSSOCKET * tds,const char * s,int len)93 tds_put_string(TDSSOCKET * tds, const char *s, int len)
94 {
95 /* int res; */
96 TDSSTATICINSTREAM r;
97 TDSDATAOUTSTREAM w;
98
99
100 if (len < 0) {
101 TDS_ENCODING *client;
102 client = &tds->conn->char_convs[client2ucs2]->from.charset;
103
104 if (client->min_bytes_per_char == 1) { /* ascii or UTF-8 */
105 len = (int)strlen(s);
106 } else if (client->min_bytes_per_char == 2) { /* UCS-2 or variant */
107 const char *p = s;
108
109 while (p[0] || p[1])
110 p += 2;
111 len = (int)(p - s);
112
113 } else if (client->min_bytes_per_char == 4) { /* UCS-4 or variant */
114 const char *p = s;
115
116 while (p[0] || p[1] || p[2] || p[3])
117 p += 4;
118 len = (int)(p - s);
119 } else {
120 assert(client->min_bytes_per_char < 3); /* FIXME */
121 }
122 }
123
124 assert(len >= 0);
125
126 /* valid test only if client and server share a character set. TODO conversions for Sybase */
127 if (!IS_TDS7_PLUS(tds->conn)) {
128 tds_put_n(tds, s, len);
129 return len;
130 }
131
132 tds_staticin_stream_init(&r, s, len);
133 tds_dataout_stream_init(&w, tds);
134
135 /* res = */ tds_convert_stream(tds, tds->conn->char_convs[client2ucs2],
136 to_server, &r.stream, &w.stream);
137 return w.written;
138 }
139
140 int
tds_put_buf(TDSSOCKET * tds,const unsigned char * buf,int dsize,int ssize)141 tds_put_buf(TDSSOCKET * tds, const unsigned char *buf, int dsize, int ssize)
142 {
143 int cpsize;
144
145 cpsize = ssize > dsize ? dsize : ssize;
146 tds_put_n(tds, buf, cpsize);
147 dsize -= cpsize;
148 tds_put_n(tds, NULL, dsize);
149 return tds_put_byte(tds, cpsize);
150 }
151
152 int
tds_put_int8(TDSSOCKET * tds,TDS_INT8 i)153 tds_put_int8(TDSSOCKET * tds, TDS_INT8 i)
154 {
155 #if TDS_ADDITIONAL_SPACE < 8
156 #if WORDS_BIGENDIAN
157 TDS_UINT h;
158
159 if (tds->conn->emul_little_endian) {
160 h = (TDS_UINT) i;
161 tds_put_byte(tds, h & 0x000000FF);
162 tds_put_byte(tds, (h & 0x0000FF00) >> 8);
163 tds_put_byte(tds, (h & 0x00FF0000) >> 16);
164 tds_put_byte(tds, (h & 0xFF000000) >> 24);
165 h = (TDS_UINT) (i >> 32);
166 tds_put_byte(tds, h & 0x000000FF);
167 tds_put_byte(tds, (h & 0x0000FF00) >> 8);
168 tds_put_byte(tds, (h & 0x00FF0000) >> 16);
169 tds_put_byte(tds, (h & 0xFF000000) >> 24);
170 return 0;
171 }
172 #endif
173 return tds_put_n(tds, (const unsigned char *) &i, sizeof(TDS_INT8));
174 #else
175 TDS_UCHAR *p;
176
177 if (tds->out_pos >= tds->out_buf_max)
178 tds_write_packet(tds, 0x0);
179
180 p = &tds->out_buf[tds->out_pos];
181 #if WORDS_BIGENDIAN
182 if (tds->conn->emul_little_endian) {
183 TDS_PUT_UA4LE(p, (TDS_UINT) i);
184 TDS_PUT_UA4LE(p+4, (TDS_UINT) (i >> 32));
185 } else {
186 TDS_PUT_UA4(p, (TDS_UINT) (i >> 32));
187 TDS_PUT_UA4(p+4, (TDS_UINT) i);
188 }
189 #else
190 TDS_PUT_UA4(p, (TDS_UINT) i);
191 TDS_PUT_UA4(p+4, (TDS_UINT) (i >> 32));
192 #endif
193 tds->out_pos += 8;
194 return 0;
195 #endif
196 }
197
198 int
tds_put_int(TDSSOCKET * tds,TDS_INT i)199 tds_put_int(TDSSOCKET * tds, TDS_INT i)
200 {
201 #if TDS_ADDITIONAL_SPACE < 4
202 #if WORDS_BIGENDIAN
203 if (tds->conn->emul_little_endian) {
204 tds_put_byte(tds, i & 0x000000FF);
205 tds_put_byte(tds, (i & 0x0000FF00) >> 8);
206 tds_put_byte(tds, (i & 0x00FF0000) >> 16);
207 tds_put_byte(tds, (i & 0xFF000000) >> 24);
208 return 0;
209 }
210 #endif
211 return tds_put_n(tds, (const unsigned char *) &i, sizeof(TDS_INT));
212 #else
213 TDS_UCHAR *p;
214
215 if (tds->out_pos >= tds->out_buf_max)
216 tds_write_packet(tds, 0x0);
217
218 p = &tds->out_buf[tds->out_pos];
219 #if WORDS_BIGENDIAN
220 if (tds->conn->emul_little_endian)
221 TDS_PUT_UA4LE(p, i);
222 else
223 TDS_PUT_UA4(p, i);
224 #else
225 TDS_PUT_UA4(p, i);
226 #endif
227 tds->out_pos += 4;
228 return 0;
229 #endif
230 }
231
232 int
tds_put_smallint(TDSSOCKET * tds,TDS_SMALLINT si)233 tds_put_smallint(TDSSOCKET * tds, TDS_SMALLINT si)
234 {
235 #if TDS_ADDITIONAL_SPACE < 2
236 #if WORDS_BIGENDIAN
237 if (tds->conn->emul_little_endian) {
238 tds_put_byte(tds, si & 0x000000FF);
239 tds_put_byte(tds, (si & 0x0000FF00) >> 8);
240 return 0;
241 }
242 #endif
243 return tds_put_n(tds, (const unsigned char *) &si, sizeof(TDS_SMALLINT));
244 #else
245 TDS_UCHAR *p;
246
247 if (tds->out_pos >= tds->out_buf_max)
248 tds_write_packet(tds, 0x0);
249
250 p = &tds->out_buf[tds->out_pos];
251 #if WORDS_BIGENDIAN
252 if (tds->conn->emul_little_endian)
253 TDS_PUT_UA2LE(p, si);
254 else
255 TDS_PUT_UA2(p, si);
256 #else
257 TDS_PUT_UA2(p, si);
258 #endif
259 tds->out_pos += 2;
260 return 0;
261 #endif
262 }
263
264 int
tds_put_byte(TDSSOCKET * tds,unsigned char c)265 tds_put_byte(TDSSOCKET * tds, unsigned char c)
266 {
267 if (tds->out_pos >= (unsigned int)tds->out_buf_max)
268 tds_write_packet(tds, 0x0);
269 tds->out_buf[tds->out_pos++] = c;
270 return 0;
271 }
272
273 int
tds_init_write_buf(TDSSOCKET * tds)274 tds_init_write_buf(TDSSOCKET * tds)
275 {
276 TDS_MARK_UNDEFINED(tds->out_buf, tds->out_buf_max);
277 tds->out_pos = 8;
278 return 0;
279 }
280
281 /**
282 * Flush packet to server
283 * @return TDS_FAIL or TDS_SUCCESS
284 */
285 TDSRET
tds_flush_packet(TDSSOCKET * tds)286 tds_flush_packet(TDSSOCKET * tds)
287 {
288 TDSRET result = TDS_FAIL;
289
290 /* GW added check for tds->s */
291 if (!IS_TDSDEAD(tds)) {
292 #if TDS_ADDITIONAL_SPACE != 0
293 if (tds->out_pos > tds->out_buf_max) {
294 result = tds_write_packet(tds, 0x00);
295 if (TDS_FAILED(result))
296 return result;
297 }
298 #endif
299 result = tds_write_packet(tds, 0x01);
300 }
301 return result;
302 }
303
304 /** @} */
305