/* * ipsocket.cpp - ip router * * Basilisk II (C) 1997-2001 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdeps.h" #include "cpu_emulation.h" #include "ws2tcpip.h" #include "prefs.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "dynsockets.h" #include "ipsocket.h" #include "icmp.h" #include "tcp.h" #include "udp.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" socket_t::socket_t( int _proto ) { s = INVALID_SOCKET; proto = _proto; ip_src = ip_dest = 0; src_port = dest_port = 0; memset( &overlapped, 0, sizeof(overlapped) ); overlapped.hEvent = (HANDLE)this; bytes_received = 0; flags = 0; from_len = sizeof(struct sockaddr_in); memset( &from, 0, sizeof(from) ); from.sin_family = AF_INET; buffer_count = 1; buffers[0].len = 1460; buffers[0].buf = new char [buffers[0].len]; out_buffers[0].len = 1460; out_buffers[0].buf = new char [out_buffers[0].len]; socket_ttl = GetTickCount() + 60000L; permanent = false; } socket_t::~socket_t() { if(s != INVALID_SOCKET) { _closesocket( s ); // slam! s = INVALID_SOCKET; } delete [] out_buffers[0].buf; delete [] buffers[0].buf; } int socket_t::WSARecvFrom() { return _WSARecvFrom( s, buffers, buffer_count, &bytes_received, &flags, (struct sockaddr *)&from, &from_len, &overlapped, proto == IPPROTO_UDP ? udp_read_completion : icmp_read_completion ); } bool socket_t::b_recfrom() { bool result; int ret = WSARecvFrom(); if(ret == SOCKET_ERROR) { int socket_error = _WSAGetLastError(); if(socket_error == WSA_IO_PENDING) { D(bug("WSARecvFrom() i/o pending\r\n")); result = true; } else { D(bug("_WSAGetLastError() returned %d\r\n", socket_error)); result = false; } } else /*if(ret == 0) */ { D(bug("WSARecvFrom() ok\r\n")); // Completion routine call is already scheduled. result = true; } return result; } void socket_t::set_ttl( uint8 ttl ) { int _ttl = ttl; // defensive programming, I know VCx if(_setsockopt( s, IPPROTO_IP, IP_TTL, (const char *)&_ttl, sizeof(int) ) == SOCKET_ERROR ) { D(bug("could not set ttl to %d.\r\n", ttl)); } else { D(bug("ttl set to %d.\r\n", ttl)); } } #define MAX_OPEN_SOCKETS 1024 static socket_t *all_sockets[MAX_OPEN_SOCKETS]; static int open_sockets = 0; int get_socket_index( uint16 src_port, uint16 dest_port, int proto ) { int result = -1; for( int i=0; isrc_port == src_port && cmpl->dest_port == dest_port && cmpl->proto == proto ) { result = i; break; } } return result; } int get_socket_index( uint16 src_port, int proto ) { int result = -1; for( int i=0; isrc_port == src_port && cmpl->proto == proto ) { result = i; break; } } return result; } int get_socket_index( socket_t *cmpl ) { int result = -1; for( int i=0; isrc_port, cmpl->dest_port)); EnterCriticalSection( &router_section ); int i = get_socket_index( cmpl ); if( i >= 0 ) { delete all_sockets[i]; all_sockets[i] = all_sockets[--open_sockets]; } else { D(bug("Deleted socket not in table!\r\n")); // delete cmpl; } LeaveCriticalSection( &router_section ); } socket_t *find_socket( uint16 src_port, uint16 dest_port, int proto ) { socket_t *result = 0; EnterCriticalSection( &router_section ); int i = get_socket_index( src_port, dest_port, proto ); if( i >= 0 ) { result = all_sockets[i]; } else { i = get_socket_index( src_port, proto ); if( i >= 0 ) { delete_socket( all_sockets[i] ); } } LeaveCriticalSection( &router_section ); D(bug("find_socket(%d,%d): %s\r\n", src_port, dest_port, result ? "found" : "not found")); return result; } void add_socket( socket_t *cmpl ) { D(bug("adding socket(%d,%d)\r\n", cmpl->src_port, cmpl->dest_port)); EnterCriticalSection( &router_section ); if( open_sockets < MAX_OPEN_SOCKETS ) { all_sockets[open_sockets++] = cmpl; } else { // Urgchiyuppijee! (that's finnish language, meaning "do something about this") delete all_sockets[0]; all_sockets[0] = cmpl; } LeaveCriticalSection( &router_section ); } void close_old_sockets() { DWORD now = GetTickCount(); EnterCriticalSection( &router_section ); for( int i=open_sockets-1; i>=0; i-- ) { socket_t *cmpl = all_sockets[i]; if( !cmpl->permanent && now >= cmpl->socket_ttl ) { D(bug("expiring socket(%d,%d)\r\n", cmpl->src_port, cmpl->dest_port)); if(cmpl->s == INVALID_SOCKET) { delete all_sockets[i]; all_sockets[i] = all_sockets[--open_sockets]; } else { // read completion will deallocate _closesocket( cmpl->s ); } } } LeaveCriticalSection( &router_section ); } void close_all_sockets() { D(bug("closing all(%d) sockets\r\n", open_sockets)); EnterCriticalSection( &router_section ); for( int i=0; isrc_port, cmpl->dest_port)); if(cmpl->s == INVALID_SOCKET) { delete all_sockets[i]; all_sockets[i] = all_sockets[--open_sockets]; } else { // read completion will deallocate _closesocket( cmpl->s ); } } LeaveCriticalSection( &router_section ); }