~ubuntu-branches/ubuntu/wily/maradns/wily-proposed

« back to all changes in this revision

Viewing changes to deadwood-3.2.05/src/DwTcpSocket.c

  • Committer: Package Import Robot
  • Author(s): Dariusz Dwornikowski, Tomasz Buchert, Dariusz Dwornikowski
  • Date: 2015-03-27 18:34:08 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20150327183408-wnfachdkdjt96yu6
Tags: 2.0.11-1
[ Tomasz Buchert ]
* Imported Upstream version 2.0.11

[ Dariusz Dwornikowski ]
* d/patches: 
  - refreshed all patches for new deadwood version
  - removed generating of random prime on build (Closes: #785536) 
* d/rules: date taken from changelog (Closes: #785535)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2007-2012 Sam Trenholme
2
 
 * IPv6 code contributed by Jean-Jacques Sarton in 2007
3
 
 *
4
 
 * TERMS
5
 
 *
6
 
 * Redistribution and use in source and binary forms, with or without
7
 
 * modification, are permitted provided that the following conditions
8
 
 * are met:
9
 
 *
10
 
 * 1. Redistributions of source code must retain the above copyright
11
 
 *    notice, this list of conditions and the following disclaimer.
12
 
 * 2. Redistributions in binary form must reproduce the above copyright
13
 
 *    notice, this list of conditions and the following disclaimer in the
14
 
 *    documentation and/or other materials provided with the distribution.
15
 
 *
16
 
 * This software is provided 'as is' with no guarantees of correctness or
17
 
 * fitness for purpose.
18
 
 */
19
 
 
20
 
#include "DwSocket.h"
21
 
#include "DwTcpSocket.h"
22
 
#include "DwDnsStr.h"
23
 
#include <signal.h>
24
 
#include <errno.h>
25
 
 
26
 
/* One parameter that may eventually become a dwood2rc parameter */
27
 
#define TCP_BUFFERSIZE 1024
28
 
 
29
 
/* Mararc parameters that are set in DwMararc.c */
30
 
extern dw_str *key_s[];
31
 
extern dw_str *key_d[];
32
 
extern int32_t key_n[];
33
 
 
34
 
/* Parameters set in DwSys.c */
35
 
extern int64_t the_time;
36
 
extern dwr_rg *rng_seed;
37
 
 
38
 
/* List of addresses we will bind to */
39
 
extern ip_addr_T bind_address[];
40
 
extern ip_addr_T upstream_address[];
41
 
 
42
 
/* Some global variables */
43
 
extern int max_tcp_procs;
44
 
extern int timeout_seconds;
45
 
extern int timeout_seconds_tcp;
46
 
extern int dns_port;
47
 
extern int upstream_port;
48
 
extern int num_retries;
49
 
 
50
 
tcp_pend_T *tcp_pend;
51
 
SOCKET tcp_b_local[DW_MAXIPS + 1]; /* Local sockets */
52
 
 
53
 
/* The following is needed because Winsock's "make this socket non-blocking"
54
 
 * uses a pointer to a number as one of its arguments */
55
 
#ifdef MINGW
56
 
extern u_long dont_block;
57
 
extern void windows_socket_start();
58
 
#endif /* MINGW */
59
 
 
60
 
/* The upstream server we will connect to (round robin rotated) */
61
 
 
62
 
/* Allocate the memory for the list of the open remote TCP connections.
63
 
 * This memory is never freed once allocated, because this data is always
64
 
 * used by the program */
65
 
void malloc_tcp_pend() {
66
 
        tcp_pend = dw_malloc((max_tcp_procs + 1) * sizeof(tcp_pend_T));
67
 
        if(tcp_pend == 0) {
68
 
                dw_alog_3strings("Fatal: Could not allocate tcp_pend","","");
69
 
                exit(1);
70
 
        }
71
 
}
72
 
 
73
 
/* Initialize the values of all the open remote TCP connections */
74
 
void init_tcp_b_pend() {
75
 
        int a = 0;
76
 
        for(a = 0; a < max_tcp_procs; a++) {
77
 
                init_tcp_pend(a);
78
 
        }
79
 
}
80
 
 
81
 
/* TCP bind to all IP addresses we are to bind to and return the number of
82
 
 * IP addresses we got */
83
 
int bind_all_tcp() {
84
 
        int a = 0;
85
 
        int count = 0;
86
 
        if(key_n[DWM_N_tcp_listen] != 1) {
87
 
                return 0;
88
 
        }
89
 
        for(a = 0; a < DW_MAXIPS; a++) {
90
 
                if(bind_address[a].len != 0) {
91
 
                        tcp_b_local[a] = do_bind(&bind_address[a],SOCK_STREAM);
92
 
                        if(tcp_b_local[a] != -1) {
93
 
                                count++;
94
 
                        } else {
95
 
                                return -1;
96
 
                        }
97
 
                } else {
98
 
                        tcp_b_local[a] = -1;
99
 
                }
100
 
        }
101
 
        return count;
102
 
}
103
 
 
104
 
/* Find a free pending TCP connection to use; return -1 if
105
 
 * there isn't one (we're overloaded) */
106
 
int32_t find_free_tcp_pend() {
107
 
        int32_t a = 0;
108
 
        for(a = 0; a < max_tcp_procs; a++) {
109
 
                if(tcp_pend[a].local == INVALID_SOCKET) {
110
 
                        return a;
111
 
                }
112
 
        }
113
 
        return -1; /* None available (we're overloaded) */
114
 
}
115
 
 
116
 
/* Set up a TCP server that we will use to connect to a remote host */
117
 
SOCKET setup_tcp_server(sockaddr_all_T *server, dw_str *query, int b) {
118
 
        SOCKET remote = INVALID_SOCKET;
119
 
        ip_addr_T rem_ip = {0,{0,0},0,0};
120
 
 
121
 
        rem_ip = get_upstream_ip(query,b);
122
 
        if(rem_ip.glueless != 0) {
123
 
                dw_destroy(rem_ip.glueless);
124
 
        }
125
 
        if(rem_ip.len == 4) {
126
 
                server->V4.sin_family = AF_INET;
127
 
                server->V4.sin_port = htons(upstream_port);
128
 
                memcpy(&(server->V4.sin_addr),rem_ip.ip,4);
129
 
                remote = socket(AF_INET,SOCK_STREAM,0);
130
 
#ifdef IPV6
131
 
        } else if(rem_ip.len == 16) {
132
 
                server->V6.sin6_family = AF_INET6;
133
 
                server->V6.sin6_port = htons(upstream_port);
134
 
                memcpy(&(server->V6.sin6_addr),rem_ip.ip,16);
135
 
                remote = socket(AF_INET6,SOCK_STREAM,0);
136
 
#endif /* IPV6 */
137
 
        } else {
138
 
                return INVALID_SOCKET;
139
 
        }
140
 
        return remote;
141
 
}
142
 
 
143
 
/* Given a tcp socket s, accept the connection on that socket, then
144
 
 * prepare things so we can get <len><DNS packet>, send the query in their
145
 
 * packet upstream, then send <len><DNS reply> back to the TCP client
146
 
 */
147
 
void local_tcp_accept(SOCKET s) {
148
 
        sockaddr_all_T client;
149
 
        SOCKET local = 0;
150
 
        socklen_t len = sizeof(struct sockaddr_in);
151
 
        int b = 0;
152
 
        ip_addr_T from_ip;
153
 
 
154
 
        b = find_free_tcp_pend();
155
 
        if(b == -1) { /* Out of active TCP connections */
156
 
                return;
157
 
        }
158
 
 
159
 
        len = sizeof(client);
160
 
        local = accept(s,(struct sockaddr *)&client,&len);
161
 
        make_socket_nonblock(local);
162
 
 
163
 
        if(local == INVALID_SOCKET) { /* accept() error */
164
 
                return;
165
 
        }
166
 
 
167
 
        /* This is where we do ip-based packet rejection */
168
 
        get_from_ip_port(&from_ip,&client);
169
 
        if(check_ip_acl(&from_ip) != 1) {
170
 
                closesocket(local);
171
 
                return;
172
 
        }
173
 
 
174
 
        /* At this point, we want to get the 2-byte
175
 
         * length of the DNS packet, followed by getting the DNS packet;
176
 
         * we then want to be able to send UDP queries upstream to get
177
 
         * the information we want, then we went to send the reply back
178
 
         * over TCP */
179
 
        init_tcp_pend(b);
180
 
        tcp_pend[b].buffer = dw_malloc(3); /* To put the two bytes we want */
181
 
        if(tcp_pend[b].buffer == 0) {
182
 
                closesocket(local);
183
 
                reset_tcp_pend(b);
184
 
                return;
185
 
        }
186
 
        tcp_pend[b].local = local;
187
 
        tcp_pend[b].wanted = 2; /* We want to get the two-byte DNS length
188
 
                                 * header from the client */
189
 
        tcp_pend[b].die = get_time() + ((int64_t)timeout_seconds_tcp << 8);
190
 
}
191
 
 
192
 
/* For a given pending TCP connection, see if we have all the bytes we
193
 
 * want.  If we don't, try to get the data we want */
194
 
void tcp_get_wanted(int b) {
195
 
        char *buffer = 0;
196
 
        ssize_t len = 0;
197
 
        int toget = 0;
198
 
        toget = tcp_pend[b].wanted - tcp_pend[b].got;
199
 
        if(toget > 0 && tcp_pend[b].state == 0) {
200
 
                buffer = dw_malloc(toget + 1);
201
 
                if(buffer == 0) {
202
 
                        return;
203
 
                }
204
 
                len = recv(tcp_pend[b].local,buffer,toget,MSG_DONTWAIT);
205
 
                /* Add the bytes we get to the end of the buffer of wanted
206
 
                 * bytes */
207
 
                if(len > toget || len < 0) {
208
 
                        free(buffer);
209
 
                        return;
210
 
                }
211
 
                memcpy(tcp_pend[b].buffer + tcp_pend[b].got, buffer, len);
212
 
                tcp_pend[b].got += len;
213
 
                tcp_pend[b].die = get_time() +
214
 
                        ((int64_t)timeout_seconds_tcp << 8);
215
 
                free(buffer);
216
 
        }
217
 
}
218
 
 
219
 
/* For a given TCP connection, if we have all the bytes we want, do the
220
 
 * next thing */
221
 
void tcp_process_data(int b) {
222
 
        int32_t wanted = 0;
223
 
        if(tcp_pend[b].wanted != tcp_pend[b].got || tcp_pend[b].buffer == 0
224
 
           || tcp_pend[b].state != 0) {
225
 
                return;
226
 
        }
227
 
        if(tcp_pend[b].wanted == 2) { /* If we wanted the length of the DNS
228
 
                                       * packet */
229
 
                /* Based on the length of the DNS packet wanted, we next
230
 
                 * try to get the DNS packet */
231
 
                tcp_pend[b].got = 0;
232
 
                wanted = tcp_pend[b].buffer[0];
233
 
                wanted <<= 8;
234
 
                wanted |= tcp_pend[b].buffer[1];
235
 
                free(tcp_pend[b].buffer);
236
 
                tcp_pend[b].buffer = 0;
237
 
                if(wanted < 12) {
238
 
                        closesocket(tcp_pend[b].local);
239
 
                        reset_tcp_pend(b);
240
 
                        return;
241
 
                }
242
 
                tcp_pend[b].wanted = wanted;
243
 
                tcp_pend[b].buffer = dw_malloc(wanted + 1);
244
 
                tcp_pend[b].die = get_time() +
245
 
                        ((int64_t)timeout_seconds_tcp << 8);
246
 
        } else if(tcp_pend[b].wanted >= 12) {
247
 
                tcp_to_udp(b);
248
 
        }
249
 
 
250
 
}
251
 
 
252
 
/* Convert a TCP packet on a connection in to a reply we either get from
253
 
 * the cache or send upstream via UDP */
254
 
void tcp_to_udp(int b) {
255
 
        int32_t local_id = -1;
256
 
        dw_str *query = 0, *orig_query = 0;
257
 
 
258
 
        local_id = get_dns_qid((void *)tcp_pend[b].buffer, tcp_pend[b].wanted,
259
 
                        2);
260
 
        if(local_id == -1) {
261
 
                closesocket(tcp_pend[b].local);
262
 
                reset_tcp_pend(b);
263
 
                return;
264
 
        }
265
 
 
266
 
        /* See if the data is cached */
267
 
        query = dw_get_dname_type((void *)tcp_pend[b].buffer,12,
268
 
                tcp_pend[b].wanted);
269
 
        if(query == 0) {
270
 
                closesocket(tcp_pend[b].local);
271
 
                reset_tcp_pend(b);
272
 
                return;
273
 
        }
274
 
        orig_query = dw_copy(query);
275
 
        dwc_lower_case(query);
276
 
 
277
 
        if(get_reply_from_cache(query,0,0,local_id,0,b,orig_query,0) != 1) {
278
 
                /* If not cached, make the buffer a UDP connection upstream */
279
 
                forward_local_udp_packet(1,local_id,0,0,
280
 
                        (void *)tcp_pend[b].buffer,tcp_pend[b].wanted,b,
281
 
                                orig_query);
282
 
                tcp_pend[b].state = 1; /* Awaiting UDP reply */
283
 
 
284
 
                /* "<< 10" instead of "<< 8" because we need more time to
285
 
                 * get a reply upstream */
286
 
                tcp_pend[b].die = get_time() +
287
 
                        ((int64_t)timeout_seconds_tcp << 10);
288
 
        }
289
 
 
290
 
        dw_destroy(query);
291
 
        dw_destroy(orig_query);
292
 
}
293
 
 
294
 
/* Called from the "UDP" code, this tells Deadwood to buffer a TCP
295
 
 * packet to send back to the client */
296
 
void tcp_return_reply(int b, char *packet, int len) {
297
 
        if(tcp_pend[b].buffer != 0) {
298
 
                free(tcp_pend[b].buffer);
299
 
                tcp_pend[b].buffer = 0;
300
 
        }
301
 
        tcp_pend[b].state = 2; /* Send TCP reply back to client */
302
 
        tcp_pend[b].buffer = dw_malloc(len + 3);
303
 
        /* 2-byte length header */
304
 
        tcp_pend[b].buffer[0] = ((len & 0xff00) >> 8);
305
 
        tcp_pend[b].buffer[1] = (len & 0xff);
306
 
        memcpy(tcp_pend[b].buffer + 2, packet, len);
307
 
        tcp_pend[b].wanted = len + 2;
308
 
        tcp_pend[b].got = 0;
309
 
        tcp_pend[b].die = get_time() + ((int64_t)timeout_seconds_tcp << 8);
310
 
}
311
 
 
312
 
/* This code sends back buffered data to the client who sent us the original
313
 
 * TCP request */
314
 
void tcp_send_wanted(int b) {
315
 
        ssize_t len = 0;
316
 
        int tosend = 0;
317
 
        if(tcp_pend[b].state != 2) { /* Data to return to client */
318
 
                return;
319
 
        }
320
 
        tosend = tcp_pend[b].wanted - tcp_pend[b].got;
321
 
        if(tosend > 0 && tcp_pend[b].state == 2) {
322
 
                len = send(tcp_pend[b].local,tcp_pend[b].buffer +
323
 
                           tcp_pend[b].got,tosend,MSG_DONTWAIT);
324
 
                tcp_pend[b].got += len;
325
 
                tcp_pend[b].die = get_time() +
326
 
                        ((int64_t)timeout_seconds_tcp << 8);
327
 
        } else {
328
 
                closesocket(tcp_pend[b].local);
329
 
                reset_tcp_pend(b);
330
 
        }
331
 
}
332
 
 
333
 
/* Create a DNS query packet, given a raw DNS query, as a dw_string object */
334
 
dw_str *make_dns_query_packet(dw_str *query, int id, int is_upstream) {
335
 
        dw_str *out = 0;
336
 
 
337
 
        /* Convert the query in to a DNS packet to send */
338
 
        /* 0x0180: QR = 0; Opcode = 0; AA = 0; TC = 0; RD = 1; RA = 1;
339
 
         *         Z = 0; RCODE = 0 ; 0x0080: Same but RD = 0 */
340
 
        if(is_upstream == 1) {
341
 
                out = make_dns_header(id,0x0180,0,0,0); /* Header */
342
 
        } else {
343
 
                out = make_dns_header(id,0x0080,0,0,0); /* Header */
344
 
        }
345
 
        if(out == 0) {
346
 
                goto catch_make_dns_query_packet;
347
 
        }
348
 
        if(dw_append(query,out) == -1) /* Question */ {
349
 
                goto catch_make_dns_query_packet;
350
 
        }
351
 
        if(dw_put_u16(out,1,-1) == -1) /* "class" (internet) */ {
352
 
                goto catch_make_dns_query_packet;
353
 
        }
354
 
 
355
 
        return out;
356
 
 
357
 
catch_make_dns_query_packet:
358
 
        if(out != 0) {
359
 
                dw_destroy(out);
360
 
        }
361
 
        return 0;
362
 
}
363
 
 
364
 
/* If we get a "truncated" UDP DNS packet upstream, and have connected via
365
 
 * TCP to make our original DNS query, connect via TCP to the upstream
366
 
 * server to try and get the non-truncated reply */
367
 
void tcp_truncated_retry(int b, dw_str *query, int id, int udp_id, int is_up) {
368
 
        dw_str *tmp = 0;
369
 
        sockaddr_all_T server;
370
 
        socklen_t len = sizeof(struct sockaddr_in);
371
 
 
372
 
        if(tcp_pend[b].buffer != 0) {
373
 
                free(tcp_pend[b].buffer);
374
 
                tcp_pend[b].buffer = 0;
375
 
        }
376
 
 
377
 
        /* Prepare packet to send */
378
 
        tmp = make_dns_query_packet(query,id,is_up);
379
 
        if(tmp == 0) {
380
 
                goto catch_tcp_truncated_retry;
381
 
        }
382
 
        tcp_pend[b].buffer = dw_malloc(tmp->len + 3);
383
 
        if(tcp_pend[b].buffer == 0) {
384
 
                goto catch_tcp_truncated_retry;
385
 
        }
386
 
        tcp_pend[b].buffer[0] = (tmp->len & 0xff00) >> 8; /* Header byte 1 */
387
 
        tcp_pend[b].buffer[1] = tmp->len & 0xff; /* Header byte 2 */
388
 
        memcpy(tcp_pend[b].buffer + 2, tmp->str, tmp->len); /* DNS query */
389
 
        tcp_pend[b].state = 3; /* Send buffer upstream */
390
 
        tcp_pend[b].got = 0; /* No bytes sent */
391
 
        tcp_pend[b].wanted = tmp->len + 2; /* Send entire packet */
392
 
 
393
 
        /* Connect to upstream server over TCP */
394
 
        tcp_pend[b].upstream = setup_tcp_server(&server,query,udp_id);
395
 
        if(tcp_pend[b].upstream == INVALID_SOCKET) {
396
 
                goto catch_tcp_truncated_retry;
397
 
        }
398
 
        make_socket_nonblock(tcp_pend[b].upstream);
399
 
#ifdef IPV6
400
 
        if (server.Family == AF_INET6)
401
 
                len = sizeof(struct sockaddr_in6);
402
 
#endif /* IPV6 */
403
 
        if(connect(tcp_pend[b].upstream,(struct sockaddr *)&server,len) == -1
404
 
           && SCKT_ERR != EINPROGRESS) {
405
 
                closesocket(tcp_pend[b].upstream);
406
 
                goto catch_tcp_truncated_retry;
407
 
        }
408
 
 
409
 
        /* Clean-up */
410
 
        dw_destroy(tmp);
411
 
        return;
412
 
 
413
 
catch_tcp_truncated_retry:
414
 
        if(tmp != 0) {
415
 
                dw_destroy(tmp);
416
 
        }
417
 
        closesocket(tcp_pend[b].local);
418
 
        reset_tcp_pend(b);
419
 
}
420
 
 
421
 
/* Send data via TCP to upstream DNS server */
422
 
void tcp_upstream_send(int b) {
423
 
        ssize_t len = 0;
424
 
 
425
 
        if(tcp_pend[b].state != 3) {
426
 
                return;
427
 
        }
428
 
 
429
 
        if(tcp_pend[b].wanted < tcp_pend[b].got) {
430
 
                closesocket(tcp_pend[b].local);
431
 
                closesocket(tcp_pend[b].upstream);
432
 
                reset_tcp_pend(b);
433
 
        }
434
 
 
435
 
        len = send(tcp_pend[b].upstream,tcp_pend[b].buffer + tcp_pend[b].got,
436
 
                   tcp_pend[b].wanted - tcp_pend[b].got,MSG_DONTWAIT);
437
 
 
438
 
        if(len == -1) { /* Nothing sent, try later */
439
 
                return;
440
 
        }
441
 
 
442
 
        tcp_pend[b].got += len;
443
 
        tcp_pend[b].die = get_time() + ((int64_t)timeout_seconds << 8);
444
 
        if(tcp_pend[b].got >= tcp_pend[b].wanted) { /* All sent, get ready
445
 
                                                     * for reply */
446
 
                free(tcp_pend[b].buffer);
447
 
                tcp_pend[b].buffer = 0;
448
 
                tcp_pend[b].state = 4; /* Get packet length from upstream */
449
 
        }
450
 
}
451
 
 
452
 
/* Prepare things to get the length upstream */
453
 
void tcp_prepare_upstream_len(int b) {
454
 
        if(tcp_pend[b].state != 4) {
455
 
                return;
456
 
        }
457
 
        tcp_pend[b].buffer = dw_malloc(3);
458
 
        if(tcp_pend[b].buffer == 0) {
459
 
                closesocket(tcp_pend[b].local);
460
 
                closesocket(tcp_pend[b].upstream);
461
 
                reset_tcp_pend(b);
462
 
        }
463
 
        tcp_pend[b].wanted = 2;
464
 
        tcp_pend[b].got = 0;
465
 
        tcp_pend[b].state = 5; /* Getting length from upstream */
466
 
}
467
 
 
468
 
/* Get the two-byte length packet from upstream and allocate memory
469
 
 * to store the up-and-coming packet */
470
 
void tcp_get_upstream_len(int b) {
471
 
        int32_t wanted = 0;
472
 
        int32_t toget = 0;
473
 
        ssize_t len = 0;
474
 
 
475
 
        if(tcp_pend[b].state != 5) {
476
 
                return;
477
 
        }
478
 
        toget = tcp_pend[b].wanted - tcp_pend[b].got;
479
 
        if(toget > 0) {
480
 
                len = recv(tcp_pend[b].upstream,
481
 
                                tcp_pend[b].buffer + tcp_pend[b].got,
482
 
                                toget, MSG_DONTWAIT);
483
 
                if(len <= 0) {
484
 
                        return;
485
 
                }
486
 
                tcp_pend[b].got += len;
487
 
                tcp_pend[b].die = get_time() +
488
 
                        ((int64_t)timeout_seconds_tcp << 8);
489
 
        } else if(toget == 0) {
490
 
                wanted = tcp_pend[b].buffer[0] & 0xff;
491
 
                wanted <<= 8;
492
 
                wanted |= tcp_pend[b].buffer[1] & 0xff;
493
 
                free(tcp_pend[b].buffer);
494
 
                tcp_pend[b].buffer = 0;
495
 
                tcp_pend[b].wanted = wanted;
496
 
                tcp_pend[b].buffer = dw_malloc(wanted + 3);
497
 
                tcp_pend[b].die = get_time() +
498
 
                        ((int64_t)timeout_seconds_tcp << 8);
499
 
                tcp_pend[b].state = 6;
500
 
                tcp_pend[b].buffer[0] = (wanted & 0xff00) >> 8;
501
 
                tcp_pend[b].buffer[1] = (wanted & 0xff);
502
 
                tcp_pend[b].got = 0;
503
 
        }
504
 
}
505
 
 
506
 
/* Forward data from upstream DNS server locally; nearly identical to
507
 
 * Deadwood 2.3's tcp_local2remote */
508
 
void tcp_downstream_forward(int b) {
509
 
        ssize_t len = 0;
510
 
        ssize_t actual = 0;
511
 
 
512
 
        if(tcp_pend[b].state != 6) {
513
 
                return;
514
 
        }
515
 
 
516
 
        if(tcp_pend[b].got >= tcp_pend[b].wanted ||
517
 
           tcp_pend[b].buffer == 0 ||
518
 
           tcp_pend[b].sent >= tcp_pend[b].wanted + 2) {
519
 
                closesocket(tcp_pend[b].local);
520
 
                closesocket(tcp_pend[b].upstream);
521
 
                reset_tcp_pend(b);
522
 
                return;
523
 
        }
524
 
 
525
 
        /* The "2" you see is the 2-byte length header */
526
 
        len = recv(tcp_pend[b].upstream,
527
 
                tcp_pend[b].buffer + 2 + tcp_pend[b].got,
528
 
                tcp_pend[b].wanted - tcp_pend[b].got,MSG_DONTWAIT);
529
 
 
530
 
        if(len != (tcp_pend[b].wanted - tcp_pend[b].got)) {
531
 
                if(len <= 0) {
532
 
                        return; /* Try again later */
533
 
                } else {
534
 
                        tcp_pend[b].die = get_time() +
535
 
                                ((int64_t)timeout_seconds_tcp << 8);
536
 
                }
537
 
        }
538
 
 
539
 
        tcp_pend[b].got += len;
540
 
 
541
 
        /* Again, the '2' is the 2-byte length header */
542
 
        actual = send(tcp_pend[b].local,tcp_pend[b].buffer + tcp_pend[b].sent,
543
 
                        tcp_pend[b].got - tcp_pend[b].sent + 2,
544
 
                        MSG_DONTWAIT);
545
 
 
546
 
        if(actual <= 0) {
547
 
                return;
548
 
        } else if(actual != len) { /* Partial sends not supported */
549
 
                tcp_pend[b].die = get_time() +
550
 
                        ((int64_t)timeout_seconds_tcp << 8);
551
 
                tcp_pend[b].sent += actual;
552
 
                return;
553
 
        } else if(actual == len && tcp_pend[b].wanted == tcp_pend[b].got) {
554
 
                /* All data sent, success */
555
 
                closesocket(tcp_pend[b].local);
556
 
                closesocket(tcp_pend[b].upstream);
557
 
                reset_tcp_pend(b);
558
 
                return;
559
 
        }
560
 
 
561
 
        tcp_pend[b].sent += actual;
562
 
 
563
 
}
564
 
 
565
 
/* Handle all TCP connections with data pending to be sent */
566
 
void tcp_handle_all(int b) {
567
 
        if(key_n[DWM_N_tcp_listen] == 1) {
568
 
                tcp_get_wanted(b);
569
 
                tcp_process_data(b);
570
 
                tcp_send_wanted(b);
571
 
                tcp_upstream_send(b);
572
 
                tcp_prepare_upstream_len(b);
573
 
                tcp_get_upstream_len(b);
574
 
                tcp_downstream_forward(b);
575
 
        }
576
 
}
577
 
 
578
 
/* Disconnect idle TCP connections */
579
 
void kill_tcp_expired() {
580
 
        int a = 0;
581
 
        for(a = 0; a < max_tcp_procs; a++) {
582
 
                if(tcp_pend[a].die > 0 && tcp_pend[a].die < get_time()) {
583
 
                        closesocket(tcp_pend[a].local);
584
 
                        reset_tcp_pend(a);
585
 
                }
586
 
        }
587
 
}
588
 
 
589
 
/* Process any pending connections which select() caught */
590
 
void tcp_process_results(int a, fd_set *rx_fd) {
591
 
        int b = 0, z = 0;
592
 
 
593
 
        /* Find the pending connection */
594
 
        while(a > 0 && z < 10000) {
595
 
                /* Handle new connections */
596
 
                for(b = 0; b < DW_MAXIPS; b++) {
597
 
                        if(tcp_b_local[b] != INVALID_SOCKET &&
598
 
                           FD_ISSET(tcp_b_local[b],rx_fd)) {
599
 
                                local_tcp_accept(tcp_b_local[b]);
600
 
                                a--;
601
 
                                if(a <= 0) {
602
 
                                        return;
603
 
                                }
604
 
                        }
605
 
                }
606
 
                z++;
607
 
        }
608
 
}
609