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 776 : dump_login(TDSLOGIN *login)
47 : {
48 1552 : fprintf(stderr, "host %s\n", tds_dstr_cstr(&login->client_host_name));
49 1552 : fprintf(stderr, "user %s\n", tds_dstr_cstr(&login->user_name));
50 1552 : fprintf(stderr, "pass %s\n", tds_dstr_cstr(&login->password));
51 1552 : fprintf(stderr, "app %s\n", tds_dstr_cstr(&login->app_name));
52 1552 : fprintf(stderr, "srvr %s\n", tds_dstr_cstr(&login->server_name));
53 776 : fprintf(stderr, "vers %d.%d\n", TDS_MAJOR(login), TDS_MINOR(login));
54 1552 : fprintf(stderr, "lib %s\n", tds_dstr_cstr(&login->library));
55 1552 : fprintf(stderr, "lang %s\n", tds_dstr_cstr(&login->language));
56 1552 : fprintf(stderr, "char %s\n", tds_dstr_cstr(&login->server_charset));
57 776 : fprintf(stderr, "bsiz %d\n", login->block_size);
58 776 : }
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 67234 : pool_packet_read(TDSSOCKET *tds)
67 : {
68 : unsigned int packet_len;
69 : int readed;
70 :
71 67234 : 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 67234 : packet_len = tds->in_len >= 4 ? TDS_GET_A2BE(&tds->in_buf[2]) : 8;
77 67234 : if (TDS_UNLIKELY(packet_len < 8)) {
78 0 : tds->in_len = 0;
79 0 : return false;
80 : }
81 :
82 : /* get another packet */
83 67234 : if (tds->in_len >= packet_len) {
84 : /* packet was not fully forwarded */
85 34365 : if (tds->in_pos < tds->in_len)
86 : return false;
87 34365 : tds->in_pos = 0;
88 34365 : tds->in_len = 0;
89 : }
90 :
91 : for (;;) {
92 : /* determine packet size */
93 134600 : packet_len = 8;
94 134600 : if (tds->in_len >= 4) {
95 67766 : packet_len = TDS_GET_A2BE(&tds->in_buf[2]);
96 67766 : if (packet_len < 8)
97 : break;
98 67766 : tdsdump_log(TDS_DBG_INFO1, "packet_len %u in_len %d\n", packet_len, tds->in_len);
99 : /* resize packet if not enough */
100 67766 : if (packet_len > tds->recv_packet->capacity) {
101 : TDSPACKET *packet;
102 :
103 279 : packet = tds_realloc_packet(tds->recv_packet, packet_len);
104 279 : if (!packet)
105 : break;
106 279 : tds->in_buf = packet->buf;
107 279 : tds->recv_packet = packet;
108 : }
109 67766 : CHECK_TDS_EXTRA(tds);
110 67766 : if (tds->in_len >= packet_len)
111 : return false;
112 : }
113 :
114 101009 : assert(packet_len > tds->in_len);
115 101009 : assert(packet_len <= tds->recv_packet->capacity);
116 101009 : assert(tds->in_len < tds->recv_packet->capacity);
117 :
118 101009 : readed = READSOCKET(tds_get_s(tds), &tds->in_buf[tds->in_len], packet_len - tds->in_len);
119 101009 : tdsdump_log(TDS_DBG_INFO1, "readed %d\n", readed);
120 :
121 : /* socket closed */
122 101009 : if (readed == 0)
123 : break;
124 :
125 : /* error */
126 100239 : if (readed < 0) {
127 32873 : int err = sock_errno;
128 :
129 32873 : if (err == EINTR)
130 0 : continue;
131 32873 : if (TDSSOCK_WOULDBLOCK(err))
132 : return true;
133 : break;
134 : }
135 :
136 : /* got some data */
137 67366 : tds->in_len += readed;
138 : }
139 :
140 : /* failure */
141 774 : tds->in_len = 0;
142 774 : return false;
143 : }
144 :
145 : int
146 33592 : pool_write(TDS_SYS_SOCKET sock, const void *buf, size_t len)
147 : {
148 : int ret;
149 33592 : const unsigned char *p = (const unsigned char *) buf;
150 :
151 100776 : while (len) {
152 33593 : ret = WRITESOCKET(sock, p, len);
153 33593 : if (ret <= 0) {
154 1 : int err = errno;
155 :
156 1 : if (TDSSOCK_WOULDBLOCK(err) || err == EINTR)
157 : break;
158 : return -1;
159 : }
160 33592 : p += ret;
161 33592 : len -= ret;
162 : }
163 33592 : return p - (const unsigned char *) buf;
164 : }
165 :
166 : void
167 1550 : pool_event_add(TDS_POOL *pool, TDS_POOL_EVENT *ev, TDS_POOL_EXECUTE execute)
168 : {
169 1550 : tds_mutex_lock(&pool->events_mtx);
170 1550 : ev->execute = execute;
171 1550 : ev->next = pool->events;
172 1550 : pool->events = ev;
173 1550 : tds_mutex_unlock(&pool->events_mtx);
174 1550 : WRITESOCKET(pool->event_fd, "x", 1);
175 1550 : }
176 :
177 : bool
178 33592 : pool_write_data(TDS_POOL_SOCKET *from, TDS_POOL_SOCKET *to)
179 : {
180 : int ret;
181 : TDSSOCKET *tds;
182 :
183 33592 : tdsdump_log(TDS_DBG_INFO1, "trying to send\n");
184 :
185 33592 : tds = from->tds;
186 33592 : tdsdump_log(TDS_DBG_INFO1, "sending %d bytes\n", tds->in_len);
187 33592 : tds_connection_coalesce(to->tds);
188 : /* cf. net.c for better technique. */
189 33592 : 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 33592 : if (ret < 0)
192 : return false;
193 :
194 33592 : tds->in_pos += ret;
195 33592 : 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 33591 : to->poll_send = false;
201 33591 : from->poll_recv = true;
202 : }
203 : return true;
204 : }
|