| /* |
| * based on Windows Sockets 1.1 specs |
| * (ftp.microsoft.com:/Advsys/winsock/spec11/WINSOCK.TXT) |
| * |
| * (C) 1993,1994 John Brezak, Erik Bos. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <signal.h> |
| #include <sys/types.h> |
| #include <sys/ipc.h> |
| #include <sys/ioctl.h> |
| #include <sys/msg.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <netdb.h> |
| #include <unistd.h> |
| #include "heap.h" |
| #include "winsock.h" |
| #include "stddebug.h" |
| #include "debug.h" |
| |
| static WORD wsa_errno; |
| static int wsa_initted; |
| static key_t wine_key = 0; |
| static FARPROC BlockFunction; |
| static fd_set fd_in_use; |
| |
| struct ipc_packet { |
| long mtype; |
| HANDLE handle; |
| HWND hWnd; |
| WORD wMsg; |
| LONG lParam; |
| }; |
| #define IPC_PACKET_SIZE (sizeof(struct ipc_packet) - sizeof(long)) |
| #define MTYPE 0xb0b0eb05 |
| #define WINE_PACKED __attribute__ ((packed)) |
| |
| struct WIN_hostent { |
| char *h_name WINE_PACKED; /* official name of host */ |
| char **h_aliases WINE_PACKED; /* alias list */ |
| int h_addrtype WINE_PACKED; /* host address type */ |
| int h_length WINE_PACKED; /* length of address */ |
| char **h_addr_list WINE_PACKED; /* list of addresses from name server */ |
| char *names[2]; |
| char hostname[200]; |
| }; |
| |
| struct WIN_protoent { |
| char *p_name WINE_PACKED; /* official protocol name */ |
| char **p_aliases WINE_PACKED; /* alias list */ |
| int p_proto WINE_PACKED; /* protocol # */ |
| }; |
| |
| struct WIN_servent { |
| char *s_name WINE_PACKED; /* official service name */ |
| char **s_aliases WINE_PACKED; /* alias list */ |
| int s_port WINE_PACKED; /* port # */ |
| char *s_proto WINE_PACKED; /* protocol to use */ |
| }; |
| |
| struct WinSockHeap { |
| char ntoa_buffer[32]; |
| |
| struct WIN_hostent hostent_addr; |
| struct WIN_hostent hostent_name; |
| struct WIN_protoent protoent_name; |
| struct WIN_protoent protoent_number; |
| struct WIN_servent servent_name; |
| struct WIN_servent servent_port; |
| |
| struct WIN_hostent WSAhostent_addr; |
| struct WIN_hostent WSAhostent_name; |
| struct WIN_protoent WSAprotoent_name; |
| struct WIN_protoent WSAprotoent_number; |
| struct WIN_servent WSAservent_name; |
| struct WIN_servent WSAservent_port; |
| }; |
| static struct WinSockHeap *heap; |
| |
| #define dump_sockaddr(a) \ |
| fprintf(stderr, "sockaddr_in: family %d, address %s, port %d\n", \ |
| ((struct sockaddr_in *)a)->sin_family, \ |
| inet_ntoa(((struct sockaddr_in *)a)->sin_addr), \ |
| ntohs(((struct sockaddr_in *)a)->sin_port)) |
| |
| static WORD wsaerrno(void) |
| { |
| #ifdef DEBUG_WINSOCK |
| #ifndef sun |
| #if defined(__FreeBSD__) |
| fprintf(stderr, "winsock: errno %d, (%s).\n", |
| errno, sys_errlist[errno]); |
| #else |
| fprintf(stderr, "winsock: errno %d, (%s).\n", |
| errno, strerror(errno)); |
| #endif |
| #else |
| fprintf(stderr, "winsock: errno %d\n", errno); |
| #endif |
| #endif |
| |
| switch(errno) |
| { |
| case EINTR: return WSAEINTR; |
| case EACCES: return WSAEACCES; |
| case EFAULT: return WSAEFAULT; |
| case EINVAL: return WSAEINVAL; |
| case EMFILE: return WSAEMFILE; |
| case EWOULDBLOCK: return WSAEWOULDBLOCK; |
| case EINPROGRESS: return WSAEINPROGRESS; |
| case EALREADY: return WSAEALREADY; |
| case EBADF: |
| case ENOTSOCK: return WSAENOTSOCK; |
| case EDESTADDRREQ: return WSAEDESTADDRREQ; |
| case EMSGSIZE: return WSAEMSGSIZE; |
| case EPROTOTYPE: return WSAEPROTOTYPE; |
| case ENOPROTOOPT: return WSAENOPROTOOPT; |
| case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT; |
| case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT; |
| case EOPNOTSUPP: return WSAEOPNOTSUPP; |
| case EPFNOSUPPORT: return WSAEPFNOSUPPORT; |
| case EAFNOSUPPORT: return WSAEAFNOSUPPORT; |
| case EADDRINUSE: return WSAEADDRINUSE; |
| case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL; |
| case ENETDOWN: return WSAENETDOWN; |
| case ENETUNREACH: return WSAENETUNREACH; |
| case ENETRESET: return WSAENETRESET; |
| case ECONNABORTED: return WSAECONNABORTED; |
| case ECONNRESET: return WSAECONNRESET; |
| case ENOBUFS: return WSAENOBUFS; |
| case EISCONN: return WSAEISCONN; |
| case ENOTCONN: return WSAENOTCONN; |
| case ESHUTDOWN: return WSAESHUTDOWN; |
| case ETOOMANYREFS: return WSAETOOMANYREFS; |
| case ETIMEDOUT: return WSAETIMEDOUT; |
| case ECONNREFUSED: return WSAECONNREFUSED; |
| case ELOOP: return WSAELOOP; |
| case ENAMETOOLONG: return WSAENAMETOOLONG; |
| case EHOSTDOWN: return WSAEHOSTDOWN; |
| case EHOSTUNREACH: return WSAEHOSTUNREACH; |
| case ENOTEMPTY: return WSAENOTEMPTY; |
| #ifdef EPROCLIM |
| case EPROCLIM: return WSAEPROCLIM; |
| #endif |
| case EUSERS: return WSAEUSERS; |
| case EDQUOT: return WSAEDQUOT; |
| case ESTALE: return WSAESTALE; |
| case EREMOTE: return WSAEREMOTE; |
| |
| default: |
| fprintf(stderr, "winsock: unknown errorno %d!\n", errno); |
| return WSAEOPNOTSUPP; |
| } |
| } |
| |
| static void errno_to_wsaerrno(void) |
| { |
| wsa_errno = wsaerrno(); |
| } |
| |
| static void convert_sockopt(INT *level, INT *optname) |
| { |
| /* $%#%!@! why couldn't they use the same values for both winsock and unix ? */ |
| |
| switch (*level) { |
| case -1: |
| *level = SOL_SOCKET; |
| switch (*optname) { |
| case 0x01: *optname = SO_DEBUG; |
| break; |
| case 0x04: *optname = SO_REUSEADDR; |
| break; |
| case 0x08: *optname = SO_KEEPALIVE; |
| break; |
| case 0x10: *optname = SO_DONTROUTE; |
| break; |
| case 0x20: *optname = SO_BROADCAST; |
| break; |
| case 0x80: *optname = SO_LINGER; |
| break; |
| case 0x100: *optname = SO_OOBINLINE; |
| break; |
| case 0x1001: *optname = SO_SNDBUF; |
| break; |
| case 0x1002: *optname = SO_RCVBUF; |
| break; |
| case 0x1007: *optname = SO_ERROR; |
| break; |
| case 0x1008: *optname = SO_TYPE; |
| break; |
| default: |
| fprintf(stderr, "convert_sockopt() unknown optname %d\n", *optname); |
| break; |
| } |
| break; |
| case 6: *optname = IPPROTO_TCP; |
| } |
| } |
| |
| #ifndef WINELIB |
| static void CONVERT_HOSTENT(struct WIN_hostent *heap, struct hostent *host) |
| { |
| |
| } |
| |
| static void CONVERT_PROTOENT(struct WIN_protoent *heap, struct protoent *proto) |
| { |
| |
| } |
| |
| static void CONVERT_SERVENT(struct WIN_servent *heap, struct servent *serv) |
| { |
| |
| } |
| #else |
| #define CONVERT_HOSTENT(a,b) memcpy(&a, &b, sizeof(a)) |
| #define CONVERT_PROTOENT(a,b) memcpy(&a, &b, sizeof(a)) |
| #define CONVERT_SERVENT(a,b) memcpy(&a, &b, sizeof(a)) |
| #endif |
| |
| SOCKET WINSOCK_accept(SOCKET s, struct sockaddr *addr, INT *addrlen) |
| { |
| int sock; |
| |
| dprintf_winsock(stddeb, "WSA_accept: socket %d, ptr %8x, length %d\n", s, (int) addr, *addrlen); |
| |
| if ((sock = accept(s, addr, (int *) addrlen)) < 0) { |
| errno_to_wsaerrno(); |
| return INVALID_SOCKET; |
| } |
| return sock; |
| } |
| |
| INT WINSOCK_bind(SOCKET s, struct sockaddr *name, INT namelen) |
| { |
| dprintf_winsock(stddeb, "WSA_bind: socket %d, ptr %8x, length %d\n", s, (int) name, namelen); |
| dump_sockaddr(name); |
| |
| if (bind(s, name, namelen) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| INT WINSOCK_closesocket(SOCKET s) |
| { |
| dprintf_winsock(stddeb, "WSA_closesocket: socket %d\n", s); |
| |
| FD_CLR(s, &fd_in_use); |
| |
| if (close(s) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| INT WINSOCK_connect(SOCKET s, struct sockaddr *name, INT namelen) |
| { |
| dprintf_winsock(stddeb, "WSA_connect: socket %d, ptr %8x, length %d\n", s, (int) name, namelen); |
| dump_sockaddr(name); |
| |
| if (connect(s, name, namelen) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| INT WINSOCK_getpeername(SOCKET s, struct sockaddr *name, INT *namelen) |
| { |
| dprintf_winsock(stddeb, "WSA_getpeername: socket: %d, ptr %8x, ptr %8x\n", s, (int) name, *namelen); |
| dump_sockaddr(name); |
| |
| if (getpeername(s, name, (int *) namelen) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| INT WINSOCK_getsockname(SOCKET s, struct sockaddr *name, INT *namelen) |
| { |
| dprintf_winsock(stddeb, "WSA_getsockname: socket: %d, ptr %8x, ptr %8x\n", s, (int) name, (int) *namelen); |
| if (getsockname(s, name, (int *) namelen) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| INT |
| WINSOCK_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen) |
| { |
| dprintf_winsock(stddeb, "WSA_getsockopt: socket: %d, opt %d, ptr %8x, ptr %8x\n", s, level, (int) optval, (int) *optlen); |
| convert_sockopt(&level, &optname); |
| |
| if (getsockopt(s, (int) level, optname, optval, (int *) optlen) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| u_long WINSOCK_htonl(u_long hostlong) |
| { |
| return( htonl(hostlong) ); |
| } |
| |
| u_short WINSOCK_htons(u_short hostshort) |
| { |
| return( htons(hostshort) ); |
| } |
| |
| u_long WINSOCK_inet_addr(char *cp) |
| { |
| return( inet_addr(cp) ); |
| } |
| |
| char *WINSOCK_inet_ntoa(struct in_addr in) |
| { |
| char *s; |
| |
| /* dprintf_winsock(stddeb, "WSA_inet_ntoa: %8lx\n", (int) in);*/ |
| |
| if ((s = inet_ntoa(in)) == NULL) { |
| errno_to_wsaerrno(); |
| return NULL; |
| } |
| |
| strncpy(heap->ntoa_buffer, s, sizeof(heap->ntoa_buffer) ); |
| |
| return (char *) &heap->ntoa_buffer; |
| } |
| |
| INT WINSOCK_ioctlsocket(SOCKET s, long cmd, u_long *argp) |
| { |
| dprintf_winsock(stddeb, "WSA_ioctl: socket %d, cmd %ld, ptr %8x\n", s, cmd, (int) argp); |
| |
| if (ioctl(s, cmd, argp) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| INT WINSOCK_listen(SOCKET s, INT backlog) |
| { |
| dprintf_winsock(stddeb, "WSA_listen: socket %d, backlog %d\n", s, backlog); |
| |
| if (listen(s, backlog) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| u_long WINSOCK_ntohl(u_long netlong) |
| { |
| return( ntohl(netlong) ); |
| } |
| |
| u_short WINSOCK_ntohs(u_short netshort) |
| { |
| return( ntohs(netshort) ); |
| } |
| |
| INT WINSOCK_recv(SOCKET s, char *buf, INT len, INT flags) |
| { |
| int length; |
| |
| dprintf_winsock(stddeb, "WSA_recv: socket %d, ptr %8x, length %d, flags %d\n", s, (int) buf, len, flags); |
| |
| if ((length = recv(s, buf, len, flags)) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return length; |
| } |
| |
| INT WINSOCK_recvfrom(SOCKET s, char *buf, INT len, INT flags, |
| struct sockaddr *from, int *fromlen) |
| { |
| int length; |
| |
| dprintf_winsock(stddeb, "WSA_recvfrom: socket %d, ptr %8lx, length %d, flags %d\n", s, (unsigned long)buf, len, flags); |
| |
| if ((length = recvfrom(s, buf, len, flags, from, fromlen)) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return length; |
| } |
| |
| INT WINSOCK_select(INT nfds, fd_set *readfds, fd_set *writefds, |
| fd_set *exceptfds, struct timeval *timeout) |
| { |
| dprintf_winsock(stddeb, "WSA_select: fd # %d, ptr %8lx, ptr %8lx, ptr %8lX\n", nfds, (unsigned long) readfds, (unsigned long) writefds, (unsigned long) exceptfds); |
| |
| return(select(nfds, readfds, writefds, exceptfds, timeout)); |
| } |
| |
| INT WINSOCK_send(SOCKET s, char *buf, INT len, INT flags) |
| { |
| int length; |
| |
| dprintf_winsock(stddeb, "WSA_send: socket %d, ptr %8lx, length %d, flags %d\n", s, (unsigned long) buf, len, flags); |
| |
| if ((length = send(s, buf, len, flags)) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return length; |
| } |
| |
| INT WINSOCK_sendto(SOCKET s, char *buf, INT len, INT flags, |
| struct sockaddr *to, INT tolen) |
| { |
| int length; |
| |
| dprintf_winsock(stddeb, "WSA_sendto: socket %d, ptr %8lx, length %d, flags %d\n", s, (unsigned long) buf, len, flags); |
| |
| if ((length = sendto(s, buf, len, flags, to, tolen)) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return length; |
| } |
| |
| INT WINSOCK_setsockopt(SOCKET s, INT level, INT optname, const char *optval, |
| INT optlen) |
| { |
| dprintf_winsock(stddeb, "WSA_setsockopt: socket %d, level %d, opt %d, ptr %8x, len %d\n", s, level, optname, (int) optval, optlen); |
| convert_sockopt(&level, &optname); |
| |
| if (setsockopt(s, level, optname, optval, optlen) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| INT WINSOCK_shutdown(SOCKET s, INT how) |
| { |
| dprintf_winsock(stddeb, "WSA_shutdown: socket s %d, how %d\n", s, how); |
| |
| if (shutdown(s, how) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| SOCKET WINSOCK_socket(INT af, INT type, INT protocol) |
| { |
| int sock; |
| |
| dprintf_winsock(stddeb, "WSA_socket: af=%d type=%d protocol=%d\n", af, type, protocol); |
| |
| if ((sock = socket(af, type, protocol)) < 0) { |
| errno_to_wsaerrno(); |
| dprintf_winsock(stddeb, "WSA_socket: failed !\n"); |
| return INVALID_SOCKET; |
| } |
| |
| if (sock > 0xffff) { |
| wsa_errno = WSAEMFILE; |
| return INVALID_SOCKET; |
| } |
| |
| FD_SET(sock, &fd_in_use); |
| |
| dprintf_winsock(stddeb, "WSA_socket: fd %d\n", sock); |
| return sock; |
| } |
| |
| struct WIN_hostent *WINSOCK_gethostbyaddr(const char *addr, INT len, INT type) |
| { |
| struct hostent *host; |
| |
| dprintf_winsock(stddeb, "WSA_gethostbyaddr: ptr %8x, len %d, type %d\n", (int) addr, len, type); |
| |
| if ((host = gethostbyaddr(addr, len, type)) == NULL) { |
| errno_to_wsaerrno(); |
| return NULL; |
| } |
| CONVERT_HOSTENT(&heap->hostent_addr, host); |
| |
| return &heap->hostent_addr; |
| } |
| |
| struct WIN_hostent *WINSOCK_gethostbyname(const char *name) |
| { |
| struct hostent *host; |
| |
| dprintf_winsock(stddeb, "WSA_gethostbyname: %s\n", name); |
| |
| if ((host = gethostbyname(name)) == NULL) { |
| errno_to_wsaerrno(); |
| return NULL; |
| } |
| CONVERT_HOSTENT(&heap->hostent_name, host); |
| |
| return &heap->hostent_name; |
| } |
| |
| INT WINSOCK_gethostname(char *name, INT namelen) |
| { |
| dprintf_winsock(stddeb, "WSA_gethostname: name %s, len %d\n", name, namelen); |
| |
| if (gethostname(name, namelen) < 0) { |
| errno_to_wsaerrno(); |
| return SOCKET_ERROR; |
| } |
| return 0; |
| } |
| |
| struct WIN_protoent *WINSOCK_getprotobyname(char *name) |
| { |
| struct protoent *proto; |
| |
| dprintf_winsock(stddeb, "WSA_getprotobyname: name %s\n", name); |
| |
| if ((proto = getprotobyname(name)) == NULL) { |
| errno_to_wsaerrno(); |
| return NULL; |
| } |
| CONVERT_PROTOENT(&heap->protoent_name, proto); |
| |
| return &heap->protoent_name; |
| } |
| |
| struct WIN_protoent *WINSOCK_getprotobynumber(INT number) |
| { |
| struct protoent *proto; |
| |
| dprintf_winsock(stddeb, "WSA_getprotobynumber: num %d\n", number); |
| |
| if ((proto = getprotobynumber(number)) == NULL) { |
| errno_to_wsaerrno(); |
| return NULL; |
| } |
| CONVERT_PROTOENT(&heap->protoent_number, proto); |
| |
| return &heap->protoent_number; |
| } |
| |
| struct WIN_servent *WINSOCK_getservbyname(const char *name, const char *proto) |
| { |
| struct servent *service; |
| |
| if (proto == NULL) |
| proto = "tcp"; |
| |
| dprintf_winsock(stddeb, "WSA_getservbyname: name %s, proto %s\n", name, proto); |
| |
| if ((service = getservbyname(name, proto)) == NULL) { |
| errno_to_wsaerrno(); |
| return NULL; |
| } |
| CONVERT_SERVENT(&heap->servent_name, service); |
| |
| return &heap->servent_name; |
| } |
| |
| struct WIN_servent *WINSOCK_getservbyport(INT port, const char *proto) |
| { |
| struct servent *service; |
| |
| dprintf_winsock(stddeb, "WSA_getservbyport: port %d, name %s\n", port, proto); |
| |
| if ((service = getservbyport(port, proto)) == NULL) { |
| errno_to_wsaerrno(); |
| return NULL; |
| } |
| CONVERT_SERVENT(&heap->servent_port, service); |
| |
| return &heap->servent_port; |
| } |
| |
| /******************** winsock specific functions ************************ |
| * |
| */ |
| static HANDLE new_handle = 0; |
| |
| static HANDLE AllocWSAHandle(void) |
| { |
| return new_handle++; |
| } |
| |
| static void recv_message(int sig) |
| { |
| struct ipc_packet message; |
| |
| if (msgrcv(wine_key, &message, IPC_PACKET_SIZE, MTYPE, IPC_NOWAIT) == -1) |
| perror("wine: msgrcv"); |
| |
| fprintf(stderr, |
| "WSA: PostMessage (hwnd %d, wMsg %d, wParam %d, lParam %ld)\n", |
| message.hWnd, |
| message.wMsg, |
| message.handle, |
| message.lParam); |
| |
| PostMessage(message.hWnd, message.wMsg, message.handle, message.lParam); |
| |
| signal(SIGUSR1, recv_message); |
| } |
| |
| |
| static void send_message(HANDLE handle, HWND hWnd, u_int wMsg, long lParam) |
| { |
| struct ipc_packet message; |
| |
| message.mtype = MTYPE; |
| message.handle = handle; |
| message.hWnd = hWnd; |
| message.wMsg = wMsg; |
| message.lParam = lParam; |
| |
| fprintf(stderr, |
| "WSA: send (hwnd %d, wMsg %d, handle %d, lParam %ld)\n", |
| hWnd, wMsg, handle, lParam); |
| |
| if (msgsnd(wine_key, &message, IPC_PACKET_SIZE, IPC_NOWAIT) == -1) |
| perror("wine: msgsnd"); |
| |
| kill(getppid(), SIGUSR1); |
| } |
| |
| |
| HANDLE WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg, const char *addr, |
| INT len, INT type, char *buf, INT buflen) |
| { |
| HANDLE handle; |
| struct hostent *host; |
| |
| handle = AllocWSAHandle(); |
| |
| if (fork()) { |
| return handle; |
| } else { |
| if ((host = gethostbyaddr(addr, len, type)) == NULL) { |
| send_message(hWnd, wMsg, handle, wsaerrno() << 16); |
| exit(0); |
| } |
| memcpy(buf, host, buflen); |
| send_message(hWnd, wMsg, handle, 0); |
| exit(0); |
| } |
| } |
| |
| |
| HANDLE WSAAsyncGetHostByName(HWND hWnd, u_int wMsg, const char *name, |
| char *buf, INT buflen) |
| { |
| HANDLE handle; |
| struct hostent *host; |
| |
| handle = AllocWSAHandle(); |
| |
| if (fork()) { |
| return handle; |
| } else { |
| if ((host = gethostbyname(name)) == NULL) { |
| send_message(hWnd, wMsg, handle, wsaerrno() << 16); |
| exit(0); |
| } |
| memcpy(buf, host, buflen); |
| send_message(hWnd, wMsg, handle, 0); |
| exit(0); |
| } |
| } |
| |
| |
| HANDLE WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg, const char *name, |
| char *buf, INT buflen) |
| { |
| HANDLE handle; |
| struct protoent *proto; |
| |
| handle = AllocWSAHandle(); |
| |
| if (fork()) { |
| return handle; |
| } else { |
| if ((proto = getprotobyname(name)) == NULL) { |
| send_message(hWnd, wMsg, handle, wsaerrno() << 16); |
| exit(0); |
| } |
| memcpy(buf, proto, buflen); |
| send_message(hWnd, wMsg, handle, 0); |
| exit(0); |
| } |
| } |
| |
| |
| HANDLE WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg, INT number, |
| char *buf, INT buflen) |
| { |
| HANDLE handle; |
| struct protoent *proto; |
| |
| handle = AllocWSAHandle(); |
| |
| if (fork()) { |
| return handle; |
| } else { |
| if ((proto = getprotobynumber(number)) == NULL) { |
| send_message(hWnd, wMsg, handle, wsaerrno() << 16); |
| exit(0); |
| } |
| memcpy(buf, proto, buflen); |
| send_message(hWnd, wMsg, handle, 0); |
| exit(0); |
| } |
| } |
| |
| |
| HANDLE WSAAsyncGetServByName(HWND hWnd, u_int wMsg, const char *name, |
| const char *proto, char *buf, INT buflen) |
| { |
| HANDLE handle; |
| struct servent *service; |
| |
| handle = AllocWSAHandle(); |
| |
| if (fork()) { |
| return handle; |
| } else { |
| if ((service = getservbyname(name, proto)) == NULL) { |
| send_message(hWnd, wMsg, handle, wsaerrno() << 16); |
| exit(0); |
| } |
| memcpy(buf, service, buflen); |
| send_message(hWnd, wMsg, handle, 0); |
| exit(0); |
| } |
| } |
| |
| |
| HANDLE WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, INT port, const char |
| *proto, char *buf, INT buflen) |
| { |
| HANDLE handle; |
| struct servent *service; |
| |
| handle = AllocWSAHandle(); |
| |
| if (fork()) { |
| return handle; |
| } else { |
| if ((service = getservbyport(port, proto)) == NULL) { |
| send_message(hWnd, wMsg, handle, wsaerrno() << 16); |
| exit(0); |
| } |
| memcpy(buf, service, buflen); |
| send_message(hWnd, wMsg, handle, 0); |
| exit(0); |
| } |
| } |
| |
| INT WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg, long lEvent) |
| { |
| long event; |
| fd_set read_fds, write_fds, except_fds; |
| |
| dprintf_winsock(stddeb, "WSA_AsyncSelect: socket %d, HWND %d, wMsg %d, event %ld\n", s, hWnd, wMsg, lEvent); |
| |
| /* remove outstanding asyncselect() processes */ |
| /* kill */ |
| |
| if (wMsg == 0 && lEvent == 0) |
| return 0; |
| |
| if (fork()) { |
| return 0; |
| } else { |
| while (1) { |
| FD_ZERO(&read_fds); |
| FD_ZERO(&write_fds); |
| FD_ZERO(&except_fds); |
| |
| if (lEvent & FD_READ) |
| FD_SET(s, &read_fds); |
| if (lEvent & FD_WRITE) |
| FD_SET(s, &write_fds); |
| |
| fcntl(s, F_SETFL, O_NONBLOCK); |
| select(s + 1, &read_fds, &write_fds, &except_fds, NULL); |
| |
| event = 0; |
| if (FD_ISSET(s, &read_fds)) |
| event |= FD_READ; |
| if (FD_ISSET(s, &write_fds)) |
| event |= FD_WRITE; |
| |
| send_message(hWnd, wMsg, s, (wsaerrno() << 16) | event); |
| } |
| } |
| } |
| |
| INT WSAFDIsSet(INT fd, fd_set *set) |
| { |
| return( FD_ISSET(fd, set) ); |
| } |
| |
| INT WSACancelAsyncRequest(HANDLE hAsyncTaskHandle) |
| { |
| dprintf_winsock(stddeb, "WSA_AsyncRequest: handle %d\n", hAsyncTaskHandle); |
| |
| return 0; |
| } |
| |
| INT WSACancelBlockingCall(void) |
| { |
| dprintf_winsock(stddeb, "WSA_CancelBlockCall\n"); |
| return 0; |
| } |
| |
| INT WSAGetLastError(void) |
| { |
| dprintf_winsock(stddeb, "WSA_GetLastError\n"); |
| |
| return wsa_errno; |
| } |
| |
| void WSASetLastError(INT iError) |
| { |
| dprintf_winsock(stddeb, "WSA_SetLastErorr %d\n", iError); |
| |
| wsa_errno = iError; |
| } |
| |
| BOOL WSAIsBlocking(void) |
| { |
| dprintf_winsock(stddeb, "WSA_IsBlocking\n"); |
| |
| return 0; |
| } |
| |
| FARPROC WSASetBlockingHook(FARPROC lpBlockFunc) |
| { |
| dprintf_winsock(stddeb, "WSA_SetBlockHook %8lx, STUB!\n", (unsigned long) lpBlockFunc); |
| BlockFunction = lpBlockFunc; |
| |
| return (FARPROC) lpBlockFunc; |
| } |
| |
| INT WSAUnhookBlockingHook(void) |
| { |
| dprintf_winsock(stddeb, "WSA_UnhookBlockingHook\n"); |
| BlockFunction = NULL; |
| |
| return 0; |
| } |
| |
| WSADATA WINSOCK_data = { |
| 0x0101, |
| 0x0101, |
| "WINE Sockets", |
| #ifdef linux |
| "LINUX/i386", |
| #endif |
| #ifdef __NetBSD__ |
| "NetBSD/i386", |
| #endif |
| #ifdef sunos |
| "SunOS", |
| #endif |
| 128, |
| 1024, |
| NULL |
| }; |
| |
| INT WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData) |
| { |
| int HeapHandle; |
| MDESC *MyHeap; |
| |
| dprintf_winsock(stddeb, "WSAStartup: verReq=%x\n", wVersionRequested); |
| |
| if (LOBYTE(wVersionRequested) < 1 || |
| (LOBYTE(wVersionRequested) == 1 && |
| HIBYTE(wVersionRequested) < 1)) |
| return WSAVERNOTSUPPORTED; |
| |
| if (!lpWSAData) |
| return WSAEINVAL; |
| |
| /* alloc winsock heap */ |
| |
| if ((HeapHandle = GlobalAlloc(GMEM_FIXED,sizeof(struct WinSockHeap))) == 0) |
| return WSASYSNOTREADY; |
| |
| heap = (struct WinSockHeap *) GlobalLock(HeapHandle); |
| #ifndef WINELIB |
| HEAP_Init(&MyHeap, heap, sizeof(struct WinSockHeap)); |
| #endif |
| bcopy(&WINSOCK_data, lpWSAData, sizeof(WINSOCK_data)); |
| |
| /* ipc stuff */ |
| |
| if ((wine_key = msgget(IPC_PRIVATE, 0600)) == -1) |
| perror("wine: msgget"); |
| |
| signal(SIGUSR1, recv_message); |
| |
| /* clear */ |
| |
| FD_ZERO(&fd_in_use); |
| |
| wsa_initted = 1; |
| return(0); |
| } |
| |
| INT WSACleanup(void) |
| { |
| int fd; |
| |
| if (wine_key) |
| if (msgctl(wine_key, IPC_RMID, NULL) == -1) |
| perror("wine: shmctl"); |
| |
| for (fd = 0; fd != FD_SETSIZE; fd++) |
| if (FD_ISSET(fd, &fd_in_use)) |
| close(fd); |
| |
| wsa_initted = 0; |
| return 0; |
| } |