1 |
/* |
2 |
Copyright (c) 1998-2001, Robert O'Callahan |
3 |
All rights reserved. |
4 |
|
5 |
Redistribution and use in source and binary forms, with or without modification, |
6 |
are permitted provided that the following conditions are met: |
7 |
|
8 |
Redistributions of source code must retain the above copyright notice, this list of |
9 |
conditions and the following disclaimer. |
10 |
|
11 |
Redistributions in binary form must reproduce the above copyright notice, this list |
12 |
of conditions and the following disclaimer in the documentation and/or other materials |
13 |
provided with the distribution. |
14 |
|
15 |
The name of Robert O'Callahan may not be used to endorse or promote products derived from |
16 |
this software without specific prior written permission. |
17 |
|
18 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND |
19 |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 |
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
21 |
THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
23 |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
25 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
26 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 |
*/ |
28 |
|
29 |
/* |
30 |
This code is copyright (C) 1998-1999 Robert O'Callahan. |
31 |
See LICENSE.TXT for the license. |
32 |
*/ |
33 |
|
34 |
#include "ttxssh.h" |
35 |
|
36 |
void UTIL_init_sock_write_buf(UTILSockWriteBuf FAR * buf) |
37 |
{ |
38 |
buf_create(&buf->bufdata, &buf->buflen); |
39 |
buf->datastart = 0; |
40 |
buf->datalen = 0; |
41 |
} |
42 |
|
43 |
static int send_until_block(PTInstVar pvar, SOCKET s, |
44 |
const char FAR * data, int len) |
45 |
{ |
46 |
int total_sent = 0; |
47 |
|
48 |
while (len > 0) { |
49 |
int sent_amount = (pvar->Psend) (s, data, len, 0); |
50 |
|
51 |
if (sent_amount < 0) { |
52 |
if (WSAGetLastError() == WSAEWOULDBLOCK) { |
53 |
return total_sent; |
54 |
} else { |
55 |
return sent_amount; |
56 |
} |
57 |
} else { |
58 |
total_sent += sent_amount; |
59 |
data += sent_amount; |
60 |
len -= sent_amount; |
61 |
} |
62 |
} |
63 |
|
64 |
return total_sent; |
65 |
} |
66 |
|
67 |
BOOL UTIL_sock_buffered_write(PTInstVar pvar, UTILSockWriteBuf FAR * buf, |
68 |
UTILBlockingWriteCallback blocking_write, |
69 |
SOCKET socket, const char FAR * data, |
70 |
int len) |
71 |
{ |
72 |
int curlen; |
73 |
int desiredlen; |
74 |
int space_required; |
75 |
int amount_to_write_from_buffer; |
76 |
BOOL did_block = FALSE; |
77 |
int first_copy_start; |
78 |
int first_copy_amount; |
79 |
|
80 |
/* Fast path case: buffer is empty, try nonblocking write */ |
81 |
if (buf->datalen == 0) { |
82 |
#if 0 |
83 |
int sent_amount = send_until_block(pvar, socket, data, len); |
84 |
|
85 |
if (sent_amount < 0) { |
86 |
return FALSE; |
87 |
} |
88 |
data += sent_amount; |
89 |
len -= sent_amount; |
90 |
#else |
91 |
// �m���u���b�L���O���[�h�������������������A���~���������������A�o�O�����������A |
92 |
// �����������������B�������A�������u���b�L���O���[�h���g���A�m�������M�����������B |
93 |
// �|�[�g�]��(local-to-remote)���������A�������p�P�b�g�����M���������������������B |
94 |
// (2007.11.29 yutaka) |
95 |
if (!blocking_write(pvar, socket, data, len)) { |
96 |
return FALSE; |
97 |
} else { |
98 |
len = 0; |
99 |
} |
100 |
#endif |
101 |
} |
102 |
|
103 |
if (len == 0) { |
104 |
return TRUE; |
105 |
} |
106 |
|
107 |
/* We blocked or the buffer has data in it. We need to put this data |
108 |
into the buffer. |
109 |
First, expand buffer as much as possible and necessary. */ |
110 |
curlen = buf->buflen; |
111 |
desiredlen = |
112 |
min(pvar->session_settings.WriteBufferSize, buf->datalen + len); |
113 |
|
114 |
if (curlen < desiredlen) { |
115 |
int wrap_amount = buf->datastart + buf->datalen - curlen; |
116 |
int newlen = |
117 |
min(pvar->session_settings.WriteBufferSize, 2 * desiredlen); |
118 |
|
119 |
buf->bufdata = realloc(buf->bufdata, newlen); |
120 |
buf->buflen = newlen; |
121 |
|
122 |
if (wrap_amount > 0) { |
123 |
int wrap_to_copy = min(wrap_amount, newlen - curlen); |
124 |
|
125 |
memmove(buf->bufdata + curlen, buf->bufdata, wrap_to_copy); |
126 |
memmove(buf->bufdata, buf->bufdata + wrap_to_copy, |
127 |
wrap_amount - wrap_to_copy); |
128 |
} |
129 |
} |
130 |
|
131 |
/* 1) Write data from buffer |
132 |
2) Write data from user |
133 |
3) Copy remaining user data into buffer |
134 |
*/ |
135 |
space_required = max(0, buf->datalen + len - buf->buflen); |
136 |
amount_to_write_from_buffer = min(buf->datalen, space_required); |
137 |
|
138 |
if (amount_to_write_from_buffer > 0) { |
139 |
int first_part = |
140 |
min(amount_to_write_from_buffer, buf->buflen - buf->datastart); |
141 |
|
142 |
did_block = TRUE; |
143 |
if (!blocking_write |
144 |
(pvar, socket, buf->bufdata + buf->datastart, first_part)) { |
145 |
return FALSE; |
146 |
} |
147 |
if (first_part < amount_to_write_from_buffer) { |
148 |
if (!blocking_write |
149 |
(pvar, socket, buf->bufdata, |
150 |
amount_to_write_from_buffer - first_part)) { |
151 |
return FALSE; |
152 |
} |
153 |
} |
154 |
|
155 |
buf->datalen -= amount_to_write_from_buffer; |
156 |
if (buf->datalen == 0) { |
157 |
buf->datastart = 0; |
158 |
} else { |
159 |
buf->datastart = |
160 |
(buf->datastart + |
161 |
amount_to_write_from_buffer) % buf->buflen; |
162 |
} |
163 |
space_required -= amount_to_write_from_buffer; |
164 |
} |
165 |
|
166 |
if (space_required > 0) { |
167 |
did_block = TRUE; |
168 |
if (!blocking_write(pvar, socket, data, space_required)) { |
169 |
return FALSE; |
170 |
} |
171 |
data += space_required; |
172 |
len -= space_required; |
173 |
} |
174 |
|
175 |
first_copy_start = (buf->datastart + buf->datalen) % buf->buflen; |
176 |
first_copy_amount = min(len, buf->buflen - first_copy_start); |
177 |
memcpy(buf->bufdata + first_copy_start, data, first_copy_amount); |
178 |
if (first_copy_amount < len) { |
179 |
memcpy(buf->bufdata, data + first_copy_amount, |
180 |
len - first_copy_amount); |
181 |
} |
182 |
buf->datalen += len; |
183 |
|
184 |
if (did_block) { |
185 |
return UTIL_sock_write_more(pvar, buf, socket); |
186 |
} else { |
187 |
return TRUE; |
188 |
} |
189 |
} |
190 |
|
191 |
BOOL UTIL_sock_write_more(PTInstVar pvar, UTILSockWriteBuf FAR * buf, |
192 |
SOCKET socket) |
193 |
{ |
194 |
int first_amount = min(buf->buflen - buf->datastart, buf->datalen); |
195 |
int sent = |
196 |
send_until_block(pvar, socket, buf->bufdata + buf->datastart, |
197 |
first_amount); |
198 |
|
199 |
if (sent < 0) { |
200 |
return FALSE; |
201 |
} else { |
202 |
if (sent == first_amount && first_amount < buf->datalen) { |
203 |
int sentmore = |
204 |
send_until_block(pvar, socket, buf->bufdata, |
205 |
buf->datalen - first_amount); |
206 |
|
207 |
if (sentmore < 0) { |
208 |
return FALSE; |
209 |
} |
210 |
sent += sentmore; |
211 |
} |
212 |
|
213 |
buf->datalen -= sent; |
214 |
if (buf->datalen == 0) { |
215 |
buf->datastart = 0; |
216 |
} else { |
217 |
buf->datastart = (buf->datastart + sent) % buf->buflen; |
218 |
} |
219 |
} |
220 |
|
221 |
return TRUE; |
222 |
} |
223 |
|
224 |
void UTIL_destroy_sock_write_buf(UTILSockWriteBuf FAR * buf) |
225 |
{ |
226 |
memset(buf->bufdata, 0, buf->buflen); |
227 |
buf_destroy(&buf->bufdata, &buf->buflen); |
228 |
} |
229 |
|
230 |
BOOL UTIL_is_sock_deeply_buffered(UTILSockWriteBuf FAR * buf) |
231 |
{ |
232 |
return buf->buflen / 2 < buf->datalen; |
233 |
} |
234 |
|
235 |
void UTIL_get_lang_msg(PCHAR key, PTInstVar pvar, PCHAR def) |
236 |
{ |
237 |
GetI18nStr("TTSSH", key, pvar->ts->UIMsg, sizeof(pvar->ts->UIMsg), |
238 |
def, pvar->ts->UILanguageFile); |
239 |
} |
240 |
|
241 |
int UTIL_get_lang_font(PCHAR key, HWND dlg, PLOGFONT logfont, HFONT *font, PTInstVar pvar) |
242 |
{ |
243 |
if (GetI18nLogfont("TTSSH", key, logfont, |
244 |
GetDeviceCaps(GetDC(dlg),LOGPIXELSY), |
245 |
pvar->ts->UILanguageFile) == FALSE) { |
246 |
return FALSE; |
247 |
} |
248 |
|
249 |
if ((*font = CreateFontIndirect(logfont)) == NULL) { |
250 |
return FALSE; |
251 |
} |
252 |
|
253 |
return TRUE; |
254 |
} |
255 |
|
256 |
BOOL is_NT4() |
257 |
{ |
258 |
OSVERSIONINFO osvi; |
259 |
|
260 |
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
261 |
GetVersionEx(&osvi); |
262 |
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && |
263 |
osvi.dwMajorVersion == 4) { |
264 |
return TRUE; |
265 |
} |
266 |
return FALSE; |
267 |
} |