From b72ccd6e5ae7c52132e420fe31d8d49788093d6c Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 21 Dec 2017 17:53:05 -0500 Subject: [PATCH] Implemented just enough of tcpip32.dll and dependencies to run FINGER.EXE. Finger (etc) also rely on MPTN\DLL\tnls32.dll, which I pulled out a copy of OS/2 Warp 4.52, which loads and limps along enough to not be a problem. Reimplementing that library is going to be a pain, so that's a job for another day. Inexplicably, tnls32 references pmgpi.dll's GpiQueryTextBox(), so I put a stub for that in, too, but we're nowhere near really implementing GPI yet. This is enough to run "finger.exe icculus@icculus.org" and see my .plan file, which I consider a victory. A few more TCP/IP command line tools aren't far behind. --- CMakeLists.txt | 2 +- native/os2.h | 2 + native/os2native.h | 1 + native/os2types.h | 3 + native/pmgpi.c | 16 +++ native/pmgpi.h | 25 +++++ native/tcpip32.c | 238 +++++++++++++++++++++++++++++++++++++++++++++ native/tcpip32.h | 109 +++++++++++++++++++++ 8 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 native/pmgpi.c create mode 100644 native/pmgpi.h create mode 100644 native/tcpip32.c create mode 100644 native/tcpip32.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 409d41c..1a7a3b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ elseif(CURSES_HAVE_CURSES_H) add_definitions(-DHAVE_CURSES_H) endif() -foreach(_I doscalls;msg;nls;quecalls;viocalls;kbdcalls;sesmgr) +foreach(_I doscalls;msg;nls;quecalls;viocalls;kbdcalls;sesmgr;som;pmwin;pmshapi;pmgpi;tcpip32) add_library(${_I} SHARED "native/${_I}.c") set_target_properties(${_I} PROPERTIES COMPILE_FLAGS "-m32") set_target_properties(${_I} PROPERTIES LINK_FLAGS "-m32 -ggdb3") diff --git a/native/os2.h b/native/os2.h index 3eba268..cf9dd56 100644 --- a/native/os2.h +++ b/native/os2.h @@ -15,6 +15,8 @@ #include "msg.h" #include "nls.h" #include "sesmgr.h" +#include "pmgpi.h" +#include "tcpip32.h" #endif diff --git a/native/os2native.h b/native/os2native.h index e0e886d..e6d9ff7 100644 --- a/native/os2native.h +++ b/native/os2native.h @@ -41,6 +41,7 @@ void OS2EXPORT lxNativeModuleDeinit(void); static const LxExport lx_native_exports[] = { #define LX_NATIVE_EXPORT(fn, ord) { ord, #fn, fn, NULL } +#define LX_NATIVE_EXPORT_DIFFERENT_NAME(fn, fnname, ord) { ord, fnname, fn, NULL } #define LX_NATIVE_MODULE_INIT_END() \ }; \ diff --git a/native/os2types.h b/native/os2types.h index 94a7e2e..128795c 100644 --- a/native/os2types.h +++ b/native/os2types.h @@ -37,6 +37,8 @@ typedef uint32_t APIRET; typedef uint16_t APIRET16; typedef uint32_t APIRET32; +typedef uint32_t BOOL; + typedef void VOID; typedef VOID *PVOID; typedef PVOID *PPVOID; @@ -64,6 +66,7 @@ typedef HANDLE HDIR, *PHDIR; typedef HANDLE HEV, *PHEV; typedef HANDLE HMTX, *PHMTX; typedef HANDLE HQUEUE, *PHQUEUE; +typedef HANDLE HPS, *PHPS; typedef HANDLE PID, *PPID; typedef HANDLE TID, *PTID; typedef SHANDLE HVIO, *PHVIO; diff --git a/native/pmgpi.c b/native/pmgpi.c new file mode 100644 index 0000000..0402ada --- /dev/null +++ b/native/pmgpi.c @@ -0,0 +1,16 @@ +#include "os2native.h" +#include "pmgpi.h" + +BOOL GpiQueryTextBox(HPS hps, LONG lCount1, PCH pchString, LONG lCount2, PPOINTL aptlPoints) +{ + TRACE_NATIVE("GpiQueryTextBox(%u, %d, '%s', %d, %p)", (unsigned int) hps, (int) lCount1, pchString, (int) lCount2, aptlPoints); + FIXME("write me"); + return 0; +} // GpiQueryTextBox + +LX_NATIVE_MODULE_INIT() + LX_NATIVE_EXPORT(GpiQueryTextBox, 489) +LX_NATIVE_MODULE_INIT_END() + +// end of pmgpi.c ... + diff --git a/native/pmgpi.h b/native/pmgpi.h new file mode 100644 index 0000000..5862ae0 --- /dev/null +++ b/native/pmgpi.h @@ -0,0 +1,25 @@ +#ifndef _INCL_PMGPI_H_ +#define _INCL_PMGPI_H_ + +#include "os2types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int32_t x; + int32_t y; +} POINTL, *PPOINTL; + +OS2EXPORT BOOL OS2API GpiQueryTextBox(HPS hps, LONG lCount1, PCH pchString, LONG lCount2, PPOINTL aptlPoints); + +#ifdef __cplusplus +} +#endif + +#endif + +// end of pmgpi.h ... + diff --git a/native/tcpip32.c b/native/tcpip32.c new file mode 100644 index 0000000..9f3e886 --- /dev/null +++ b/native/tcpip32.c @@ -0,0 +1,238 @@ +#include "os2native.h" +#include "tcpip32.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int OS2_sock_init(void) +{ + TRACE_NATIVE("sock_init()"); + return 1; // always succeeds. +} // OS2_sock_init + +static int mapOS2MsgFlags(const int os2flags) +{ + int bsdflags = 0; + + #define MAPSOCKFLAGS(f) if (os2flags & OS2_##f) { bsdflags |= f; } + MAPSOCKFLAGS(MSG_OOB); + MAPSOCKFLAGS(MSG_PEEK); + MAPSOCKFLAGS(MSG_DONTROUTE); + MAPSOCKFLAGS(MSG_EOR); + MAPSOCKFLAGS(MSG_TRUNC); + MAPSOCKFLAGS(MSG_CTRUNC); + MAPSOCKFLAGS(MSG_WAITALL); + MAPSOCKFLAGS(MSG_DONTWAIT); + #undef MAPSOCKFLAGS + + // !!! FIXME: no such flag on Linux + //MAPSOCKFLAGS(MSG_FULLREAD); + + return bsdflags; +} // mapOS2MsgFlags + +int OS2_recv(int sock, void *buf, size_t len, int os2flags) +{ + TRACE_NATIVE("recv(%d, %p, %d, %d)", sock, buf, (int) len, os2flags); + FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... + return recv(sock, buf, len, mapOS2MsgFlags(os2flags)); +} // OS2_recv + +int OS2_connect(int sock, const struct OS2_sockaddr *os2addr, int addrlen) +{ + TRACE_NATIVE("connect(%d, %p, %d)", sock, os2addr, addrlen); + + FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... + + if (os2addr->sa_family != OS2_AF_INET) { + FIXME("currently demands IPv4 socket"); + return -1; + } + + struct sockaddr_in bsdaddr; + memset(&bsdaddr, '\0', sizeof (bsdaddr)); + bsdaddr.sin_family = AF_INET; + bsdaddr.sin_port = ((const OS2_sockaddr_in *) os2addr)->sin_port; + bsdaddr.sin_addr.s_addr = ((const OS2_sockaddr_in *) os2addr)->sin_addr.s_addr; + return connect(sock, &bsdaddr, (socklen_t) sizeof (bsdaddr)); +} // OS2_connect + +int OS2_shutdown(int sock, int kind) +{ + TRACE_NATIVE("shutdown(%d, %d)", sock, kind); + FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... + return shutdown(sock, kind); +} // OS2_shutdown + +int OS2_socket(int os2family, int os2socktype, int protocol) +{ + TRACE_NATIVE("socket(%d, %d, %d)", os2family, os2socktype, protocol); + if (os2family != OS2_AF_INET) { + FIXME("currently demands IPv4 socket"); + return -1; + } + + if (protocol != 0) { + FIXME("Only protocol 0 supported at the moment"); + return -1; + } + + int bsdsocktype; + if (os2socktype == OS2_SOCK_STREAM) { + bsdsocktype = SOCK_STREAM; + } else if (os2socktype == OS2_SOCK_DGRAM) { + bsdsocktype = SOCK_DGRAM; + } else { + FIXME("Only SOCK_STREAM and SOCK_DGRAM supported at the moment"); + return -1; + } + + return socket(AF_INET, bsdsocktype, 0); +} // OS2_socket + +ssize_t OS2_send(int sock, const void *buf, size_t len, int os2flags) +{ + TRACE_NATIVE("send(%d, %p, %d, %d)", sock, buf, (int) len, os2flags); + FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... + return send(sock, buf, len, mapOS2MsgFlags(os2flags)); +} // OS2_send + +int OS2_soclose(int sock) +{ + TRACE_NATIVE("soclose(%d)", sock); + FIXME("this should fail if not a socket"); // otherwise you might close a file descriptor... + return close(sock); +} // OS2_soclose + +int OS2_sock_errno(void) +{ + TRACE_NATIVE("sock_errno()"); + FIXME("this should cache errno when an OS/2 socket function fails"); + return errno; +} // OS2_sock_errno + +unsigned long OS2_inet_addr(const char *name) +{ + TRACE_NATIVE("inet_addr('%s')", name); + return inet_addr(name); +} // OS2_inet_addr + +struct OS2_hostent *OS2_gethostbyname(const char *name) +{ + TRACE_NATIVE("gethostbyname('%s')", name); + struct hostent *hent = gethostbyname(name); + return (OS2_hostent *) hent; // these happen to match up between Linux and OS/2. +} // OS2_gethostbyname + +unsigned short OS2_htons(unsigned short val) +{ + TRACE_NATIVE("htons(%u)", (unsigned int) val); + return htons(val); +} // OS2_htons + +char *OS2_inet_ntoa(struct OS2_in_addr os2inaddr) +{ + TRACE_NATIVE("inet_ntoa(%u)", (unsigned int) os2inaddr.s_addr); + struct in_addr bsdaddr; + bsdaddr.s_addr = os2inaddr.s_addr; + return inet_ntoa(bsdaddr); +} // OS2_inet_ntoa + +struct OS2_servent *OS2_getservbyname(const char *name, const char *proto) +{ + TRACE_NATIVE("getservbyname('%s', '%s')", name, proto); + struct servent *sent = getservbyname(name, proto); + return (OS2_servent *) sent; // these happen to match up between Linux and OS/2. +} // OS2_getservbyname + +static void mapOS2FdSet(const OS2_fd_set *os2set, fd_set *bsdset) +{ + FD_ZERO(bsdset); + const int total = os2set->fd_count; + for (int i = 0; i < total; i++) { + FD_SET(os2set->fd_array[i], bsdset); + } +} // mapOS2FdSet + +int OS2_select(int ndfs, OS2_fd_set *os2readfds, OS2_fd_set *os2writefds, OS2_fd_set *os2errorfds, OS2_timeval *os2timeout) +{ + TRACE_NATIVE("select(%d, %p, %p, %p, %p)", ndfs, os2readfds, os2writefds, os2errorfds, os2timeout); + #define MAPFDS(t) \ + fd_set bsd##t##fds; \ + fd_set *t##fds = NULL; \ + if (os2##t##fds) { \ + t##fds = &bsd##t##fds; \ + mapOS2FdSet(os2##t##fds, t##fds); \ + } + MAPFDS(read); + MAPFDS(write); + MAPFDS(error); + #undef MAPFDS + + struct timeval bsdtv; + struct timeval *pbsdtv = NULL; + if (os2timeout) { + pbsdtv = &bsdtv; + bsdtv.tv_sec = os2timeout->tv_sec; + bsdtv.tv_usec = os2timeout->tv_usec; + } + const int rc = select(ndfs, readfds, writefds, errorfds, pbsdtv); + FIXME("fill in OS/2 fds"); + return rc; +} // OS2_select + +int OS2_os2_select(int *socks, int noreads, int nowrites, int noexcept, long timeout) +{ + TRACE_NATIVE("os2_select(%p, %d, %d, %d, %d)", socks, noreads, nowrites, noexcept, (int) timeout); + const int nfds = noreads + nowrites + noexcept; + struct pollfd *fds = (struct pollfd *) alloca(sizeof (struct pollfd) * nfds); + struct pollfd *origfds = fds; + for (int i = 0; i < noreads; i++) { + fds->fd = *(socks++); + fds->events = POLLIN; + fds++; + } + + for (int i = 0; i < nowrites; i++) { + fds->fd = *(socks++); + fds->events = POLLOUT; + fds++; + } + + for (int i = 0; i < noexcept; i++) { + fds->fd = *(socks++); + fds->events = POLLERR; + fds++; + } + + return poll(origfds, nfds, timeout * 1000); +} // OS2_os2_select + + +LX_NATIVE_MODULE_INIT() + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_connect, "connect", 3), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_recv, "recv", 10), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_os2_select, "os2_select", 12), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_send, "send", 13), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_socket, "socket", 16), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_soclose, "soclose", 17), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_sock_errno, "sock_errno", 20), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_shutdown, "shutdown", 25), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_sock_init, "sock_init", 26), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_select, "select", 32), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_inet_addr, "inet_addr", 105), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_inet_ntoa, "inet_ntoa", 110), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_gethostbyname, "gethostbyname", 111), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_getservbyname, "getservbyname",124), + LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_htons, "htons", 205) +LX_NATIVE_MODULE_INIT_END() + +// end of tcpip32.c ... + diff --git a/native/tcpip32.h b/native/tcpip32.h new file mode 100644 index 0000000..a9fb943 --- /dev/null +++ b/native/tcpip32.h @@ -0,0 +1,109 @@ +#ifndef _INCL_TCPIP32_H_ +#define _INCL_TCPIP32_H_ + +#include "os2types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// These are (mostly) the same symbols as BSD sockets, so to prevent conflicts +// with the _actual_ C runtime on the host, we name them OS2_*. The LX +// loader exports them with the correct names. If you're recompiling an +// OS/2 app and using this for API support, just use real BSD sockets +// instead. + +// !!! FIXME: lots of "int" and such in here that should probably be int32, etc. + +#define OS2_MSG_OOB 0x1 +#define OS2_MSG_PEEK 0x2 +#define OS2_MSG_DONTROUTE 0x4 +#define OS2_MSG_FULLREAD 0x8 +#define OS2_MSG_EOR 0x10 +#define OS2_MSG_TRUNC 0x20 +#define OS2_MSG_CTRUNC 0x40 +#define OS2_MSG_WAITALL 0x80 +#define OS2_MSG_DONTWAIT 0x100 + +#define OS2_AF_INET 2 + +#define OS2_SOCK_STREAM 1 +#define OS2_SOCK_DGRAM 2 + +#pragma pack(push, 1) +typedef struct OS2_sockaddr +{ + uint8 sa_len; + uint8 sa_family; + char sa_data[14]; +} OS2_sockaddr; + +typedef struct OS2_in_addr +{ + uint32 s_addr; +} OS2_in_addr; + +typedef struct OS2_sockaddr_in +{ + uint8 sin_len; + uint8 sin_family; + uint16 sin_port; + struct OS2_in_addr sin_addr; + char sin_zero[8]; +} OS2_sockaddr_in; + +typedef struct OS2_hostent +{ + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +} OS2_hostent; + +typedef struct OS2_servent +{ + char *s_name; + char **s_aliases; + int s_port; + char *s_proto; +} OS2_servent; + +#define OS2_FD_SETSIZE 64 +typedef struct OS2_fd_set +{ + uint16 fd_count; + uint16 padding; + int fd_array[OS2_FD_SETSIZE]; +} OS2_fd_set; + +typedef struct OS2_timeval +{ + sint32 tv_sec; + sint32 tv_usec; +} OS2_timeval; +#pragma pack(pop) + +OS2EXPORT int OS2API OS2_sock_init(void); +OS2EXPORT int OS2API OS2_recv(int sock, void *buf, size_t len, int os2flags); +OS2EXPORT int OS2API OS2_connect(int sock, const OS2_sockaddr *os2addr, int addrlen); +OS2EXPORT int OS2API OS2_shutdown(int sock, int kind); +OS2EXPORT int OS2API OS2_socket(int family, int os2socktype, int protocol); +OS2EXPORT ssize_t OS2API OS2_send(int sock, const void *buf, size_t len, int os2flags); +OS2EXPORT int OS2API OS2_soclose(int sock); +OS2EXPORT int OS2API OS2_sock_errno(void); +OS2EXPORT unsigned long OS2API OS2_inet_addr(const char *name); +OS2EXPORT OS2_hostent * OS2API OS2_gethostbyname(const char *name); +OS2EXPORT unsigned short OS2API OS2_htons(unsigned short val); +OS2EXPORT char * OS2API OS2_inet_ntoa(OS2_in_addr os2inaddr); +OS2EXPORT OS2_servent * OS2API OS2_getservbyname(const char *name, const char *proto); +OS2EXPORT int OS2API OS2_select(int sock, OS2_fd_set *readfds, OS2_fd_set *writefds, OS2_fd_set *errorfds, OS2_timeval *timeout); +OS2EXPORT int OS2API OS2_os2_select(int *socks, int noreads, int nowrites, int noexcept, long timeout); + +#ifdef __cplusplus +} +#endif + +#endif + +// end of tcpip32.h ...