Line data Source code
1 : /* TDSPool - Connection pooling for TDS based databases
2 : * Copyright (C) 2001 Brian Bruns
3 : *
4 : * This program is free software; you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation; either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program; if not, write to the Free Software
16 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 : *
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <stdarg.h>
23 : #include <stdio.h>
24 : #include <assert.h>
25 :
26 : #if HAVE_STDLIB_H
27 : #include <stdlib.h>
28 : #endif /* HAVE_STDLIB_H */
29 :
30 : #if HAVE_UNISTD_H
31 : #include <unistd.h>
32 : #endif /* HAVE_UNISTD_H */
33 :
34 : #if HAVE_ERRNO_H
35 : #include <errno.h>
36 : #endif /* HAVE_ERRNO_H */
37 :
38 : #include <ctype.h>
39 :
40 : #include "pool.h"
41 : #include <freetds/utils/string.h>
42 : #include <freetds/tds/checks.h>
43 : #include <freetds/bytes.h>
44 :
45 : void
46 782 : dump_login(TDSLOGIN *login)
47 : {
48 1564 : fprintf(stderr, "host %s\n", tds_dstr_cstr(&login->client_host_name));
49 1564 : fprintf(stderr, "user %s\n", tds_dstr_cstr(&login->user_name));
50 1564 : fprintf(stderr, "pass %s\n", tds_dstr_cstr(&login->password));
51 1564 : fprintf(stderr, "app %s\n", tds_dstr_cstr(&login->app_name));
52 1564 : fprintf(stderr, "srvr %s\n", tds_dstr_cstr(&login->server_name));
53 782 : fprintf(stderr, "vers %d.%d\n", TDS_MAJOR(login), TDS_MINOR(login));
54 1564 : fprintf(stderr, "lib %s\n", tds_dstr_cstr(&login->library));
55 1564 : fprintf(stderr, "lang %s\n", tds_dstr_cstr(&login->language));
56 1564 : fprintf(stderr, "char %s\n", tds_dstr_cstr(&login->server_charset));
57 782 : fprintf(stderr, "bsiz %d\n", login->block_size);
58 782 : }
59 :
60 : /**
61 : * Read part of packet. Function does not block.
62 : * @return true if packet is not complete and we must call again,
63 : * false on full packet or error.
64 : */
65 : bool
66 69365 : pool_packet_read(TDSSOCKET *tds)
67 : {
68 : unsigned int packet_len;
69 : int readed;
70 :
71 69365 : tdsdump_log(TDS_DBG_INFO1, "tds in_len %d in_pos %d\n", tds->in_len, tds->in_pos);
72 :
73 : // TODO MARS
74 :
75 : /* determine packet size */
76 69365 : packet_len = tds->in_len >= 4 ? TDS_GET_A2BE(&tds->in_buf[2]) : 8;
77 69365 : if (TDS_UNLIKELY(packet_len < 8)) {
78 0 : tds->in_len = 0;
79 0 : return false;
80 : }
81 :
82 : /* get another packet */
83 69365 : if (tds->in_len >= packet_len) {
84 : /* packet was not fully forwarded */
85 35571 : if (tds->in_pos < tds->in_len)
86 : return false;
87 35571 : tds->in_pos = 0;
88 35571 : tds->in_len = 0;
89 : }
90 :
91 : for (;;) {
92 : /* determine packet size */
93 139231 : packet_len = 8;
94 139231 : if (tds->in_len >= 4) {
95 70390 : packet_len = TDS_GET_A2BE(&tds->in_buf[2]);
96 70390 : if (packet_len < 8)
97 : break;
98 70390 : tdsdump_log(TDS_DBG_INFO1, "packet_len %u in_len %d\n", packet_len, tds->in_len);
99 : /* resize packet if not enough */
100 70390 : if (packet_len > tds->recv_packet->capacity) {
101 : TDSPACKET *packet;
102 :
103 281 : packet = tds_realloc_packet(tds->recv_packet, packet_len);
104 281 : if (!packet)
105 : break;
106 281 : tds->in_buf = packet->buf;
107 281 : tds->recv_packet = packet;
108 : }
109 70390 : CHECK_TDS_EXTRA(tds);
110 70390 : if (tds->in_len >= packet_len)
111 : return false;
112 : }
113 :
114 104440 : assert(packet_len > tds->in_len);
115 104440 : assert(packet_len <= tds->recv_packet->capacity);
116 104440 : assert(tds->in_len < tds->recv_packet->capacity);
117 :
118 104440 : readed = READSOCKET(tds_get_s(tds), &tds->in_buf[tds->in_len], packet_len - tds->in_len);
119 104440 : tdsdump_log(TDS_DBG_INFO1, "readed %d\n", readed);
120 :
121 : /* socket closed */
122 104440 : if (readed == 0)
123 : break;
124 :
125 : /* error */
126 103665 : if (readed < 0) {
127 33799 : int err = sock_errno;
128 :
129 33799 : if (err == EINTR)
130 0 : continue;
131 33799 : if (TDSSOCK_WOULDBLOCK(err))
132 : return true;
133 : break;
134 : }
135 :
136 : /* got some data */
137 69866 : tds->in_len += readed;
138 : }
139 :
140 : /* failure */
141 780 : tds->in_len = 0;
142 780 : return false;
143 : }
144 :
145 : int
146 34792 : pool_write(TDS_SYS_SOCKET sock, const void *buf, size_t len)
147 : {
148 : int ret;
149 34792 : const unsigned char *p = (const unsigned char *) buf;
150 :
151 104376 : while (len) {
152 34793 : ret = WRITESOCKET(sock, p, len);
153 34793 : if (ret <= 0) {
154 1 : int err = errno;
155 :
156 1 : if (TDSSOCK_WOULDBLOCK(err) || err == EINTR)
157 : break;
158 : return -1;
159 : }
160 34792 : p += ret;
161 34792 : len -= ret;
162 : }
163 34792 : return p - (const unsigned char *) buf;
164 : }
165 :
166 : void
167 1562 : pool_event_add(TDS_POOL *pool, TDS_POOL_EVENT *ev, TDS_POOL_EXECUTE execute)
168 : {
169 1562 : tds_mutex_lock(&pool->events_mtx);
170 1562 : ev->execute = execute;
171 1562 : ev->next = pool->events;
172 1562 : pool->events = ev;
173 1562 : tds_mutex_unlock(&pool->events_mtx);
174 1562 : WRITESOCKET(pool->event_fd, "x", 1);
175 1562 : }
176 :
177 : bool
178 34792 : pool_write_data(TDS_POOL_SOCKET *from, TDS_POOL_SOCKET *to)
179 : {
180 : int ret;
181 : TDSSOCKET *tds;
182 :
183 34792 : tdsdump_log(TDS_DBG_INFO1, "trying to send\n");
184 :
185 34792 : tds = from->tds;
186 34792 : tdsdump_log(TDS_DBG_INFO1, "sending %d bytes\n", tds->in_len);
187 34792 : tds_connection_coalesce(to->tds);
188 : /* cf. net.c for better technique. */
189 34792 : ret = pool_write(tds_get_s(to->tds), tds->in_buf + tds->in_pos, tds->in_len - tds->in_pos);
190 : /* write failed, cleanup member */
191 34792 : if (ret < 0)
192 : return false;
193 :
194 34792 : tds->in_pos += ret;
195 34792 : if (tds->in_pos < tds->in_len) {
196 : /* partial write, schedule a future write */
197 1 : to->poll_send = true;
198 1 : from->poll_recv = false;
199 : } else {
200 34791 : to->poll_send = false;
201 34791 : from->poll_recv = true;
202 : }
203 : return true;
204 : }
|