Hi, The following three patches improve wine's winsock ipx support. With these patches various games work now using IPX. For example C&C Red Alert (v 3.x) and Tiberian Sun, I expect other games to work too (Red Alert II ...). First I'll start describing all patches. The patch wsnwlink.h.diff adds a new header to wine which is needed for the winsock improvements. The patch called winsock.diff adds various new ipx stuff (IPX_PTYPE, IPX_ADDRESS ..) to the winsock dll. One new feature (IPX_PTYPE) needs a patch to the wineserver. Inside the functions WS_getsockopt/WS_setsockopt the option IPX_PTYPE was missing. On windows this option can get/set the ipx packet type. The unix way to change the packet type is to change one of the members of the unix sockaddr_ipx structure. The winsock sockaddr_ipx structure lacks this member. :( Just adding the variable can't be done ofcourse since this structure is part of the official winsock api's. Mike McCormack advised me to add a wineserver call to get/set the packet type value. This new wineserver call can be found in wineserver.diff. I'm using the new call in 3 different places inside winsock: in WS_getsockopt, WS_setsockopt and in WS2_send. There is one thing I don't like about my work. That part is quite hacky and because of this I didn't clean it up since it will likely be rejected. Inside ws2_send the winsock sockaddr structure is converted to its unix equivalent before sending the data by ws_sockaddr_ws2u. The packet type needs to be set to a variable of the unix sockaddr_ipx structure. Because of this I need my new wineserver call. The problem more is that my call needs the socket and I only have the fd. I tried using wine_server_fd_to_handle but I don't think that is the correct function to convert the fd back to the socket/handle. (didn't get good results) In the end I added the socket as a hack to the prototype of the function. Because I don't think it is the correct way, I didn't clean this part up. I hope we can find a more correct solution. ChangeLog: - implement getsockopt/setsockopt's IPX_PTYPE, IPX_ADDRESS and IPX_MAD_ADAPATER_NUM Roderick
Index: dlls/winsock/socket.c =================================================================== RCS file: /home/wine/wine/dlls/winsock/socket.c,v retrieving revision 1.130 diff -u -r1.130 socket.c --- dlls/winsock/socket.c 30 Jun 2003 20:53:48 -0000 1.130 +++ dlls/winsock/socket.c 12 Jul 2003 13:12:22 -0000 @@ -182,6 +182,11 @@ DWORD flags; } ws2_async; +#ifdef HAVE_IPX +# include "wsnwlink.h" +#endif + + /****************************************************************/ /* ----------------------------------- internal data */ @@ -1247,7 +1252,7 @@ * Work horse for both synchronous and asynchronous send() operations. */ static int WS2_send ( int fd, struct iovec* iov, int count, - const struct WS_sockaddr *to, INT tolen, DWORD dwFlags ) + const struct WS_sockaddr *to, INT tolen, DWORD dwFlags, SOCKET s) { struct msghdr hdr; int n = -1; @@ -1261,6 +1266,25 @@ #if DEBUG_SOCKADDR dump_sockaddr (to); #endif + +#ifdef HAVE_IPX + if(to->sa_family == WS_AF_IPX) + { + struct sockaddr_ipx* uipx; + uipx = (struct sockaddr_ipx*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen ); + + SERVER_START_REQ(packet_type ) + { + req->flags = IPX_GET_PTYPE; + req->handle = SOCKET2HANDLE(s); + wine_server_call( req ); + uipx->sipx_type=reply->ptype; + } + SERVER_END_REQ; + hdr.msg_name = (struct sockaddr*) uipx; + } + else +#endif hdr.msg_name = (struct sockaddr*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen ); if ( !hdr.msg_name ) { @@ -1308,7 +1332,7 @@ } result = WS2_send ( wsa->async.fd, wsa->iovec, wsa->n_iovecs, - wsa->addr, wsa->addrlen.val, wsa->flags ); + wsa->addr, wsa->addrlen.val, wsa->flags, 0 ); if (result >= 0) { @@ -1826,6 +1850,55 @@ return 0; } +#ifdef HAVE_IPX + if(level == NSPROTO_IPX) + { + struct WS_sockaddr_ipx addr; + IPX_ADDRESS_DATA *data; + int namelen; + switch(optname) + { + case IPX_PTYPE: + SERVER_START_REQ(packet_type ) + { + req->flags = IPX_GET_PTYPE; + req->handle = SOCKET2HANDLE (s); + + wine_server_call( req ); + *(int*)optval = reply->ptype; + *optlen = sizeof(int); + } + SERVER_END_REQ; + return 0; + break; + case IPX_ADDRESS: + namelen = sizeof(struct WS_sockaddr); + memset(&addr, 0, sizeof(struct WS_sockaddr)); + WS_getsockname(s, (struct WS_sockaddr*)&addr, &namelen); + + data = (IPX_ADDRESS_DATA*)optval; + memcpy(data->nodenum,&addr.sa_nodenum,sizeof(data->nodenum)); + memcpy(data->netnum,&addr.sa_netnum,sizeof(data->netnum)); + data->adapternum = 0; + data->wan = FALSE; /* We are not on a wan for now .. */ + data->status = FALSE; /* Since we are not on a wan, the wan link isn't up */ + data->maxpkt = 1500; /* Is this value correct, I found it on a IPX page */ + data->linkspeed = 13107; /* Set the line speed to 10 Mbit / 1.25 MB for now */ + FIXME("IPX_ADDRESS\n"); + return 0; + break; + case IPX_MAX_ADAPTER_NUM: + *(int*)optval = 1; /* Only one card for the moment .. */ + FIXME("IPX_MAX_ADAPTER_NUM\n"); + return 0; + break; + default: + FIXME("opt_name:%x\n", optname); + return SOCKET_ERROR; + } + } +#endif + fd = _get_sock_fd(s); if (fd != -1) { @@ -2476,7 +2549,7 @@ do_block(fd, 2); } - n = WS2_send ( fd, iovec, dwBufferCount, to, tolen, dwFlags ); + n = WS2_send ( fd, iovec, dwBufferCount, to, tolen, dwFlags, s ); if ( n == -1 ) { err = wsaErrno(); @@ -2572,6 +2645,44 @@ return 0; } +#ifdef HAVE_IPX + if(level == NSPROTO_IPX) + { + struct WS_sockaddr addr; + struct sockaddr_ipx* sipx; + int namelen, uaddrlen; + switch(optname) + { + case IPX_PTYPE: + namelen = sizeof(struct WS_sockaddr); + memset(&addr, 0, sizeof(struct WS_sockaddr)); + WS_getsockname(s, &addr, &namelen); + sipx = (struct sockaddr_ipx*)ws_sockaddr_ws2u(&addr, sizeof(addr), &uaddrlen); + + SERVER_START_REQ(packet_type ) + { + req->flags = IPX_SET_PTYPE; + req->handle = SOCKET2HANDLE (s); + + req->value = *optval; + wine_server_call( req ); + } + SERVER_END_REQ; + return 0; + break; + case IPX_FILTERPTYPE: + /* sets the receive filter packet type */ + /* SO_ATTACH_FILTER ??*/ + FIXME("IPX_FILTERPTYPE: %x\n", *optval); + return 0; + break; + default: + FIXME("opt_name:%x\n", optname); + return SOCKET_ERROR; + } + return 0; + } +#endif fd = _get_sock_fd(s); if (fd != -1)
--- /dev/null 2003-01-18 20:54:32.000000000 +0100 +++ ./include/wsnwlink.h 2003-07-12 14:21:34.000000000 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003 Roderick Colenbrander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WSNWLINK_ +#define _WSNWLINK_ + +#include "wtypes.h" + +#define IPX_PTYPE 0x4000 +#define IPX_FILTERPTYPE 0x4001 +#define IPX_DSTYPE 0x4002 +#define IPX_STOPFILTERPTYPE 0x4003 +#define IPX_EXTENDED_ADDRESS 0x4004 +#define IPX_RECVHDR 0x4005 +#define IPX_MAXSIZE 0x4006 +#define IPX_ADDRESS 0x4007 +#define IPX_GETNETINFO 0x4008 +#define IPX_GETNETINFO_NORIP 0x4009 +#define IPX_SPXGETCONNECTIONSTATUS 0x400b +#define IPX_ADDRESS_NOTIFY 0x400c +#define IPX_MAX_ADAPTER_NUM 0x400d +#define IPX_RERIPNETNUMBER 0x400e +#define IPX_RECEIVE_BROADCAST 0x400f +#define IPX_IMMEDIATESPXACK 0x4010 + +typedef struct _IPX_ADDRESS_DATA { + INT adapternum; + UCHAR netnum[4]; + UCHAR nodenum[6]; + BOOLEAN wan; + BOOLEAN status; + INT maxpkt; + ULONG linkspeed; +} IPX_ADDRESS_DATA, *PIPX_ADDRESS_DATA; + +#endif +
Index: include/wine/server_protocol.h =================================================================== RCS file: /home/wine/wine/include/wine/server_protocol.h,v retrieving revision 1.76 diff -u -r1.76 server_protocol.h --- include/wine/server_protocol.h 11 Jul 2003 21:55:59 -0000 1.76 +++ include/wine/server_protocol.h 12 Jul 2003 13:12:23 -0000 @@ -3081,6 +3081,22 @@ #define CB_OPEN 0x040 #define CB_OWNER 0x080 +struct packet_type_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int flags; + int value; +}; +struct packet_type_reply +{ + struct reply_header __header; + int ptype; +}; + +#define IPX_GET_PTYPE 0x1 +#define IPX_SET_PTYPE 0x2 + enum request { @@ -3260,6 +3276,7 @@ REQ_finish_hook_chain, REQ_get_next_hook, REQ_set_clipboard_info, + REQ_packet_type, REQ_NB_REQUESTS }; @@ -3443,6 +3460,7 @@ struct finish_hook_chain_request finish_hook_chain_request; struct get_next_hook_request get_next_hook_request; struct set_clipboard_info_request set_clipboard_info_request; + struct packet_type_request packet_type_request; }; union generic_reply { @@ -3624,8 +3642,9 @@ struct finish_hook_chain_reply finish_hook_chain_reply; struct get_next_hook_reply get_next_hook_reply; struct set_clipboard_info_reply set_clipboard_info_reply; + struct packet_type_reply packet_type_reply; }; -#define SERVER_PROTOCOL_VERSION 116 +#define SERVER_PROTOCOL_VERSION 117 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ Index: server/protocol.def =================================================================== RCS file: /home/wine/wine/server/protocol.def,v retrieving revision 1.76 diff -u -r1.76 protocol.def --- server/protocol.def 11 Jul 2003 21:55:58 -0000 1.76 +++ server/protocol.def 12 Jul 2003 13:12:25 -0000 @@ -2160,3 +2160,14 @@ #define SET_CB_CLOSE 0x020 #define CB_OPEN 0x040 #define CB_OWNER 0x080 + +@REQ(packet_type) + obj_handle_t handle; /* handle to the socket */ + unsigned int flags; /* get/set packet type */ + int value; /* packet type */ +@REPLY + int ptype; +@END + +#define IPX_GET_PTYPE 0x1 /* get ipx packet type */ +#define IPX_SET_PTYPE 0x2 /* set ipx packet type */ Index: server/request.h =================================================================== RCS file: /home/wine/wine/server/request.h,v retrieving revision 1.86 diff -u -r1.86 request.h --- server/request.h 23 Jun 2003 23:02:03 -0000 1.86 +++ server/request.h 12 Jul 2003 13:12:25 -0000 @@ -279,6 +279,7 @@ DECL_HANDLER(finish_hook_chain); DECL_HANDLER(get_next_hook); DECL_HANDLER(set_clipboard_info); +DECL_HANDLER(packet_type); #ifdef WANT_REQUEST_HANDLERS @@ -461,6 +462,7 @@ (req_handler)req_finish_hook_chain, (req_handler)req_get_next_hook, (req_handler)req_set_clipboard_info, + (req_handler)req_packet_type, }; #endif /* WANT_REQUEST_HANDLERS */ Index: server/sock.c =================================================================== RCS file: /home/wine/wine/server/sock.c,v retrieving revision 1.45 diff -u -r1.45 sock.c --- server/sock.c 12 Mar 2003 22:38:14 -0000 1.45 +++ server/sock.c 12 Jul 2003 13:12:25 -0000 @@ -1,7 +1,7 @@ /* * Server-side socket management * - * Copyright (C) 1999 Marcus Meissner, Ove Kåven + * Copyright (C) 1999 Marcus Meissner, Ove KÃ¥ven * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -82,6 +82,7 @@ struct sock* deferred; /* socket that waits for a deferred accept */ struct async_queue read_q; /* Queue for asynchronous reads */ struct async_queue write_q; /* Queue for asynchronous writes */ + int ptype; /* packet type, only used for ipx */ }; static void sock_dump( struct object *obj, int verbose ); @@ -616,6 +617,7 @@ sock->message = 0; sock->wparam = 0; sock->deferred = NULL; + sock->ptype = 0; if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj ))) { release_object( sock ); @@ -921,5 +923,24 @@ return; } sock->deferred = acceptsock; + release_object ( sock ); +} + +DECL_HANDLER(packet_type) +{ + struct sock *sock; + + sock=(struct sock*)get_handle_obj( current->process,req->handle, + GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops ); + if(!sock) + { + return; + } + + if(req->flags == IPX_GET_PTYPE) + reply->ptype = sock->ptype; + else + sock->ptype = req->value; + release_object ( sock ); } Index: server/trace.c =================================================================== RCS file: /home/wine/wine/server/trace.c,v retrieving revision 1.173 diff -u -r1.173 trace.c --- server/trace.c 11 Jul 2003 21:55:58 -0000 1.173 +++ server/trace.c 12 Jul 2003 13:12:26 -0000 @@ -2486,6 +2486,18 @@ fprintf( stderr, " seqno=%08x", req->seqno ); } +static void dump_packet_type_request( const struct packet_type_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " value=%d", req->value ); +} + +static void dump_packet_type_reply( const struct packet_type_reply *req ) +{ + fprintf( stderr, " ptype=%d", req->ptype ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -2663,6 +2675,7 @@ (dump_func)dump_finish_hook_chain_request, (dump_func)dump_get_next_hook_request, (dump_func)dump_set_clipboard_info_request, + (dump_func)dump_packet_type_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -2842,6 +2855,7 @@ (dump_func)0, (dump_func)dump_get_next_hook_reply, (dump_func)dump_set_clipboard_info_reply, + (dump_func)dump_packet_type_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -3021,6 +3035,7 @@ "finish_hook_chain", "get_next_hook", "set_clipboard_info", + "packet_type", }; /* ### make_requests end ### */