2008-12-09 21:36:07 +00:00
|
|
|
/* ipxwrapper - Winsock functions
|
|
|
|
* Copyright (C) 2008 Daniel Collins <solemnwarning@solemnwarning.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
|
|
* the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* 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., 51
|
|
|
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include <wsipx.h>
|
|
|
|
#include <mswsock.h>
|
|
|
|
#include <nspapi.h>
|
2011-09-07 23:03:14 +00:00
|
|
|
#include <wsnwlink.h>
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
#include "ipxwrapper.h"
|
2011-08-28 21:27:06 +00:00
|
|
|
#include "common.h"
|
2011-08-29 13:21:18 +00:00
|
|
|
#include "interface.h"
|
2011-09-07 20:03:16 +00:00
|
|
|
#include "router.h"
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-07 23:29:14 +00:00
|
|
|
typedef struct _PROTOCOL_INFO {
|
2011-09-07 23:03:14 +00:00
|
|
|
DWORD dwServiceFlags ;
|
|
|
|
INT iAddressFamily ;
|
|
|
|
INT iMaxSockAddr ;
|
|
|
|
INT iMinSockAddr ;
|
|
|
|
INT iSocketType ;
|
|
|
|
INT iProtocol ;
|
|
|
|
DWORD dwMessageSize ;
|
2011-09-07 23:29:14 +00:00
|
|
|
void *lpProtocol ;
|
|
|
|
} PROTOCOL_INFO;
|
2011-09-07 23:03:14 +00:00
|
|
|
|
2011-09-07 23:29:14 +00:00
|
|
|
static int do_EnumProtocols(LPINT protocols, LPVOID buf, LPDWORD bsptr, BOOL unicode) {
|
2008-12-09 21:36:07 +00:00
|
|
|
int bufsize = *bsptr, rval, i, want_ipx = 0;
|
|
|
|
|
2011-09-07 23:29:14 +00:00
|
|
|
PROTOCOL_INFO *pinfo = buf;
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-07 23:29:14 +00:00
|
|
|
if((rval = unicode ? r_EnumProtocolsW(protocols, buf, bsptr) : r_EnumProtocolsA(protocols, buf, bsptr)) == -1) {
|
2008-12-09 21:36:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!protocols) {
|
|
|
|
want_ipx = 1;
|
|
|
|
}else{
|
|
|
|
for(i = 0; protocols[i]; i++) {
|
|
|
|
if(protocols[i] == NSPROTO_IPX) {
|
|
|
|
want_ipx = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(want_ipx) {
|
|
|
|
for(i = 0; i < rval; i++) {
|
|
|
|
if(pinfo[i].iProtocol == NSPROTO_IPX) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(i == rval) {
|
2011-09-07 23:29:14 +00:00
|
|
|
*bsptr += sizeof(PROTOCOL_INFO);
|
2008-12-09 21:36:07 +00:00
|
|
|
rval++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(*bsptr > bufsize) {
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pinfo[i].dwServiceFlags = 5641;
|
|
|
|
pinfo[i].iAddressFamily = AF_IPX;
|
|
|
|
pinfo[i].iMaxSockAddr = 16;
|
|
|
|
pinfo[i].iMinSockAddr = 14;
|
|
|
|
pinfo[i].iSocketType = SOCK_DGRAM;
|
|
|
|
pinfo[i].iProtocol = NSPROTO_IPX;
|
|
|
|
pinfo[i].dwMessageSize = 576;
|
2011-09-07 23:29:14 +00:00
|
|
|
pinfo[i].lpProtocol = unicode ? (char*)L"IPX" : "IPX";
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2011-09-07 23:29:14 +00:00
|
|
|
INT APIENTRY EnumProtocolsA(LPINT protocols, LPVOID buf, LPDWORD bsptr) {
|
|
|
|
return do_EnumProtocols(protocols, buf, bsptr, FALSE);
|
|
|
|
}
|
2011-09-07 23:03:14 +00:00
|
|
|
|
2008-12-09 21:36:07 +00:00
|
|
|
INT APIENTRY EnumProtocolsW(LPINT protocols, LPVOID buf, LPDWORD bsptr) {
|
2011-09-07 23:29:14 +00:00
|
|
|
return do_EnumProtocols(protocols, buf, bsptr, TRUE);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SOCKET WSAAPI socket(int af, int type, int protocol) {
|
2011-07-13 22:56:19 +00:00
|
|
|
log_printf("socket(%d, %d, %d)", af, type, protocol);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
if(af == AF_IPX) {
|
|
|
|
ipx_socket *nsock = malloc(sizeof(ipx_socket));
|
|
|
|
if(!nsock) {
|
2011-09-08 00:20:34 +00:00
|
|
|
WSASetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return -1;
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsock->fd = r_socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if(nsock->fd == -1) {
|
2011-07-13 22:56:19 +00:00
|
|
|
log_printf("Creating fake socket failed: %s", w32_error(WSAGetLastError()));
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
free(nsock);
|
2011-09-08 00:20:34 +00:00
|
|
|
return -1;
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2011-04-24 17:40:25 +00:00
|
|
|
nsock->flags = IPX_SEND | IPX_RECV;
|
2011-07-12 13:28:57 +00:00
|
|
|
nsock->s_ptype = (protocol ? NSPROTO_IPX - protocol : 0);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-08 00:20:34 +00:00
|
|
|
lock_sockets();
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
nsock->next = sockets;
|
|
|
|
sockets = nsock;
|
|
|
|
|
2011-07-13 22:56:19 +00:00
|
|
|
log_printf("IPX socket created (fd = %d)", nsock->fd);
|
2011-04-24 17:40:25 +00:00
|
|
|
|
2008-12-09 21:36:07 +00:00
|
|
|
RETURN(nsock->fd);
|
|
|
|
}else{
|
|
|
|
return r_socket(af, type, protocol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int WSAAPI closesocket(SOCKET fd) {
|
2011-07-09 02:20:46 +00:00
|
|
|
int ret = r_closesocket(fd);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
ipx_socket *ptr = get_socket(fd);
|
|
|
|
ipx_socket *pptr = sockets;
|
|
|
|
|
2011-07-09 02:20:46 +00:00
|
|
|
if(!ptr) {
|
|
|
|
/* Not an IPX socket */
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ret == SOCKET_ERROR) {
|
2011-07-13 22:56:19 +00:00
|
|
|
log_printf("closesocket(%d) failed: %s", fd, w32_error(WSAGetLastError()));
|
2011-07-09 02:20:46 +00:00
|
|
|
RETURN(SOCKET_ERROR);
|
|
|
|
}
|
|
|
|
|
2011-07-13 22:56:19 +00:00
|
|
|
log_printf("IPX socket closed (fd = %d)", fd);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-09 18:36:52 +00:00
|
|
|
rclient_unbind(&g_rclient, fd);
|
2011-09-07 20:03:16 +00:00
|
|
|
|
2008-12-09 21:36:07 +00:00
|
|
|
if(ptr == sockets) {
|
|
|
|
sockets = ptr->next;
|
|
|
|
free(ptr);
|
|
|
|
}else{
|
|
|
|
while(ptr && pptr->next) {
|
|
|
|
if(ptr == pptr->next) {
|
|
|
|
pptr->next = ptr->next;
|
|
|
|
free(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
pptr = pptr->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) {
|
|
|
|
ipx_socket *ptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(ptr) {
|
2011-09-07 20:03:16 +00:00
|
|
|
struct sockaddr_ipx ipxaddr;
|
2011-04-24 01:23:10 +00:00
|
|
|
char net_s[12], node_s[18];
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
if(addrlen < sizeof(ipxaddr)) {
|
|
|
|
RETURN_WSA(WSAEFAULT, -1);
|
2011-04-24 01:23:10 +00:00
|
|
|
}
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
memcpy(&ipxaddr, addr, sizeof(ipxaddr));
|
2011-04-24 01:23:10 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
NET_TO_STRING(net_s, ipxaddr.sa_netnum);
|
|
|
|
NODE_TO_STRING(node_s, ipxaddr.sa_nodenum);
|
2011-04-24 01:23:10 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
log_printf("bind(%d, net=%s node=%s socket=%hu)", fd, net_s, node_s, ntohs(ipxaddr.sa_socket));
|
2011-04-24 01:23:10 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
if(ptr->flags & IPX_BOUND) {
|
|
|
|
log_printf("bind failed: socket already bound");
|
|
|
|
RETURN_WSA(WSAEINVAL, -1);
|
2011-04-24 01:23:10 +00:00
|
|
|
}
|
|
|
|
|
2011-09-09 18:36:52 +00:00
|
|
|
if(!rclient_bind(&g_rclient, fd, &ipxaddr, &(ptr->nic_bcast), ptr->flags & IPX_REUSE ? TRUE : FALSE)) {
|
2011-09-07 20:03:16 +00:00
|
|
|
RETURN(-1);
|
2011-04-24 01:23:10 +00:00
|
|
|
}
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
NET_TO_STRING(net_s, ipxaddr.sa_netnum);
|
|
|
|
NODE_TO_STRING(node_s, ipxaddr.sa_nodenum);
|
2011-04-24 01:23:10 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
log_printf("bind address: net=%s node=%s socket=%hu", net_s, node_s, ntohs(ipxaddr.sa_socket));
|
2011-04-24 01:23:10 +00:00
|
|
|
|
|
|
|
struct sockaddr_in bind_addr;
|
|
|
|
bind_addr.sin_family = AF_INET;
|
|
|
|
bind_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
2011-09-07 20:03:16 +00:00
|
|
|
bind_addr.sin_port = 0;
|
|
|
|
|
|
|
|
if(r_bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) {
|
|
|
|
log_printf("Binding local UDP socket failed: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
2011-09-09 18:36:52 +00:00
|
|
|
rclient_unbind(&g_rclient, fd);
|
2011-09-07 20:03:16 +00:00
|
|
|
RETURN(-1);
|
|
|
|
}
|
2011-04-24 01:23:10 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
int al = sizeof(bind_addr);
|
2011-04-24 01:23:10 +00:00
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
if(r_getsockname(fd, (struct sockaddr*)&bind_addr, &al) == -1) {
|
|
|
|
log_printf("getsockname failed: %s", w32_error(WSAGetLastError()));
|
|
|
|
|
2011-09-09 18:36:52 +00:00
|
|
|
rclient_unbind(&g_rclient, fd);
|
2011-09-07 20:03:16 +00:00
|
|
|
RETURN(-1);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
memcpy(&(ptr->addr), &ipxaddr, sizeof(ipxaddr));
|
|
|
|
ptr->flags |= IPX_BOUND;
|
|
|
|
|
2011-09-09 18:36:52 +00:00
|
|
|
rclient_set_port(&g_rclient, fd, bind_addr.sin_port);
|
2011-09-07 20:03:16 +00:00
|
|
|
|
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}else{
|
2011-09-08 00:20:34 +00:00
|
|
|
return r_bind(fd, addr, addrlen);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int WSAAPI getsockname(SOCKET fd, struct sockaddr *addr, int *addrlen) {
|
|
|
|
ipx_socket *ptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(ptr) {
|
|
|
|
if(ptr->flags & IPX_BOUND) {
|
|
|
|
if(*addrlen < sizeof(struct sockaddr_ipx)) {
|
|
|
|
*addrlen = sizeof(struct sockaddr_ipx);
|
|
|
|
RETURN_WSA(WSAEFAULT, -1);
|
|
|
|
}
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
memcpy(addr, &(ptr->addr), sizeof(ptr->addr));
|
2008-12-09 21:36:07 +00:00
|
|
|
*addrlen = sizeof(struct sockaddr_ipx);
|
|
|
|
|
|
|
|
RETURN(0);
|
|
|
|
}else{
|
|
|
|
RETURN_WSA(WSAEINVAL, -1);
|
|
|
|
}
|
|
|
|
}else{
|
2011-09-08 00:20:34 +00:00
|
|
|
return r_getsockname(fd, addr, addrlen);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-30 02:44:17 +00:00
|
|
|
/* Recieve a packet from an IPX socket
|
|
|
|
* addr must be NULL or a region of memory big enough for a sockaddr_ipx
|
|
|
|
*
|
|
|
|
* The mutex should be locked before calling and will be released before returning
|
2011-05-30 03:33:39 +00:00
|
|
|
* The size of the packet will be returned on success, even if it was truncated
|
2011-05-30 02:44:17 +00:00
|
|
|
*/
|
|
|
|
static int recv_packet(ipx_socket *sockptr, char *buf, int bufsize, int flags, struct sockaddr_ipx *addr) {
|
|
|
|
SOCKET fd = sockptr->fd;
|
|
|
|
int is_bound = sockptr->flags & IPX_BOUND;
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-08 00:20:34 +00:00
|
|
|
unlock_sockets();
|
2011-05-30 02:44:17 +00:00
|
|
|
|
|
|
|
if(!is_bound) {
|
|
|
|
WSASetLastError(WSAEINVAL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ipx_packet *packet = malloc(PACKET_BUF_SIZE);
|
|
|
|
if(!packet) {
|
|
|
|
WSASetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rval = r_recv(fd, (char*)packet, PACKET_BUF_SIZE, flags);
|
|
|
|
if(rval == -1) {
|
|
|
|
free(packet);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-07 20:37:18 +00:00
|
|
|
if(rval < sizeof(ipx_packet) || rval != packet->size + sizeof(ipx_packet) - 1) {
|
|
|
|
log_printf("Invalid packet received on loopback port!");
|
|
|
|
|
|
|
|
free(packet);
|
|
|
|
WSASetLastError(WSAEWOULDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Router thread replaces destination network number with source IP address */
|
|
|
|
add_host(packet->src_net, packet->src_node, *((uint32_t*)packet->dest_net));
|
|
|
|
|
2011-05-30 02:44:17 +00:00
|
|
|
if(addr) {
|
|
|
|
addr->sa_family = AF_IPX;
|
|
|
|
memcpy(addr->sa_netnum, packet->src_net, 4);
|
|
|
|
memcpy(addr->sa_nodenum, packet->src_node, 6);
|
|
|
|
addr->sa_socket = packet->src_socket;
|
|
|
|
}
|
|
|
|
|
2011-05-30 03:33:39 +00:00
|
|
|
memcpy(buf, packet->data, packet->size <= bufsize ? packet->size : bufsize);
|
|
|
|
rval = packet->size;
|
|
|
|
free(packet);
|
|
|
|
|
|
|
|
return rval;
|
2011-05-30 02:44:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int WSAAPI recvfrom(SOCKET fd, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen) {
|
|
|
|
ipx_socket *sockptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(sockptr) {
|
|
|
|
if(addr && addrlen && *addrlen < sizeof(struct sockaddr_ipx)) {
|
2011-09-08 00:20:34 +00:00
|
|
|
unlock_sockets();
|
2011-05-30 02:44:17 +00:00
|
|
|
|
|
|
|
WSASetLastError(WSAEFAULT);
|
2011-05-08 21:32:54 +00:00
|
|
|
return -1;
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2011-05-30 02:44:17 +00:00
|
|
|
int rval = recv_packet(sockptr, buf, len, flags, (struct sockaddr_ipx*)addr);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-05-30 02:44:17 +00:00
|
|
|
/* The value pointed to by addrlen is only set if the recv call was
|
|
|
|
* successful, may not be correct.
|
|
|
|
*/
|
|
|
|
if(rval >= 0 && addr && addrlen) {
|
|
|
|
*addrlen = sizeof(struct sockaddr_ipx);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
2011-05-30 02:44:17 +00:00
|
|
|
|
2011-05-30 03:33:39 +00:00
|
|
|
if(rval > len) {
|
|
|
|
WSASetLastError(WSAEMSGSIZE);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-05-30 02:44:17 +00:00
|
|
|
return rval;
|
2008-12-09 21:36:07 +00:00
|
|
|
}else{
|
2011-05-08 21:32:54 +00:00
|
|
|
return r_recvfrom(fd, buf, len, flags, addr, addrlen);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int WSAAPI recv(SOCKET fd, char *buf, int len, int flags) {
|
2011-05-30 02:44:17 +00:00
|
|
|
ipx_socket *sockptr = get_socket(fd);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-05-30 02:44:17 +00:00
|
|
|
if(sockptr) {
|
2011-05-30 03:33:39 +00:00
|
|
|
int rval = recv_packet(sockptr, buf, len, flags, NULL);
|
|
|
|
|
|
|
|
if(rval > len) {
|
|
|
|
WSASetLastError(WSAEMSGSIZE);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rval;
|
2008-12-09 21:36:07 +00:00
|
|
|
}else{
|
2011-05-30 02:44:17 +00:00
|
|
|
return r_recv(fd, buf, len, flags);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-30 03:33:39 +00:00
|
|
|
int PASCAL WSARecvEx(SOCKET fd, char *buf, int len, int *flags) {
|
|
|
|
ipx_socket *sockptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(sockptr) {
|
|
|
|
int rval = recv_packet(sockptr, buf, len, 0, NULL);
|
|
|
|
|
|
|
|
if(rval > len) {
|
|
|
|
*flags = MSG_PARTIAL;
|
|
|
|
|
|
|
|
/* Wording of MSDN is unclear on what should be returned when
|
|
|
|
* an incomplete message is read, I think it should return the
|
|
|
|
* amount of data copied to the buffer.
|
|
|
|
*/
|
|
|
|
rval = len;
|
|
|
|
}else if(rval != -1) {
|
|
|
|
*flags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}else{
|
|
|
|
return r_WSARecvEx(fd, buf, len, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-09 21:36:07 +00:00
|
|
|
#define CHECK_OPTLEN(size) \
|
|
|
|
if(*optlen < size) {\
|
|
|
|
*optlen = size;\
|
|
|
|
RETURN_WSA(WSAEFAULT, -1);\
|
|
|
|
}\
|
|
|
|
*optlen = size;
|
|
|
|
|
|
|
|
int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int FAR *optlen) {
|
|
|
|
int* intval = (int*)optval;
|
2011-09-08 18:28:01 +00:00
|
|
|
BOOL *bval = (BOOL*)optval;
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
ipx_socket *ptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(ptr) {
|
|
|
|
if(level == NSPROTO_IPX) {
|
|
|
|
if(optname == IPX_PTYPE) {
|
|
|
|
CHECK_OPTLEN(sizeof(int));
|
|
|
|
*intval = ptr->s_ptype;
|
2008-12-11 21:27:40 +00:00
|
|
|
|
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(optname == IPX_FILTERPTYPE) {
|
|
|
|
CHECK_OPTLEN(sizeof(int));
|
|
|
|
*intval = ptr->f_ptype;
|
2008-12-11 21:27:40 +00:00
|
|
|
|
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(optname == IPX_MAXSIZE) {
|
|
|
|
CHECK_OPTLEN(sizeof(int));
|
|
|
|
*intval = MAX_PACKET_SIZE;
|
2008-12-11 21:27:40 +00:00
|
|
|
|
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(optname == IPX_ADDRESS) {
|
|
|
|
CHECK_OPTLEN(sizeof(IPX_ADDRESS_DATA));
|
|
|
|
|
|
|
|
IPX_ADDRESS_DATA *ipxdata = (IPX_ADDRESS_DATA*)optval;
|
|
|
|
|
2011-09-11 17:09:57 +00:00
|
|
|
struct ipx_interface *nic = get_interfaces(ipxdata->adapternum);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
if(!nic) {
|
|
|
|
WSASetLastError(ERROR_NO_DATA);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-04-24 01:37:25 +00:00
|
|
|
memcpy(ipxdata->netnum, nic->ipx_net, 4);
|
|
|
|
memcpy(ipxdata->nodenum, nic->ipx_node, 6);
|
2008-12-09 21:36:07 +00:00
|
|
|
|
|
|
|
/* TODO: LAN/WAN detection, link speed detection */
|
|
|
|
ipxdata->wan = FALSE;
|
|
|
|
ipxdata->status = FALSE;
|
|
|
|
ipxdata->maxpkt = MAX_PACKET_SIZE;
|
|
|
|
ipxdata->linkspeed = 100000; /* 10MBps */
|
2008-12-11 21:27:40 +00:00
|
|
|
|
2011-09-11 17:09:57 +00:00
|
|
|
free_interfaces(nic);
|
|
|
|
|
2008-12-11 21:27:40 +00:00
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2011-04-24 01:37:25 +00:00
|
|
|
/* NOTE: IPX_MAX_ADAPTER_NUM implies it may be the maximum index
|
|
|
|
* for referencing an IPX interface. This behaviour makes no sense
|
|
|
|
* and a code example in MSDN implies it should be the number of
|
|
|
|
* IPX interfaces, this code follows the latter.
|
|
|
|
*/
|
2008-12-09 21:36:07 +00:00
|
|
|
if(optname == IPX_MAX_ADAPTER_NUM) {
|
|
|
|
CHECK_OPTLEN(sizeof(int));
|
|
|
|
|
|
|
|
*intval = 0;
|
|
|
|
|
2011-09-11 17:09:57 +00:00
|
|
|
struct ipx_interface *ifaces = get_interfaces(-1), *nic;
|
|
|
|
|
|
|
|
for(nic = ifaces; nic;) {
|
2008-12-09 21:36:07 +00:00
|
|
|
(*intval)++;
|
|
|
|
nic = nic->next;
|
|
|
|
}
|
2008-12-11 21:27:40 +00:00
|
|
|
|
2011-09-11 17:09:57 +00:00
|
|
|
free_interfaces(ifaces);
|
|
|
|
|
2008-12-11 21:27:40 +00:00
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 21:27:40 +00:00
|
|
|
RETURN_WSA(WSAENOPROTOOPT, -1);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
2011-09-08 00:20:34 +00:00
|
|
|
|
2011-09-08 18:28:01 +00:00
|
|
|
if(level == SOL_SOCKET) {
|
|
|
|
if(optname == SO_BROADCAST) {
|
|
|
|
CHECK_OPTLEN(sizeof(BOOL));
|
|
|
|
|
|
|
|
*bval = ptr->flags & IPX_BROADCAST ? TRUE : FALSE;
|
|
|
|
RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(optname == SO_REUSEADDR) {
|
|
|
|
CHECK_OPTLEN(sizeof(BOOL));
|
|
|
|
|
|
|
|
*bval = ptr->flags & IPX_REUSE ? TRUE : FALSE;
|
|
|
|
RETURN(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-08 00:20:34 +00:00
|
|
|
unlock_sockets();
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2011-09-08 00:20:34 +00:00
|
|
|
return r_getsockopt(fd, level, optname, optval, optlen);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, int optlen) {
|
|
|
|
int *intval = (int*)optval;
|
|
|
|
BOOL *bval = (BOOL*)optval;
|
|
|
|
|
|
|
|
ipx_socket *sockptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(sockptr) {
|
|
|
|
if(level == NSPROTO_IPX) {
|
|
|
|
if(optname == IPX_PTYPE) {
|
|
|
|
sockptr->s_ptype = *intval;
|
2008-12-11 21:27:40 +00:00
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(optname == IPX_FILTERPTYPE) {
|
2011-09-09 18:36:52 +00:00
|
|
|
if(!rclient_set_filter(&g_rclient, fd, *intval)) {
|
|
|
|
RETURN(-1);
|
|
|
|
}
|
|
|
|
|
2008-12-09 21:36:07 +00:00
|
|
|
sockptr->f_ptype = *intval;
|
|
|
|
sockptr->flags |= IPX_FILTER;
|
2008-12-11 21:27:40 +00:00
|
|
|
|
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(optname == IPX_STOPFILTERPTYPE) {
|
2011-09-09 18:36:52 +00:00
|
|
|
if(!rclient_set_filter(&g_rclient, fd, -1)) {
|
|
|
|
RETURN(-1);
|
|
|
|
}
|
2011-09-07 20:03:16 +00:00
|
|
|
|
2011-09-09 18:36:52 +00:00
|
|
|
sockptr->flags &= ~IPX_FILTER;
|
2011-09-07 20:03:16 +00:00
|
|
|
|
2008-12-11 21:27:40 +00:00
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 21:27:40 +00:00
|
|
|
RETURN_WSA(WSAENOPROTOOPT, -1);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(level == SOL_SOCKET) {
|
|
|
|
if(optname == SO_BROADCAST) {
|
2011-09-08 18:28:01 +00:00
|
|
|
if(*bval) {
|
2008-12-09 21:36:07 +00:00
|
|
|
sockptr->flags |= IPX_BROADCAST;
|
|
|
|
}else{
|
|
|
|
sockptr->flags &= ~IPX_BROADCAST;
|
|
|
|
}
|
2008-12-11 21:30:34 +00:00
|
|
|
|
2011-09-08 18:28:01 +00:00
|
|
|
RETURN(0);
|
|
|
|
}else if(optname == SO_REUSEADDR) {
|
2011-09-09 18:36:52 +00:00
|
|
|
if(!rclient_set_reuse(&g_rclient, fd, *bval)) {
|
2011-09-08 18:28:01 +00:00
|
|
|
RETURN(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(*bval) {
|
|
|
|
sockptr->flags |= IPX_REUSE;
|
|
|
|
}else{
|
|
|
|
sockptr->flags &= ~IPX_REUSE;
|
|
|
|
}
|
|
|
|
|
2008-12-11 21:30:34 +00:00
|
|
|
RETURN(0);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-08 00:20:34 +00:00
|
|
|
|
|
|
|
unlock_sockets();
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
2011-09-08 00:20:34 +00:00
|
|
|
return r_setsockopt(fd, level, optname, optval, optlen);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen) {
|
|
|
|
struct sockaddr_ipx *ipxaddr = (struct sockaddr_ipx*)addr;
|
|
|
|
|
|
|
|
ipx_socket *sockptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(sockptr) {
|
|
|
|
if(!addr || addrlen < sizeof(struct sockaddr_ipx)) {
|
|
|
|
RETURN_WSA(WSAEDESTADDRREQ, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(sockptr->flags & IPX_SEND)) {
|
|
|
|
RETURN_WSA(WSAESHUTDOWN, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(sockptr->flags & IPX_BOUND)) {
|
2011-07-13 22:56:19 +00:00
|
|
|
log_printf("sendto() on unbound socket, attempting implicit bind");
|
2008-12-11 21:52:28 +00:00
|
|
|
|
2011-04-24 02:08:37 +00:00
|
|
|
struct sockaddr_ipx bind_addr;
|
|
|
|
|
|
|
|
bind_addr.sa_family = AF_IPX;
|
|
|
|
memcpy(bind_addr.sa_netnum, ipxaddr->sa_netnum, 4);
|
|
|
|
memset(bind_addr.sa_nodenum, 0, 6);
|
|
|
|
bind_addr.sa_socket = 0;
|
|
|
|
|
|
|
|
if(bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) {
|
2008-12-11 21:52:28 +00:00
|
|
|
RETURN(-1);
|
|
|
|
}
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(len > MAX_PACKET_SIZE) {
|
|
|
|
RETURN_WSA(WSAEMSGSIZE, -1);
|
|
|
|
}
|
|
|
|
|
2011-04-24 02:08:37 +00:00
|
|
|
int psize = sizeof(ipx_packet)+len-1;
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-04-24 02:08:37 +00:00
|
|
|
ipx_packet *packet = malloc(psize);
|
2008-12-09 21:36:07 +00:00
|
|
|
if(!packet) {
|
|
|
|
RETURN_WSA(ERROR_OUTOFMEMORY, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
packet->ptype = sockptr->s_ptype;
|
|
|
|
|
|
|
|
memcpy(packet->dest_net, ipxaddr->sa_netnum, 4);
|
|
|
|
memcpy(packet->dest_node, ipxaddr->sa_nodenum, 6);
|
|
|
|
packet->dest_socket = ipxaddr->sa_socket;
|
|
|
|
|
2011-04-24 16:32:09 +00:00
|
|
|
unsigned char z6[] = {0,0,0,0,0,0};
|
|
|
|
|
|
|
|
if(memcmp(packet->dest_net, z6, 4) == 0) {
|
2011-09-07 20:03:16 +00:00
|
|
|
memcpy(packet->dest_net, sockptr->addr.sa_netnum, 4);
|
2011-04-24 16:32:09 +00:00
|
|
|
}
|
|
|
|
|
2011-09-07 20:03:16 +00:00
|
|
|
memcpy(packet->src_net, sockptr->addr.sa_netnum, 4);
|
|
|
|
memcpy(packet->src_node, sockptr->addr.sa_nodenum, 6);
|
|
|
|
packet->src_socket = sockptr->addr.sa_socket;
|
2011-04-24 02:08:37 +00:00
|
|
|
|
2008-12-09 21:36:07 +00:00
|
|
|
packet->size = htons(len);
|
|
|
|
memcpy(packet->data, buf, len);
|
|
|
|
|
2011-04-24 21:55:57 +00:00
|
|
|
ipx_host *host = find_host(packet->dest_net, packet->dest_node);
|
|
|
|
|
2011-04-24 02:08:37 +00:00
|
|
|
struct sockaddr_in saddr;
|
|
|
|
saddr.sin_family = AF_INET;
|
2011-04-24 18:44:31 +00:00
|
|
|
saddr.sin_port = htons(global_conf.udp_port);
|
2011-09-07 20:03:16 +00:00
|
|
|
saddr.sin_addr.s_addr = (host ? host->ipaddr : (global_conf.bcast_all ? INADDR_BROADCAST : sockptr->nic_bcast));
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2011-09-09 19:03:19 +00:00
|
|
|
int sval = r_sendto(send_fd, (char*)packet, psize, 0, (struct sockaddr*)&saddr, sizeof(saddr));
|
2011-04-24 21:55:57 +00:00
|
|
|
if(sval == -1) {
|
|
|
|
len = -1;
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(packet);
|
|
|
|
RETURN(len);
|
|
|
|
}else{
|
2011-09-08 00:20:34 +00:00
|
|
|
return r_sendto(fd, buf, len, flags, addr, addrlen);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int PASCAL shutdown(SOCKET fd, int cmd) {
|
|
|
|
ipx_socket *sockptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(sockptr) {
|
|
|
|
if(cmd == SD_RECEIVE || cmd == SD_BOTH) {
|
2011-09-09 18:36:52 +00:00
|
|
|
if(!rclient_set_port(&g_rclient, fd, 0)) {
|
|
|
|
RETURN(-1);
|
|
|
|
}
|
|
|
|
|
2008-12-09 21:36:07 +00:00
|
|
|
sockptr->flags &= ~IPX_RECV;
|
2011-09-09 18:36:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(cmd == SD_SEND || cmd == SD_BOTH) {
|
|
|
|
sockptr->flags &= ~IPX_SEND;
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RETURN(0);
|
|
|
|
}else{
|
2011-09-08 00:20:34 +00:00
|
|
|
return r_shutdown(fd, cmd);
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-09 16:20:18 +00:00
|
|
|
|
|
|
|
int PASCAL ioctlsocket(SOCKET fd, long cmd, u_long *argp) {
|
|
|
|
ipx_socket *sockptr = get_socket(fd);
|
|
|
|
|
|
|
|
if(sockptr && cmd == FIONREAD) {
|
|
|
|
ipx_packet packet;
|
|
|
|
fd_set fdset;
|
|
|
|
struct timeval tv = {0,0};
|
|
|
|
|
|
|
|
FD_ZERO(&fdset);
|
|
|
|
FD_SET(sockptr->fd, &fdset);
|
|
|
|
|
|
|
|
int r = select(1, &fdset, NULL, NULL, &tv);
|
|
|
|
if(r == -1) {
|
|
|
|
RETURN(-1);
|
|
|
|
}else if(r == 0) {
|
|
|
|
*(unsigned long*)argp = 0;
|
|
|
|
RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = r_recv(sockptr->fd, (char*)&packet, sizeof(packet), MSG_PEEK);
|
|
|
|
if(r == -1 && WSAGetLastError() != WSAEMSGSIZE) {
|
|
|
|
RETURN(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
*(unsigned long*)argp = packet.size;
|
|
|
|
RETURN(0);
|
|
|
|
}
|
2011-09-08 00:20:34 +00:00
|
|
|
|
|
|
|
if(sockptr) {
|
|
|
|
unlock_sockets();
|
|
|
|
}
|
|
|
|
|
|
|
|
return r_ioctlsocket(fd, cmd, argp);
|
2010-01-09 16:20:18 +00:00
|
|
|
}
|