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