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
tds_put_n(TDSSOCKET * tds,const void * buf,size_t n)63 tds_put_n(TDSSOCKET * tds, const void *buf, size_t n)
64 {
65 size_t left;
66 const unsigned char *bufp = (const unsigned char *) buf;
67
68 for (; n;) {
69 if (tds->out_buf_max <= tds->out_pos) {
70 tds_write_packet(tds, 0x0);
71 continue;
72 }
73 left = tds->out_buf_max - tds->out_pos;
74 if (left > n)
75 left = n;
76 if (bufp) {
77 memcpy(tds->out_buf + tds->out_pos, bufp, left);
78 bufp += left;
79 } else {
80 memset(tds->out_buf + tds->out_pos, 0, left);
81 }
82 tds->out_pos += (unsigned int)left;
83 n -= left;
84 }
85 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
tds_put_string(TDSSOCKET * tds,const char * s,int len)97 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 if (len < 0) {
105 TDS_ENCODING *client;
106 client = &tds->conn->char_convs[client2ucs2]->from.charset;
107
108 if (client->min_bytes_per_char == 1) { /* ascii or UTF-8 */
109 len = (int)strlen(s);
110 } else if (client->min_bytes_per_char == 2) { /* UCS-2 or variant */
111 const char *p = s;
112
113 while (p[0] || p[1])
114 p += 2;
115 len = (int)(p - s);
116
117 } else if (client->min_bytes_per_char == 4) { /* UCS-4 or variant */
118 const char *p = s;
119
120 while (p[0] || p[1] || p[2] || p[3])
121 p += 4;
122 len = (int)(p - s);
123 } else {
124 assert(client->min_bytes_per_char < 3); /* FIXME */
125 }
126 }
127
128 assert(len >= 0);
129
130 /* valid test only if client and server share a character set. TODO conversions for Sybase */
131 if (IS_TDS7_PLUS(tds->conn)) {
132 iconv_entry = client2ucs2;
133 } else if (IS_TDS50(tds->conn)) {
134 iconv_entry = client2server_chardata;
135 } else {
136 tds_put_n(tds, s, len);
137 return len;
138 }
139
140 tds_staticin_stream_init(&r, s, len);
141 tds_dataout_stream_init(&w, tds);
142
143 res = tds_convert_stream(tds, tds->conn->char_convs[iconv_entry], to_server, &r.stream, &w.stream);
144 return w.written;
145 }
146
147 int
tds_put_buf(TDSSOCKET * tds,const unsigned char * buf,int dsize,int ssize)148 tds_put_buf(TDSSOCKET * tds, const unsigned char *buf, int dsize, int ssize)
149 {
150 int cpsize;
151
152 cpsize = ssize > dsize ? dsize : ssize;
153 tds_put_n(tds, buf, cpsize);
154 dsize -= cpsize;
155 tds_put_n(tds, NULL, dsize);
156 return tds_put_byte(tds, cpsize);
157 }
158
159 int
tds_put_int8(TDSSOCKET * tds,TDS_INT8 i)160 tds_put_int8(TDSSOCKET * tds, TDS_INT8 i)
161 {
162 TDS_UCHAR *p;
163
164 if (tds->out_pos >= tds->out_buf_max)
165 tds_write_packet(tds, 0x0);
166
167 p = &tds->out_buf[tds->out_pos];
168 TDS_PUT_UA4LE(p, (TDS_UINT) i);
169 TDS_PUT_UA4LE(p+4, (TDS_UINT) (i >> 32));
170 tds->out_pos += 8;
171 return 0;
172 }
173
174 int
tds_put_int(TDSSOCKET * tds,TDS_INT i)175 tds_put_int(TDSSOCKET * tds, TDS_INT i)
176 {
177 TDS_UCHAR *p;
178
179 if (tds->out_pos >= tds->out_buf_max)
180 tds_write_packet(tds, 0x0);
181
182 p = &tds->out_buf[tds->out_pos];
183 TDS_PUT_UA4LE(p, i);
184 tds->out_pos += 4;
185 return 0;
186 }
187
188 int
tds_put_smallint(TDSSOCKET * tds,TDS_SMALLINT si)189 tds_put_smallint(TDSSOCKET * tds, TDS_SMALLINT si)
190 {
191 TDS_UCHAR *p;
192
193 if (tds->out_pos >= tds->out_buf_max)
194 tds_write_packet(tds, 0x0);
195
196 p = &tds->out_buf[tds->out_pos];
197 TDS_PUT_UA2LE(p, si);
198 tds->out_pos += 2;
199 return 0;
200 }
201
202 int
tds_put_byte(TDSSOCKET * tds,unsigned char c)203 tds_put_byte(TDSSOCKET * tds, unsigned char c)
204 {
205 if (tds->out_pos >= (unsigned int)tds->out_buf_max)
206 tds_write_packet(tds, 0x0);
207 tds->out_buf[tds->out_pos++] = c;
208 return 0;
209 }
210
211 int
tds_init_write_buf(TDSSOCKET * tds)212 tds_init_write_buf(TDSSOCKET * tds)
213 {
214 TDS_MARK_UNDEFINED(tds->out_buf, tds->out_buf_max);
215 tds->out_pos = 8;
216 return 0;
217 }
218
219 /**
220 * Flush packet to server
221 * @return TDS_FAIL or TDS_SUCCESS
222 */
223 TDSRET
tds_flush_packet(TDSSOCKET * tds)224 tds_flush_packet(TDSSOCKET * tds)
225 {
226 TDSRET result = TDS_FAIL;
227
228 /* GW added check for tds->s */
229 if (!IS_TDSDEAD(tds)) {
230 if (tds->out_pos > tds->out_buf_max) {
231 result = tds_write_packet(tds, 0x00);
232 if (TDS_FAILED(result))
233 return result;
234 }
235 result = tds_write_packet(tds, 0x01);
236 }
237 return result;
238 }
239
240 /** @} */
241