ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/router/udp.cpp
Revision: 1.1
Committed: 2004-12-05T16:48:36Z (20 years ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-17
Log Message:
import NAT-Router code from original Basilisk II for Windows

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * udp.cpp - ip router
3     *
4     * Basilisk II (C) 1997-2001 Christian Bauer
5     *
6     * Windows platform specific code copyright (C) Lauri Pesonen
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21     */
22    
23     #include "sysdeps.h"
24     #include "cpu_emulation.h"
25     #include "prefs.h"
26     #include "ether_windows.h"
27     #include "ether.h"
28     #include "router.h"
29     #include "router_types.h"
30     #include "dynsockets.h"
31     #include "ipsocket.h"
32     #include "iphelp.h"
33     #include "udp.h"
34     #include "dump.h"
35    
36    
37     #if DEBUG
38     #pragma optimize("",off)
39     #endif
40    
41     #include "debug.h"
42    
43    
44     void CALLBACK udp_read_completion(
45     DWORD error,
46     DWORD bytes_read,
47     LPWSAOVERLAPPED lpOverlapped,
48     DWORD flags
49     )
50     {
51     D(bug("udp_read_completion(error=0x%x, bytes_read=%d, flags=0x%x)\r\n", error, bytes_read, flags));
52    
53     socket_t *cmpl = (socket_t *)lpOverlapped->hEvent;
54    
55     // It's not easy to know whether empty upd datagrams should be passed along. doh.
56     if(error == 0 && bytes_read > 0) {
57    
58     if(bytes_read > 1460) {
59     D(bug("discarding oversized udp packet, size = \r\n", bytes_read));
60     } else {
61     struct sockaddr_in name;
62     int namelen = sizeof(name);
63     memset( &name, 0, sizeof(name) );
64     if( _getsockname( cmpl->s, (struct sockaddr *)&name, &namelen ) == SOCKET_ERROR ) {
65     D(bug("_getsockname() failed, error=%d\r\n", _WSAGetLastError() ));
66     } else {
67     D(bug("_getsockname(): port=%d\r\n", ntohs(name.sin_port) ));
68     }
69    
70     int udp_size = sizeof(udp_t) + bytes_read;
71     udp_t *udp = (udp_t *)malloc( udp_size );
72     if(udp) {
73     mac_t *mac = (mac_t *)udp;
74     ip_t *ip = (ip_t *)udp;
75    
76     // Build MAC
77     // memcpy( udp->ip.mac.dest, cmpl->mac_src, 6 );
78     memcpy( mac->dest, ether_addr, 6 );
79     memcpy( mac->src, router_mac_addr, 6 );
80     mac->type = htons(mac_type_ip4);
81    
82     // Build IP
83     ip->version = 4;
84     ip->header_len = 5;
85     ip->tos = 0;
86     ip->total_len = htons(sizeof(udp_t) - sizeof(mac_t) + bytes_read); // no options
87     ip->ident = htons(next_ip_ident_number++); // htons() might be a macro... but does not really matter here.
88     ip->flags_n_frag_offset = 0;
89     ip->ttl = 128; // one hop actually!
90     ip->proto = ip_proto_udp;
91     ip->src = htonl(cmpl->ip_dest);
92     ip->dest = htonl(cmpl->ip_src);
93     make_ip4_checksum( (ip_t *)udp );
94    
95     // Copy payload (used by UDP checksum)
96     memcpy( (char *)udp + sizeof(udp_t), cmpl->buffers[0].buf, bytes_read );
97    
98     // Build UDP
99     udp->src_port = htons(cmpl->dest_port);
100     udp->dest_port = htons(cmpl->src_port);
101     udp->msg_len = htons(sizeof(udp_t) - sizeof(ip_t) + bytes_read); // no options
102     make_udp_checksum( udp );
103    
104     dump_bytes( (uint8 *)udp, udp_size );
105    
106     enqueue_packet( (uint8 *)udp, udp_size );
107     free(udp);
108     }
109     }
110     }
111    
112     if(!is_router_shutting_down && cmpl->s != INVALID_SOCKET && cmpl->b_recfrom()) {
113     cmpl->socket_ttl = GetTickCount() + 60000L;
114     } else {
115     delete_socket( cmpl );
116     }
117     }
118    
119     void write_udp( udp_t *udp, int len )
120     {
121     if( len < sizeof(udp_t) ) {
122     D(bug("Too small udp packet(%d), dropped\r\n", len));
123     return;
124     }
125    
126     uint16 src_port = ntohs(udp->src_port);
127     uint16 dest_port = ntohs(udp->dest_port);
128    
129     BOOL ok = true;
130    
131     socket_t *cmpl = find_socket( src_port, dest_port, IPPROTO_UDP );
132    
133     BOOL old_socket_found = cmpl != 0;
134    
135     if(!cmpl) {
136     cmpl = new socket_t(IPPROTO_UDP);
137     if(cmpl) {
138     cmpl->s = _socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
139     if(cmpl->s == INVALID_SOCKET) {
140     delete cmpl;
141     cmpl = 0;
142     ok = false;
143     } else {
144     cmpl->src_port = src_port;
145     cmpl->dest_port = dest_port;
146     add_socket( cmpl );
147     }
148     } else {
149     ok = false;
150     }
151     }
152    
153     if(ok) {
154     cmpl->src_port = src_port;
155     cmpl->dest_port = dest_port;
156     cmpl->ip_src = ntohl(udp->ip.src);
157     cmpl->ip_dest = ntohl(udp->ip.dest);
158    
159     struct sockaddr_in to;
160     memset( &to, 0, sizeof(to) );
161     to.sin_family = AF_INET;
162     to.sin_port = udp->dest_port;
163     to.sin_addr.s_addr = udp->ip.dest;
164    
165     char *data = (char *)udp + sizeof(udp_t);
166     int dlen = len - sizeof(udp_t);
167    
168     // ttl changed, update checksum
169     make_udp_checksum( udp );
170    
171     cmpl->set_ttl( udp->ip.ttl );
172    
173     bool please_close = true;
174     /*
175     Note that broadcast messages fill fail, no setsockopt(SO_BROADCAST).
176     That's exactly what I want.
177     */
178     if(SOCKET_ERROR != _sendto( cmpl->s, data, dlen, 0, (struct sockaddr *)&to, sizeof(to) )) {
179     if(old_socket_found) {
180     // This socket is not overlapped.
181     please_close = false;
182     } else {
183     if(cmpl->b_recfrom()) please_close = false;
184     }
185     cmpl->socket_ttl = GetTickCount() + 60000L;
186     } else {
187     int socket_error = _WSAGetLastError();
188     D(bug("_sendto() completed with error %d\r\n", socket_error));
189     // TODO: check this out: error_winsock_2_icmp() uses router_ip_address
190     // as source ip; but it's probably allright
191     error_winsock_2_icmp( socket_error, (ip_t *)udp, len );
192     }
193     if(please_close) {
194     delete_socket(cmpl);
195     }
196     }
197     }
198    
199     void init_udp()
200     {
201     }
202    
203     void final_udp()
204     {
205     }