source: filezilla/trunk/fuentes/src/putty/windows/winhsock.c @ 3185

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 2 years ago

Update new version: 3.15.02

File size: 8.5 KB
Line 
1/*
2 * General mechanism for wrapping up reading/writing of Windows
3 * HANDLEs into a PuTTY Socket abstraction.
4 */
5
6#include <stdio.h>
7#include <assert.h>
8#include <limits.h>
9
10#define DEFINE_PLUG_METHOD_MACROS
11#include "tree234.h"
12#include "putty.h"
13#include "network.h"
14
15typedef struct Socket_handle_tag *Handle_Socket;
16
17struct Socket_handle_tag {
18    const struct socket_function_table *fn;
19    /* the above variable absolutely *must* be the first in this structure */
20
21    HANDLE send_H, recv_H, stderr_H;
22    struct handle *send_h, *recv_h, *stderr_h;
23
24    /*
25     * Freezing one of these sockets is a slightly fiddly business,
26     * because the reads from the handle are happening in a separate
27     * thread as blocking system calls and so once one is in progress
28     * it can't sensibly be interrupted. Hence, after the user tries
29     * to freeze one of these sockets, it's unavoidable that we may
30     * receive one more load of data before we manage to get
31     * winhandl.c to stop reading.
32     */
33    enum {
34        UNFROZEN,  /* reading as normal */
35        FREEZING,  /* have been set to frozen but winhandl is still reading */
36        FROZEN,    /* really frozen - winhandl has been throttled */
37        THAWING    /* we're gradually releasing our remaining data */
38    } frozen;
39    /* We buffer data here if we receive it from winhandl while frozen. */
40    bufchain inputdata;
41
42    /* Data received from stderr_H, if we have one. */
43    bufchain stderrdata;
44
45    char *error;
46
47    Plug plug;
48};
49
50static int handle_gotdata(struct handle *h, void *data, int len)
51{
52    Handle_Socket ps = (Handle_Socket) handle_get_privdata(h);
53
54    if (len < 0) {
55        return plug_closing(ps->plug, "Read error from handle",
56                            0, 0);
57    } else if (len == 0) {
58        return plug_closing(ps->plug, NULL, 0, 0);
59    } else {
60        assert(ps->frozen != FREEZING && ps->frozen != THAWING);
61        if (ps->frozen == FREEZING) {
62            /*
63             * If we've received data while this socket is supposed to
64             * be frozen (because the read winhandl.c started before
65             * sk_set_frozen was called has now returned) then buffer
66             * the data for when we unfreeze.
67             */
68            bufchain_add(&ps->inputdata, data, len);
69
70            /*
71             * And return a very large backlog, to prevent further
72             * data arriving from winhandl until we unfreeze.
73             */
74            return INT_MAX;
75        } else {
76            return plug_receive(ps->plug, 0, data, len);
77        }
78    }
79}
80
81static int handle_stderr(struct handle *h, void *data, int len)
82{
83    Handle_Socket ps = (Handle_Socket) handle_get_privdata(h);
84
85    if (len > 0)
86        log_proxy_stderr(ps->plug, &ps->stderrdata, data, len);
87
88    return 0;
89}
90
91static void handle_sentdata(struct handle *h, int new_backlog)
92{
93    Handle_Socket ps = (Handle_Socket) handle_get_privdata(h);
94   
95    plug_sent(ps->plug, new_backlog);
96}
97
98static Plug sk_handle_plug(Socket s, Plug p)
99{
100    Handle_Socket ps = (Handle_Socket) s;
101    Plug ret = ps->plug;
102    if (p)
103        ps->plug = p;
104    return ret;
105}
106
107static void sk_handle_close(Socket s)
108{
109    Handle_Socket ps = (Handle_Socket) s;
110
111    handle_free(ps->send_h);
112    handle_free(ps->recv_h);
113    CloseHandle(ps->send_H);
114    if (ps->recv_H != ps->send_H)
115        CloseHandle(ps->recv_H);
116    bufchain_clear(&ps->inputdata);
117    bufchain_clear(&ps->stderrdata);
118
119    sfree(ps);
120}
121
122static int sk_handle_write(Socket s, const char *data, int len)
123{
124    Handle_Socket ps = (Handle_Socket) s;
125
126    return handle_write(ps->send_h, data, len);
127}
128
129static int sk_handle_write_oob(Socket s, const char *data, int len)
130{
131    /*
132     * oob data is treated as inband; nasty, but nothing really
133     * better we can do
134     */
135    return sk_handle_write(s, data, len);
136}
137
138static void sk_handle_write_eof(Socket s)
139{
140    Handle_Socket ps = (Handle_Socket) s;
141
142    handle_write_eof(ps->send_h);
143}
144
145static void sk_handle_flush(Socket s)
146{
147    /* Handle_Socket ps = (Handle_Socket) s; */
148    /* do nothing */
149}
150
151static void handle_socket_unfreeze(void *psv)
152{
153    Handle_Socket ps = (Handle_Socket) psv;
154    void *data;
155    int len, new_backlog;
156
157    /*
158     * If we've been put into a state other than THAWING since the
159     * last callback, then we're done.
160     */
161    if (ps->frozen != THAWING)
162        return;
163
164    /*
165     * Get some of the data we've buffered.
166     */
167    bufchain_prefix(&ps->inputdata, &data, &len);
168    assert(len > 0);
169
170    /*
171     * Hand it off to the plug.
172     */
173    new_backlog = plug_receive(ps->plug, 0, data, len);
174
175    if (bufchain_size(&ps->inputdata) > 0) {
176        /*
177         * If there's still data in our buffer, stay in THAWING state,
178         * and reschedule ourself.
179         */
180        queue_toplevel_callback(handle_socket_unfreeze, ps);
181    } else {
182        /*
183         * Otherwise, we've successfully thawed!
184         */
185        ps->frozen = UNFROZEN;
186        handle_unthrottle(ps->recv_h, new_backlog);
187    }
188}
189
190static void sk_handle_set_frozen(Socket s, int is_frozen)
191{
192    Handle_Socket ps = (Handle_Socket) s;
193
194    if (is_frozen) {
195        switch (ps->frozen) {
196          case FREEZING:
197          case FROZEN:
198            return;                    /* nothing to do */
199
200          case THAWING:
201            /*
202             * We were in the middle of emptying our bufchain, and got
203             * frozen again. In that case, winhandl.c is already
204             * throttled, so just return to FROZEN state. The toplevel
205             * callback will notice and disable itself.
206             */
207            ps->frozen = FROZEN;
208            break;
209
210          case UNFROZEN:
211            /*
212             * The normal case. Go to FREEZING, and expect one more
213             * load of data from winhandl if we're unlucky.
214             */
215            ps->frozen = FREEZING;
216            break;
217        }
218    } else {
219        switch (ps->frozen) {
220          case UNFROZEN:
221          case THAWING:
222            return;                    /* nothing to do */
223
224          case FREEZING:
225            /*
226             * If winhandl didn't send us any data throughout the time
227             * we were frozen, then we'll still be in this state and
228             * can just unfreeze in the trivial way.
229             */
230            assert(bufchain_size(&ps->inputdata) == 0);
231            ps->frozen = UNFROZEN;
232            break;
233
234          case FROZEN:
235            /*
236             * If we have buffered data, go to THAWING and start
237             * releasing it in top-level callbacks.
238             */
239            ps->frozen = THAWING;
240            queue_toplevel_callback(handle_socket_unfreeze, ps);
241        }
242    }
243}
244
245static const char *sk_handle_socket_error(Socket s)
246{
247    Handle_Socket ps = (Handle_Socket) s;
248    return ps->error;
249}
250
251static char *sk_handle_peer_info(Socket s)
252{
253    Handle_Socket ps = (Handle_Socket) s;
254    ULONG pid;
255    static HMODULE kernel32_module;
256    DECL_WINDOWS_FUNCTION(static, BOOL, GetNamedPipeClientProcessId,
257                          (HANDLE, PULONG));
258
259    if (!kernel32_module) {
260        kernel32_module = load_system32_dll("kernel32.dll");
261        GET_WINDOWS_FUNCTION(kernel32_module, GetNamedPipeClientProcessId);
262    }
263
264    /*
265     * Of course, not all handles managed by this module will be
266     * server ends of named pipes, but if they are, then it's useful
267     * to log what we can find out about the client end.
268     */
269    if (p_GetNamedPipeClientProcessId &&
270        p_GetNamedPipeClientProcessId(ps->send_H, &pid))
271        return dupprintf("process id %lu", (unsigned long)pid);
272
273    return NULL;
274}
275
276Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H,
277                          Plug plug, int overlapped)
278{
279    static const struct socket_function_table socket_fn_table = {
280        sk_handle_plug,
281        sk_handle_close,
282        sk_handle_write,
283        sk_handle_write_oob,
284        sk_handle_write_eof,
285        sk_handle_flush,
286        sk_handle_set_frozen,
287        sk_handle_socket_error,
288        sk_handle_peer_info,
289    };
290
291    Handle_Socket ret;
292    int flags = (overlapped ? HANDLE_FLAG_OVERLAPPED : 0);
293
294    ret = snew(struct Socket_handle_tag);
295    ret->fn = &socket_fn_table;
296    ret->plug = plug;
297    ret->error = NULL;
298    ret->frozen = UNFROZEN;
299    bufchain_init(&ret->inputdata);
300    bufchain_init(&ret->stderrdata);
301
302    ret->recv_H = recv_H;
303    ret->recv_h = handle_input_new(ret->recv_H, handle_gotdata, ret, flags);
304    ret->send_H = send_H;
305    ret->send_h = handle_output_new(ret->send_H, handle_sentdata, ret, flags);
306    ret->stderr_H = stderr_H;
307    if (ret->stderr_H)
308        ret->stderr_h = handle_input_new(ret->stderr_H, handle_stderr,
309                                         ret, flags);
310
311    return (Socket) ret;
312}
Note: See TracBrowser for help on using the repository browser.