diff --git a/Hercules_VS2008.vcproj b/Hercules_VS2008.vcproj index 4b4767002..aefdcfc5a 100644 --- a/Hercules_VS2008.vcproj +++ b/Hercules_VS2008.vcproj @@ -1131,6 +1131,10 @@ RelativePath=".\strsignal.c" > + + @@ -1163,6 +1167,10 @@ RelativePath=".\w32util.c" > + + @@ -1511,6 +1519,10 @@ RelativePath=".\targetver.h" > + + @@ -1535,6 +1547,10 @@ RelativePath=".\w32util.h" > + + + + diff --git a/Hercules_VS2015.vcxproj b/Hercules_VS2015.vcxproj index d9265f7f3..96da5fd18 100644 --- a/Hercules_VS2015.vcxproj +++ b/Hercules_VS2015.vcxproj @@ -444,6 +444,7 @@ + @@ -455,6 +456,7 @@ + @@ -692,6 +694,7 @@ + @@ -1111,6 +1114,7 @@ + @@ -1123,6 +1127,7 @@ + @@ -1374,4 +1379,4 @@ - \ No newline at end of file + diff --git a/Hercules_VS2015.vcxproj.filters b/Hercules_VS2015.vcxproj.filters index 3b627e678..d95e8cdb2 100644 --- a/Hercules_VS2015.vcxproj.filters +++ b/Hercules_VS2015.vcxproj.filters @@ -738,6 +738,9 @@ Source Files\Hercules\Emulation\Source Files + + Source Files\Hercules\Emulation\Source Files + Source Files\Hercules\Emulation\Source Files @@ -762,6 +765,9 @@ Source Files\Hercules\Emulation\Source Files + + Source Files\Hercules\Emulation\Source Files + Source Files\Hercules\Emulation\Source Files @@ -1001,6 +1007,9 @@ Other Files\DOC\README + + Other Files\DOC\README + Other Files\DOC\README @@ -2701,6 +2710,9 @@ Source Files\Hercules\Emulation\Header Files + + Source Files\Hercules\Emulation\Header Files + Source Files\Hercules\Emulation\Header Files @@ -2716,6 +2728,9 @@ Source Files\Hercules\Emulation\Header Files + + Source Files\Hercules\Emulation\Header Files + Source Files\Hercules\ExtPkgs\decNumber\include @@ -3481,4 +3496,4 @@ Resource Files - \ No newline at end of file + diff --git a/Hercules_VS2017.vcxproj b/Hercules_VS2017.vcxproj index 9966a93ce..f04b69f93 100644 --- a/Hercules_VS2017.vcxproj +++ b/Hercules_VS2017.vcxproj @@ -443,6 +443,7 @@ + @@ -455,6 +456,7 @@ + @@ -692,6 +694,7 @@ + @@ -1111,6 +1114,7 @@ + @@ -1123,6 +1127,7 @@ + @@ -1374,4 +1379,4 @@ - \ No newline at end of file + diff --git a/Hercules_VS2017.vcxproj.filters b/Hercules_VS2017.vcxproj.filters index 3b627e678..d95e8cdb2 100644 --- a/Hercules_VS2017.vcxproj.filters +++ b/Hercules_VS2017.vcxproj.filters @@ -738,6 +738,9 @@ Source Files\Hercules\Emulation\Source Files + + Source Files\Hercules\Emulation\Source Files + Source Files\Hercules\Emulation\Source Files @@ -762,6 +765,9 @@ Source Files\Hercules\Emulation\Source Files + + Source Files\Hercules\Emulation\Source Files + Source Files\Hercules\Emulation\Source Files @@ -1001,6 +1007,9 @@ Other Files\DOC\README + + Other Files\DOC\README + Other Files\DOC\README @@ -2701,6 +2710,9 @@ Source Files\Hercules\Emulation\Header Files + + Source Files\Hercules\Emulation\Header Files + Source Files\Hercules\Emulation\Header Files @@ -2716,6 +2728,9 @@ Source Files\Hercules\Emulation\Header Files + + Source Files\Hercules\Emulation\Header Files + Source Files\Hercules\ExtPkgs\decNumber\include @@ -3481,4 +3496,4 @@ Resource Files - \ No newline at end of file + diff --git a/Makefile.am b/Makefile.am index 9ad4f5e08..177d12efc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -472,12 +472,14 @@ libherc_la_SOURCES = \ sr.c \ stack.c \ strsignal.c \ + tcpip.c \ timer.c \ trace.c \ transact.c \ vector.c \ vm.c \ vmd250.c \ + x75.c \ xstore.c \ $(DYNSRC) @@ -797,6 +799,7 @@ EXTRA_DIST = \ README.SOFTFLOAT \ README.SUN \ README.TAPE \ + README.TCPIP \ README.VMFPLC2 \ README.TELNET \ README.WIN64 \ @@ -929,6 +932,7 @@ noinst_HEADERS = \ stfl.h \ tapedev.h \ targetver.h \ + tcpip.h \ tt32api.h \ tt32if.h \ tuntap.h \ @@ -940,6 +944,7 @@ noinst_HEADERS = \ w32mtio.h \ w32stape.h \ w32util.h \ + x75.h \ zfcp.h ############################################################################### diff --git a/Makefile.in b/Makefile.in index 28603e719..da09abf99 100644 --- a/Makefile.in +++ b/Makefile.in @@ -218,8 +218,8 @@ am_libherc_la_OBJECTS = _archdep_templ.lo archlvl.lo assist.lo \ httpserv.lo ieee.lo impl.lo io.lo ipl.lo loadmem.lo \ loadparm.lo losc.lo machchk.lo opcode.lo panel.lo pfpo.lo \ plo.lo qdio.lo scedasd.lo scescsi.lo script.lo service.lo \ - sie.lo sr.lo stack.lo strsignal.lo timer.lo trace.lo \ - transact.lo vector.lo vm.lo vmd250.lo xstore.lo \ + sie.lo sr.lo stack.lo strsignal.lo tcpip.lo timer.lo trace.lo \ + transact.lo vector.lo vm.lo vmd250.lo x75.lo xstore.lo \ $(am__objects_1) libherc_la_OBJECTS = $(am_libherc_la_OBJECTS) libherc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -1103,12 +1103,14 @@ libherc_la_SOURCES = \ sr.c \ stack.c \ strsignal.c \ + tcpip.c \ timer.c \ trace.c \ transact.c \ vector.c \ vm.c \ vmd250.c \ + x75.c \ xstore.c \ $(DYNSRC) @@ -1387,6 +1389,7 @@ EXTRA_DIST = \ README.SOFTFLOAT \ README.SUN \ README.TAPE \ + README.TCPIP \ README.VMFPLC2 \ README.TELNET \ README.WIN64 \ @@ -1519,6 +1522,7 @@ noinst_HEADERS = \ stfl.h \ tapedev.h \ targetver.h \ + tcpip.h \ tt32api.h \ tt32if.h \ tuntap.h \ @@ -1530,6 +1534,7 @@ noinst_HEADERS = \ w32mtio.h \ w32stape.h \ w32util.h \ + x75.h \ zfcp.h all: config.h @@ -2019,6 +2024,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapedev.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapesplt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpip.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transact.Plo@am__quote@ @@ -2028,6 +2034,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmd250.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmfplc2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x75.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xstore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zfcp.Plo@am__quote@ diff --git a/README.TCPIP b/README.TCPIP new file mode 100644 index 000000000..e26a19ff0 --- /dev/null +++ b/README.TCPIP @@ -0,0 +1,94 @@ +Guest Access To Host IP Stack - The TCPIP (X'75') Instruction ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +Introduction +============ + +Around 2002 Jason Winter developed a Hercules extension allowing the guest OS to access the +IP stack of the host OS by means of a special instruction that does not exist on real +S/3x0, ESA/390 or z/Architecture hardware. The operation is in RX format, its operation +code is X'75': + +75rxbddd - TCPIP R1,D2(X2,B2) R1=GPR 0-15, B2=GPR 5-13, X2=GPR 0,5-13 + +As opposed to "classic" instructions the TCPIP (X'75') instruction preserves a state +between calls, an essential requirement to transfer IP traffic back and forth between the +host and the guest. Due to this fact, setting up for native execution of the instruction is +complex. + +To avoid having application programmers go through this complexity, at the time of this +writing two higher-level interfaces are available, allowing easy and standardized access to +the functionality provided by the TCPIP instruction: + +- A socket API in Jason's JCC-Library, which provides the well-known C socket + programming functions. See the JCC-Library help in the JCC distribution (found in + TK4-.JASON.JCC.ZIP on TK4- systems) for a description of the functions available. + +- TCP/IP for MVS 3.8 Assembler by Shelby Beach, a programming interface that is source + code compatible to IBM's well-known EZASMI API. A comprehensive documentation of all + available functions is part of the installer found at TK4-.SHELBY.EZASMI.V100.ZIP on + TK4- systems. + +Caution: The TCPIP instruction gives a guest program the very same access to the host's IP +-------- stack that the host process running the Hercules instance has. Allowing every + guest program this type of access may be undesirable, particularly when the + Hercules process runs using elevated privileges. In addition, one guest program + can easily interfere with IP communications of any other guest program by + hijacking the other program's socket identifiers. In sum, a malicious user with + access to the TCPIP instruction can severely compromise the guest's and the + host's integrity. A problem state instruction with this type of capabilities + clearly does not comply with parts specifications of the architectures emulated + by Hercules. + + To allow users to overcome these weaknesses of the TCPIP instruction, its + implementation on SDL Hyperion comes in two flavors: As a supervisor state and as + a problem state instruction, both of which are functionality wise identical. + Enabling the TCPIP instruction will default to the supervisor state instruction. + That way, only programs running in supervisor state can execute the instruction, + which is considered being compliant with the emulated architectures. + + Note that both TCPIP APIs currently existing for S/370 operating systems (C + socket library and EZASMI) rely on the instruction being available in problem + state, which is not architecture compliant. Using the problem state flavor of the + instruction is at the user's sole risk. + + Note also, that currently no software exists that would be able to make use of + the supervisor state flavor of the TCPIP instruction in a controlled way. + + +Usage +===== + +Availability and flavor of the TCPIP instruction are controlled by three elements: + +1. The compile time FEATURE_TCPIP_EXTENSION definition: To allow enabling of the TCPIP + instruction, the featxxx.h header file corresponding to the relevant architecture(s) + must contain the statement + + #define FEATURE_TCPIP_EXTENSION + + As shipped, SDL Hyperion has this feature defined for the S/370 architecture + (feat370.h) only. + +2. By default, the TCPIP instruction is at run time disabled, regardless whether the + compile time FEATURE_TCPIP_EXTENSION was defined or not. If FEATURE_TCPIP_EXTENSION + was defined for the architecture being currently in use, the supervisor state flavor + of the TCPIP instruction can be enabled by issuing the command + + facility enable HERC_TCPIP_EXTENSION + + before IPLing the operating system. + +3. If the problem state flavor of the TCPIP instruction is desired, after having + enabled the supervisor state flavor as described above, the command + + facility enable HERC_TCPIP_PROB_STATE + + must be issued before IPLing the operating system. + + +Copyright +========= + +See the comment headers of the x75.c and tcpip.c programs for copyright information. diff --git a/facility.c b/facility.c index 8f44649d0..278fdabcd 100644 --- a/facility.c +++ b/facility.c @@ -605,6 +605,11 @@ FT( Z390, Z390, NONE, HERC_SVS ) FT( MALL, NONE, NONE, HERC_VIRTUAL_MACHINE ) #endif +#if defined( FEATURE_TCPIP_EXTENSION ) +FT( MALL, NONE, NONE, HERC_TCPIP_EXTENSION ) +FT( MALL, NONE, NONE, HERC_TCPIP_PROB_STATE ) +#endif + }; /*-------------------------------------------------------------------*/ @@ -722,6 +727,7 @@ static void instr146 ( int arch, bool enable ); static void hercmvcin( int arch, bool enable ); static void hercsvs ( int arch, bool enable ); static void herc37X ( int arch, bool enable ); +static void herctcp ( int arch, bool enable ); /*-------------------------------------------------------------------*/ /* The ACTUAL facilities table, initialized by init_facilities_lists */ @@ -841,6 +847,8 @@ FT2( NULL, NULL, HERC_QEBSM, "Hercules QDIO Enhanced B FT2( NULL, NULL, HERC_SIGP_SETARCH_S370, "Hercules SIGP Set Architecture S/370 Support" ) FT2( NULL, hercsvs, HERC_SVS, "Hercules SVS Set Vector Summary Instruction Support" ) FT2( NULL, NULL, HERC_VIRTUAL_MACHINE, "Hercules Emulate Virtual Machine Support" ) +FT2( NULL, herctcp, HERC_TCPIP_EXTENSION, "Hercules Access Host TCP/IP Stack Through X'75' Instruction" ) +FT2( NULL, NULL, HERC_TCPIP_PROB_STATE, "Hercules Enable X'75' As Problem State Instruction" ) }; /*-------------------------------------------------------------------*/ @@ -3167,6 +3175,14 @@ BEG_DIS_FAC_INS_FUNC( herc37X ) } END_DIS_FAC_INS_FUNC() +/*-------------------------------------------------------------------*/ + +BEG_DIS_FAC_INS_FUNC( herctcp ) +{ + DIS_FAC_INS( 75, "TCPIP 75 TCPIP" ); +} +END_DIS_FAC_INS_FUNC() + /*-------------------------------------------------------------------*/ /* Special handling for HERC_370_EXTENSION Pseudo-Facility */ /*-------------------------------------------------------------------*/ diff --git a/feat370.h b/feat370.h index 85f1e6d68..c7ba7ed9b 100644 --- a/feat370.h +++ b/feat370.h @@ -47,6 +47,7 @@ #define FEATURE_SEGMENT_PROTECTION #define FEATURE_TEST_BLOCK #define FEATURE_VM_BLOCKIO +#define FEATURE_TCPIP_EXTENSION /*-------------------------------------------------------------------*/ /* "Hercules S/370 Instruction Extension Facility" */ diff --git a/featall.h b/featall.h index 6e0677611..490ef5bfa 100644 --- a/featall.h +++ b/featall.h @@ -328,5 +328,6 @@ #undef FEATURE_VIRTUAL_ARCHITECTURE_LEVEL #undef FEATURE_VM_BLOCKIO #undef FEATURE_WAITSTATE_ASSIST +#undef FEATURE_TCPIP_EXTENSION /* end of FEATALL.H */ diff --git a/featchk.h b/featchk.h index e55345f08..0dcb2ceab 100644 --- a/featchk.h +++ b/featchk.h @@ -547,6 +547,10 @@ #define _FEATURE_WAITSTATE_ASSIST #endif +#if defined( FEATURE_TCPIP_EXTENSION ) + #define _FEATURE_TCPIP_EXTENSION +#endif + /*-------------------------------------------------------------------*/ /* PROGRAMMING NOTE */ /*-------------------------------------------------------------------*/ diff --git a/msvc.makefile.includes/OBJ_CODE.msvc b/msvc.makefile.includes/OBJ_CODE.msvc index b48abf30d..1931b870c 100644 --- a/msvc.makefile.includes/OBJ_CODE.msvc +++ b/msvc.makefile.includes/OBJ_CODE.msvc @@ -140,10 +140,12 @@ hengine_OBJ = \ $(O)sie.obj \ $(O)sr.obj \ $(O)stack.obj \ + $(O)tcpip.obj \ $(O)timer.obj \ $(O)trace.obj \ $(O)transact.obj \ $(O)vector.obj \ $(O)vm.obj \ $(O)vmd250.obj \ + $(O)x75.obj \ $(O)xstore.obj diff --git a/opcode.c b/opcode.c index 8fc05d1c3..d71ec1f4c 100644 --- a/opcode.c +++ b/opcode.c @@ -1235,6 +1235,10 @@ DISABLE_GCC_UNUSED_FUNCTION_WARNING; UNDEF_INST( set_vector_summary ) #endif +#if !defined( FEATURE_TCPIP_EXTENSION ) + UNDEF_INST( tcpip ) +#endif + /*----------------------------------------------------------------------------*/ /* The following execute_xxxx routines can be optimized by the compiler to */ /* an indexed jump, leaving the stack frame untouched as the called routine */ @@ -2059,7 +2063,7 @@ static INSTR_FUNC opcode_table[256][NUM_INSTR_TAB_PTRS] = /*72*/ GENx___x___x___ , /*73*/ GENx___x___x___ , /*74*/ GENx___x___x___ , - /*75*/ GENx___x___x___ , + /*75*/ GENx370x390x900 (tcpip,RX,"TCPIP"), /*76*/ GENx___x___x___ , /*77*/ GENx___x___x___ , /*78*/ GENx370x390x900 (load_float_short,RX,"LE"), diff --git a/opcode.h b/opcode.h index f2ea7efa7..4792e3cef 100644 --- a/opcode.h +++ b/opcode.h @@ -4475,6 +4475,10 @@ DEF_INST( search_string ); DEF_INST( branch_in_subspace_group ); #endif +#if defined( FEATURE_TCPIP_EXTENSION ) +DEF_INST( tcpip ); +#endif + /*-------------------------------------------------------------------*/ /* Instructions NOT associated with ANY facility or feature */ /*-------------------------------------------------------------------*/ diff --git a/stfl.h b/stfl.h index 9e647bebc..76dab6200 100644 --- a/stfl.h +++ b/stfl.h @@ -337,8 +337,10 @@ #define STFL_HERC_SIGP_SETARCH_S370 ( STFL_HERC_FIRST_BIT + 13 ) #define STFL_HERC_SVS ( STFL_HERC_FIRST_BIT + 14 ) #define STFL_HERC_VIRTUAL_MACHINE ( STFL_HERC_FIRST_BIT + 15 ) +#define STFL_HERC_TCPIP_EXTENSION ( STFL_HERC_FIRST_BIT + 16 ) +#define STFL_HERC_TCPIP_PROB_STATE ( STFL_HERC_FIRST_BIT + 17 ) -#define STFL_HERC_LAST_BIT ( STFL_HERC_FIRST_BIT + 15 ) +#define STFL_HERC_LAST_BIT ( STFL_HERC_FIRST_BIT + 17 ) #define STFL_HERC_BY_SIZE (ROUND_UP( STFL_HERC_LAST_BIT, 8 ) / 8) #define STFL_HERC_DW_SIZE (ROUND_UP( STFL_HERC_BY_SIZE, sizeof( DW )) / sizeof( DW )) diff --git a/tcpip.c b/tcpip.c new file mode 100644 index 000000000..dfec5738a --- /dev/null +++ b/tcpip.c @@ -0,0 +1,1038 @@ +/*-------------------------------------------------------------------*/ +/* TCPIP.C (C) Copyright Jason Paul Winter, 2003,2010 */ +/* Minor adaptions for SDL Hyperion, Juergen Winkelmann 2019 */ +/* */ +/* C Socket Interface for the Hercules System/370, ESA/390, */ +/* ------------------ and z/Architecture Emulator */ +/* */ +/* This program was written by Jason Paul Winter. */ +/* */ +/* Copyright (c) 2003-2010, Jason Paul Winter */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with */ +/* or without modification, are permitted provided that */ +/* the following conditions are met: */ +/* */ +/* Redistributions of source code must retain the above */ +/* copyright notice, this list of conditions and the */ +/* following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */ +/* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */ +/* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR */ +/* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS */ +/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ +/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ +/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH */ +/* DAMAGE. */ +/* */ +/*-------------------------------------------------------------------*/ +/* This module implements the backend to the TCPIP instruction by */ +/* mapping calls from the guest's socket library (EZASOKET or */ +/* equivalent) to native socket calls on the host. */ +/*-------------------------------------------------------------------*/ + +#include "hstdinc.h" + +#define _TCPIP_C_ +#define _HENGINE_DLL_ + +#include "hercules.h" +#include "opcode.h" +#include "inline.h" + +#include "tcpip.h" + +static u_int find_slot ( ULONG_PTR address ) { + u_int i; + i = 0; + obtain_lock (&tcpip_lock); + while ((((signed) map32[i]) != -1) && (i < Ccom-1)) i++; + map32[i] = address; + release_lock (&tcpip_lock); + return (i); +} + +static void tcpip_init () { + u_int i; + + initialize_lock(&tcpip_lock); + + CerrGen = 0; + + i = 0; + while (i < Ccom) { + map32[i] = -1; + + Cselect [i] = NULL; + + Cerr [i] = 0; + Ccom_blk [i] = 1; + Ccom_han [i] = -1; + Ccom_opn [i++] = 0; + } +} + +/* This is the error translation routine for whatever host to Hercules: */ +static int Get_errno () { + u_int i; + +#ifndef _MSVC_ + i = errno; +#else + i = WSAGetLastError (); +#endif + + switch (i) { + case fEMFILE: + return (hEMFILE); +/* case EAGAIN: + return (hEAGAIN); SAME AS EWOULDBLOCK*/ + case EWOULDBLOCK: + return (hEWOULDBLOCK); + case EINPROGRESS: + return (hEINPROGRESS); + case EALREADY: + return (hEALREADY); + case ENOTSOCK: + return (hENOTSOCK); + case EDESTADDRREQ: + return (hEDESTADDRREQ); + case EMSGSIZE: + return (hEMSGSIZE); + case EPROTOTYPE: + return (hEPROTOTYPE); + case ENOPROTOOPT: + return (hENOPROTOOPT); + case EPROTONOSUPPORT: + return (hEPROTONOSUPPORT); + case ESOCKTNOSUPPORT: + return (hESOCKTNOSUPPORT); + case EOPNOTSUPP: + return (hEOPNOTSUPP); + case EPFNOSUPPORT: + return (hEPFNOSUPPORT); + case EAFNOSUPPORT: + return (hEAFNOSUPPORT); + case EADDRINUSE: + return (hEADDRINUSE); + case EADDRNOTAVAIL: + return (hEADDRNOTAVAIL); + case ENETDOWN: + return (hENETDOWN); + case ENETUNREACH: + return (hENETUNREACH); + case ENETRESET: + return (hENETRESET); + case ECONNABORTED: + return (hECONNABORTED); + case ECONNRESET: + return (hECONNRESET); + case ENOBUFS: + return (hENOBUFS); + case EISCONN: + return (hEISCONN); + case ENOTCONN: + return (hENOTCONN); + case ESHUTDOWN: + return (hESHUTDOWN); + case ETOOMANYREFS: + return (hETOOMANYREFS); + case ETIMEDOUT: + return (hETIMEDOUT); + case ECONNREFUSED: + return (hECONNREFUSED); + case fEINVAL : + return (hEINVAL); + case ELOOP : + return (hELOOP); + case fENAMETOOLONG : + return (hENAMETOOLONG); + case EHOSTDOWN : + return (hEHOSTDOWN); + case EHOSTUNREACH : + return (hEHOSTUNREACH); + case fENOTEMPTY : + return (hENOTEMPTY); +#ifdef EPROCLIM // Some *nixs don't have this error + case EPROCLIM : + return (hEPROCLIM); +#endif + case EUSERS : + return (hEUSERS); + case EDQUOT : + return (hEDQUOT); + case ESTALE : + return (hESTALE); + case EREMOTE : + return (hEREMOTE); + } + + return (i); +} + +/**********************************************************************************/ + +#if defined(WORDS_BIGENDIAN) + +/* + regs comming in: (Non Intel Format - msb first.) + /--R0--\ /--R1--\ + 00000000 xxxxxxxx 00000000 yyyyyyyy ... + (Zeros are the 64bit register parts, never used in S370.) +*/ + +static void set_reg (u_int * regs, u_int r, u_int v) { + regs [(r * 2) + 1] = v; +} + +static u_int get_reg (u_int * regs, u_int r) { + return (regs [(r * 2) + 1]); +} + +#else + +/* + regs comming in: (Intel Format - lsb first.) + /--R0--\ /--R1--\ + xxxxxxxx 00000000 yyyyyyyy 00000000 ... + (Zeros are the 64bit register parts, never used in S370.) +*/ + +static void set_reg (u_int * regs, u_int r, u_int v) { + regs [r * 2] = v; +} + +static u_int get_reg (u_int * regs, u_int r) { + return (regs [r * 2]); +} + +#endif + +/**********************************************************************************/ + +static u_int check_not_sock (u_int s, talk_ptr t) { + + if ((s < 1) || (s >= Ccom)) { + t->ret_cd = -1; + return (1); + } + + if (Ccom_han [s] == -1) { + t->ret_cd = -1; + return (1); + } + + return (0); +} + +static void EZASOKET (u_int func, int aux1, int aux2, talk_ptr t) { + int i; + socklen_t isock; + int k; + int l; + int m; + int size; + struct hostent * hp; + struct timeval timeout; + fd_set sockets; + SOCKADDR_IN Clocal_adx; + SOCKADDR Slocal_adx; + + switch (func & 0xFF) { + case 1: /* INITAPI */ + + t->ret_cd = 0; + return; + + case 2: /* GETERRORS */ + + if (check_not_sock (aux1, t)) { + t->ret_cd = hENOTSOCK; + return; + } + + t->ret_cd = Cerr [aux1]; + return; + + case 3: /* GETERROR */ + + t->ret_cd = CerrGen; + return; + + case 4: /* GETHOSTBYNAME */ + + m = strlen (t->buffer_in); + k = 0; + while (m) { + t->buffer_in [k] = DCCebcdic_to_ascii [(unsigned char)(t->buffer_in [k])]; + if ((unsigned char)t->buffer_in [k] == 0x20) {t->buffer_in [k] = 0; break;}; + k++; + m--; + } + + if ((hp = gethostbyname (t->buffer_in)) == NULL) { + + CerrGen = Get_errno (); + + t->ret_cd = 0; + return; + } else { + if (hp->h_addr_list [0] == NULL) { + t->ret_cd = 0; + return; + } else { + t->ret_cd = (ntohl(((u_int *)(hp->h_addr_list [0])) [0])); + return; + } + } + + case 5: /* SOCKET */ + + obtain_lock (&tcpip_lock); + + m = 1; + while (m < Ccom) { + if (Ccom_opn [m] == 0) break; + m++; + } + if (m == Ccom) { + + CerrGen = hEMFILE; + + release_lock (&tcpip_lock); + + t->ret_cd = -1; + return; /* None available. */ + } + + i = aux1 >> 16; /* Family: eg. PF_INET */ + + if ((Ccom_han [m] = socket (i, (aux1 & 0xFFFF), aux2)) == INVALID_SOCKET) { + + CerrGen = Get_errno (); + + release_lock (&tcpip_lock); + + t->ret_cd = -1; + return; /* ERROR */ + } + + Ccom_opn [m] = 1; + + release_lock (&tcpip_lock); + + t->ret_cd = m; + return; + + case 6: /* BIND */ + + /* FUNC:SOCK&FUNC, AUX1:ADDRESS, AUX2:FAMILY&PORT */ + + m = func >> 16; /* SOCKET # */ + i = aux2 >> 16; /* Family */ + + if (check_not_sock (m, t)) return; + +#if defined(__APPLE__) + bzero ((LPSOCKADDR)&Clocal_adx, sizeof (Clocal_adx)); /* cleanup address */ +#endif + + /* set up socket */ + Clocal_adx.sin_family = (short)(i & 0xFF); + + Clocal_adx.sin_addr.s_addr = htonl (aux1); + + Clocal_adx.sin_port = htons ((unsigned short)(aux2 & 0xFFFF)); + + if (bind (Ccom_han [m], (LPSOCKADDR)&Clocal_adx, sizeof (Clocal_adx))) { + + Cerr [m] = Get_errno (); + + t->ret_cd = -1; + return; /* ERROR */ + } + + t->ret_cd = 0; + return; + + case 7: /* CONNECT */ + + m = func >> 16; /* SOCKET # */ + i = aux2 >> 16; /* Family */ + + if (check_not_sock (m, t)) return; + + /* set up socket */ + Clocal_adx.sin_family = (short)(i & 0xFF); + + Clocal_adx.sin_addr.s_addr = htonl (aux1); + + Clocal_adx.sin_port = htons ((unsigned short)(aux2 & 0xFFFF)); + + k = 1; + ioctlsocket (Ccom_han [m], FIONBIO, &k); + + i = connect (Ccom_han [m], (LPSOCKADDR)&Clocal_adx, sizeof (Clocal_adx)); + Cerr [m] = Get_errno (); + + k = 0; + ioctlsocket (Ccom_han [m], FIONBIO, &k); + + if (i == -1) { + + switch (Cerr [m]) { + case hEISCONN : + t->ret_cd = 0; /* Worked! */ + return; + + case hEINVAL : /* WSAEALREADY in Windows old sockets */ + case hEALREADY : + case hEWOULDBLOCK : + case hEINPROGRESS : + + if (Ccom_blk [m] == 0) { + t->ret_cd = -1; + return; /* ERROR, But Client Knows... */ + } + + t->ret_cd = -2; /* Must wait. */ + return; + } + + t->ret_cd = -1; + return; /* ERROR */ + } + + t->ret_cd = 0; + return; + + case 8: /* LISTEN */ + + if (check_not_sock (aux1, t)) return; + + i = aux2; + if (i == 0) i = SOMAXCONN; + + if (listen (Ccom_han [aux1], i)) { + + Cerr [aux1] = Get_errno (); + + t->ret_cd = -1; + return; /* ERROR */ + } + + t->ret_cd = 0; + return; + + case 9: /* ACCEPT */ + + if (check_not_sock (aux1, t)) return; + + obtain_lock (&tcpip_lock); + + m = 1; + while (m < Ccom) { + if (Ccom_opn [m] == 0) break; + m++; + } + + if (m == Ccom) { + + Cerr [aux1] = hEMFILE; + + release_lock (&tcpip_lock); + + t->ret_cd = -1; + return; /* None available. */ + } + + isock = sizeof (Slocal_adx); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&sockets); + FD_SET (Ccom_han [aux1], &sockets); + + if (select (Ccom_han [aux1] + 1, &sockets, NULL, NULL, &timeout) == 0) { + + release_lock (&tcpip_lock); + + if (Ccom_blk [aux1]) { + t->ret_cd = -2; + } else { + Cerr [aux1] = hEWOULDBLOCK; + t->ret_cd = -1; + } + return; + } + + l = Ccom_han [m] = accept (Ccom_han [aux1], &Slocal_adx, &isock); + + if (l == INVALID_SOCKET) { + + Cerr [aux1] = Get_errno (); + + release_lock (&tcpip_lock); + + t->ret_cd = -1; + return; /* ERROR */ + } + + Ccom_opn [m] = 1; + + release_lock (&tcpip_lock); + + t->len_out = sizeof (Clocal_adx); + t->buffer_out = (char *)malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + memcpy (t->buffer_out, &Slocal_adx, t->len_out); + ((SOCKADDR_IN *)(t->buffer_out))->sin_family = htons (((SOCKADDR_IN *)(t->buffer_out))->sin_family); + + t->ret_cd = m; + return; + + case 10: /* SEND */ + + if (check_not_sock (aux1, t)) return; + + if ((l = send (Ccom_han [aux1], t->buffer_in, t->len_in, 0)) == SOCKET_ERROR) { + + Cerr [aux1] = Get_errno (); + + t->ret_cd = -1; + return; + } + + t->ret_cd = l; + return; + + case 11: /* RECV */ + + if (check_not_sock (aux1, t)) return; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&sockets); + FD_SET (Ccom_han [aux1], &sockets); + + if (select (Ccom_han [aux1] + 1, &sockets, NULL, NULL, &timeout) == 0) { + + if (Ccom_blk [aux1]) { + t->ret_cd = -2; + } else { + Cerr [aux1] = hEWOULDBLOCK; + t->ret_cd = -1; + } + return; + } + + t->buffer_out = (char *)malloc (aux2); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + + if ((size = recv (Ccom_han [aux1], t->buffer_out, aux2, 0)) == SOCKET_ERROR) { /* receive command */ + + Cerr [aux1] = Get_errno (); + + t->len_out = 0; + map32[t->buffer_out_slot] = -1; + free (t->buffer_out); + t->buffer_out = NULL; + + t->ret_cd = -1; + return; + } + + t->len_out = size; + t->ret_cd = size; + return; + + case 12: /* CLOSE */ + + if ((aux1 > 0) && (aux1 < Ccom)) { + /* close connection */ + if (Ccom_opn [aux1]) + closesocket (Ccom_han [aux1]); + + Ccom_opn [aux1] = 0; + Ccom_han [aux1] = -1; + Ccom_blk [aux1] = 1; + } + + t->ret_cd = 0; + return; + + case 13: /* EBCDIC2ASCII */ + + t->len_out = t->len_in; + t->buffer_out = (char *)malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + + m = t->len_out; + i = 0; + k = 0; + while (m) { + t->buffer_out [k++] = DCCebcdic_to_ascii [(unsigned char)(t->buffer_in [i++])]; + m--; + } + + t->ret_cd = t->len_out; + return; + + case 14: /* ASCII2EBCDIC */ + + t->len_out = t->len_in; + t->buffer_out = (char *)malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + + m = t->len_out; + i = 0; + k = 0; + while (m) { + t->buffer_out [k++] = DCCascii_to_ebcdic [(unsigned char)(t->buffer_in [i++])]; + m--; + } + + t->ret_cd = t->len_out; + return; + + case 15: /* IOCTL */ + + m = func >> 16; + + if (check_not_sock (m, t)) return; + + if (aux1 == 1) { + + if (aux2) { + Ccom_blk [m] = 0; /* No longer blocking */ + } else { + Ccom_blk [m] = 1; + } + + t->ret_cd = 0; + + } else { + + i = ioctlsocket (Ccom_han [m], FIONREAD, &(t->ret_cd)); + if (i == -1) { + t->ret_cd = -1; + Cerr [m] = Get_errno (); + } + } + + return; + + case 16: /* GETSOCKNAME */ + + if (check_not_sock (aux1, t)) return; + + t->len_out = sizeof (Clocal_adx); + t->buffer_out = (char *)malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + + isock = t->len_out; + t->ret_cd = getsockname (Ccom_han [aux1], (struct sockaddr *)(t->buffer_out), &isock); + + if (t->ret_cd == -1) { + Cerr [aux1] = Get_errno (); + } else { + ((SOCKADDR_IN *)(t->buffer_out))->sin_family = htons (((SOCKADDR_IN *)(t->buffer_out))->sin_family); + } + + return; + + case 17: /* SELECT */ + + /* func>>16 = socket + aux1 = func subcode + aux2 = maxsock+1 */ + + m = func >> 16; + + if (check_not_sock (m, t)) return; + + switch (aux1 & 0xFF) { + case 0: /* Start */ + if (Cselect [m] == NULL) { /* Start-part */ + + Cselect [m] = malloc (sizeof (selects)); + + Cselect [m]->ri = malloc (sizeof (fd_set)); + Cselect [m]->wi = malloc (sizeof (fd_set)); + Cselect [m]->ei = malloc (sizeof (fd_set)); + + Cselect [m]->ro = malloc (sizeof (fd_set)); + Cselect [m]->wo = malloc (sizeof (fd_set)); + Cselect [m]->eo = malloc (sizeof (fd_set)); + } + + FD_ZERO ((fd_set *)(Cselect [m]->ri)); + FD_ZERO ((fd_set *)(Cselect [m]->wi)); + FD_ZERO ((fd_set *)(Cselect [m]->ei)); + + Cselect [m]->len = 0; + Cselect [m]->invalid = 0; + + t->ret_cd = 0; + return; + + case 1: /* Read Inputs */ + + Cselect [m]->len = t->len_in; /* Copy every time... */ + + /* Need to bswap every long in the incoming array... */ + i = t->len_in / 4; + while (i) { + i--; + ((u_int *)t->buffer_in) [i] = htonl (((u_int *)t->buffer_in) [i]); + } + + i = 0; + while (i < aux2) { + if (hercFD_ISSET (i, (hercfd_set *)(t->buffer_in))) { + if (Ccom_han [i] == -1) { + Cselect [m]->invalid = 1; + } else { + FD_SET (Ccom_han [i], (fd_set *)(Cselect [m]->ri)); + } + } + i++; + } + + t->ret_cd = 0; + return; + + case 2: /* Write Inputs */ + + Cselect [m]->len = t->len_in; /* Copy every time... */ + + /* Need to bswap every long in the incoming array... */ + i = t->len_in / 4; + while (i) { + i--; + ((u_int *)t->buffer_in) [i] = htonl (((u_int *)t->buffer_in) [i]); + } + + i = 0; + while (i < aux2) { + if (hercFD_ISSET (i, (hercfd_set *)(t->buffer_in))) { + if (Ccom_han [i] == -1) { + Cselect [m]->invalid = 1; + } else { + FD_SET (Ccom_han [i], (fd_set *)(Cselect [m]->wi)); + } + } + i++; + } + + t->ret_cd = 0; + return; + + case 3: /* Exception Inputs */ + + Cselect [m]->len = t->len_in; /* Copy every time... */ + + /* Need to bswap every long in the incoming array... */ + i = t->len_in / 4; + while (i) { + i--; + ((u_int *)t->buffer_in) [i] = htonl (((u_int *)t->buffer_in) [i]); + } + + i = 0; + while (i < aux2) { + if (hercFD_ISSET (i, (hercfd_set *)(t->buffer_in))) { + if (Ccom_han [i] == -1) { + Cselect [m]->invalid = 1; + } else { + FD_SET (Ccom_han [i], (fd_set *)(Cselect [m]->ei)); + } + } + i++; + } + + t->ret_cd = 0; + return; + + case 4: /* Run 'select' (never blocking here, so may loop back.) */ + + memcpy (Cselect [m]->ro, Cselect [m]->ri, sizeof (fd_set)); + memcpy (Cselect [m]->wo, Cselect [m]->wi, sizeof (fd_set)); + memcpy (Cselect [m]->eo, Cselect [m]->ei, sizeof (fd_set)); + + if (Cselect [m]->invalid) { + Cerr [m] = hENOTSOCK; + t->ret_cd = -1; + return; + } + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + i = select (Ccom_han [aux2 - 1] + 1, + (fd_set *)(Cselect [m]->ro), + (fd_set *)(Cselect [m]->wo), + (fd_set *)(Cselect [m]->eo), + &timeout); + + if (i == 0) { + t->ret_cd = -2; /* Let the caller decide what to do. */ + } else { + t->ret_cd = i; + } + return; + + case 5: /* Read Outputs */ + + t->len_out = Cselect [m]->len; + t->buffer_out = (char *)malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + memset (t->buffer_out, 0, t->len_out); + + i = 0; + while (i < aux2) { + if (Ccom_han [i] != -1) + if (FD_ISSET (Ccom_han [i], (fd_set *)(Cselect [m]->ro))) + hercFD_SET (i, (hercfd_set *)(t->buffer_out)); + i++; + } + + /* Need to bswap every long in the outgoing array... */ + i = t->len_out / 4; + while (i) { + i--; + ((u_int *)t->buffer_out) [i] = htonl (((u_int *)t->buffer_out) [i]); + } + + t->ret_cd = 0; + return; + + case 6: /* Write Outputs */ + + t->len_out = Cselect [m]->len; + t->buffer_out = (char *)malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + memset (t->buffer_out, 0, t->len_out); + + i = 0; + while (i < aux2) { + if (Ccom_han [i] != -1) + if (FD_ISSET (Ccom_han [i], (fd_set *)(Cselect [m]->wo))) + hercFD_SET (i, (hercfd_set *)(t->buffer_out)); + i++; + } + + /* Need to bswap every long in the outgoing array... */ + i = t->len_out / 4; + while (i) { + i--; + ((u_int *)t->buffer_out) [i] = htonl (((u_int *)t->buffer_out) [i]); + } + + t->ret_cd = 0; + return; + + case 7: /* Exception Outputs */ + + t->len_out = Cselect [m]->len; + t->buffer_out = (char *)malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + memset (t->buffer_out, 0, t->len_out); + + i = 0; + while (i < aux2) { + if (Ccom_han [i] != -1) + if (FD_ISSET (Ccom_han [i], (fd_set *)(Cselect [m]->eo))) + hercFD_SET (i, (hercfd_set *)(t->buffer_out)); + i++; + } + + /* Need to bswap every long in the outgoing array... */ + i = t->len_out / 4; + while (i) { + i--; + ((u_int *)t->buffer_out) [i] = htonl (((u_int *)t->buffer_out) [i]); + } + + t->ret_cd = 0; + return; + + case 8: /* Finish */ + + if (Cselect [m] != NULL) { /* Clean-up */ + + free (Cselect [m]->ri); + free (Cselect [m]->wi); + free (Cselect [m]->ei); + + free (Cselect [m]->ro); + free (Cselect [m]->wo); + free (Cselect [m]->eo); + + free (Cselect [m]); + Cselect [m] = NULL; + } + + t->ret_cd = 0; + return; + } + + return; + + case 18: /* GETHOSTBYADDR */ + + isock = sizeof (Slocal_adx); + i = htonl (aux1); + +#ifdef _MSVC_ + if ((hp = gethostbyaddr ((const char *) &i, isock, AF_INET)) == NULL) { +#else + if ((hp = gethostbyaddr (&i, isock, AF_INET)) == NULL) { +#endif + + CerrGen = Get_errno (); + + t->ret_cd = 0; + return; + } else { + if (!(t->ret_cd = strlen (hp->h_name) )) { + t->ret_cd = 0; + return; + } else { + + t->len_out = t->ret_cd; + t->buffer_out = (char *) malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + + m = t->ret_cd; + i = 0; + k = 0; + while (m) { + t->buffer_out [k++] = DCCascii_to_ebcdic [(unsigned char)(hp->h_name [i++])]; + m--; + } + return; + } + } + + case 19: /* GETPEERNAME */ + + if (check_not_sock (aux1, t)) return; + + t->len_out = sizeof (Clocal_adx); + t->buffer_out = (char *) malloc (t->len_out); + t->buffer_out_slot = find_slot ((ULONG_PTR)&(t->buffer_out [0])); + + isock = t->len_out; + t->ret_cd = getpeername (Ccom_han [aux1], (struct sockaddr *)(t->buffer_out), &isock); + + if (t->ret_cd == -1) { + Cerr [aux1] = Get_errno (); + } else { + ((SOCKADDR_IN *)(t->buffer_out))->sin_family = htons (((SOCKADDR_IN *)(t->buffer_out))->sin_family); + } + + return; + + } + + t->ret_cd = 0; + return; +} + +/**********************************************************************************/ +/* + R0 = 0 (Initially, but turns to > 0 after the native call. + R1 = Byte Counter + R2 = Source/Destination of PC buffer. 32bits. + R3 = Direction (0 = to Host PC, 1 = from Host PC) + R4 = Returned Bytes + + R7 = Function + R8 = Aux. value 1 + R9 = Aux. value 2 + + R14 = Identifier (returned & passed back for conversations.) + R15 = Work Variable / Return Code +*/ + +u_int lar_tcpip (u_int * regs) { + talk_ptr t; + + if (tcpip_init_req) { + tcpip_init_req = 0; + tcpip_init (); + } + + if (get_reg (regs, 0) == 0) { /* Initial call. */ + + if (get_reg (regs, 3) == 0) { /* Alloc memory for this communication. */ + + t = (talk_ptr)malloc (sizeof (talk)); + t->slot = find_slot ((ULONG_PTR)t); + + t->len_in = get_reg (regs, 1); + t->buffer_in = (char *)malloc (t->len_in + 1); + t->buffer_in_slot = find_slot ((ULONG_PTR)&(t->buffer_in [0])); + t->buffer_in [t->len_in] = 0; /* NULL Terminator */ + + t->len_out = 0; + t->buffer_out = NULL; /* I've got nothing, at the moment */ + t->ret_cd = 0; + + set_reg (regs, 14, (u_int )t->slot); + + set_reg (regs, 2, (u_int )t->buffer_in_slot); + + } else { /* They want some return info... */ + + t = (talk_ptr)map32[get_reg (regs, 14)]; + + set_reg (regs, 1, t->len_out); + set_reg (regs, 2, (u_int )t->buffer_out_slot); + + set_reg (regs, 4, t->ret_cd); + } + + } else { /* Must need additional processing. */ + + t = (talk_ptr)map32[get_reg (regs, 14)]; + + if (get_reg (regs, 3) == 0) { /* Run. */ + + EZASOKET (get_reg (regs, 7), get_reg (regs, 8), get_reg (regs, 9), t); + + } else { /* Dealloc memory for this communication. */ + + map32[t->buffer_in_slot] = -1; + free (t->buffer_in); + if (t->buffer_out) { + map32[t->buffer_out_slot] = -1; + free (t->buffer_out); + } + map32[t->slot] = -1; + free (t); + + set_reg (regs, 14, 0); + } + } + + return (1); /* We never return 0, that's for the DLL Loader. */ +} + +/**********************************************************************************/ diff --git a/tcpip.h b/tcpip.h new file mode 100644 index 000000000..a8c1b90c0 --- /dev/null +++ b/tcpip.h @@ -0,0 +1,288 @@ +/*-------------------------------------------------------------------*/ +/* TCPIP.H (C) Copyright Jason Paul Winter, 2003,2010 */ +/* Minor adaptions for SDL Hyperion, Juergen Winkelmann 2019 */ +/*-------------------------------------------------------------------*/ + +#define Ccom 1024 /* maximum number of concurrent connections + 1 */ + +#ifndef _MSVC_ +typedef unsigned long ULONG_PTR; +#endif + +#if !defined( _X75_C_ ) +#ifndef _MSVC_ + +/* Convert Windows declarations back to normal *nix types if needed: */ + +#define SOCKET int +#define SOCKADDR struct sockaddr +#define SOCKADDR_IN struct sockaddr_in +#define LPSOCKADDR struct sockaddr * + +#define closesocket close +#define ioctlsocket ioctl + +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 + +#endif + +typedef struct talk_tag * talk_ptr; +typedef struct talk_tag { + u_int len_in; + char * buffer_in; + u_int len_out; + char * buffer_out; + int ret_cd; + u_int slot; + u_int buffer_in_slot; + u_int buffer_out_slot; +} talk; + +typedef struct selects_tag * selects_ptr; +typedef struct selects_tag { + u_int len; + u_int invalid; + u_int * ri; + u_int * wi; + u_int * ei; + u_int * ro; + u_int * wo; + u_int * eo; +} selects; + + +#define hercNBBY 8 +#define hercFD_SETSIZE 256 +typedef u_int hercfd_mask; +#define hercNFDBITS (sizeof(hercfd_mask) * hercNBBY) +#define herchowmany(x, y) (((x) + ((y) - 1)) / (y)) + +typedef struct hercfd_set { + hercfd_mask hercfds_bits [herchowmany(hercFD_SETSIZE, hercNFDBITS)]; +} hercfd_set; + +#define hercFD_SET(n, p) ((p)->hercfds_bits[(n)/hercNFDBITS] |= (1 << ((n) % hercNFDBITS))) +#define hercFD_CLR(n, p) ((p)->hercfds_bits[(n)/hercNFDBITS] &= ~(1 << ((n) % hercNFDBITS))) +#define hercFD_ISSET(n, p) ((p)->hercfds_bits[(n)/hercNFDBITS] & (1 << ((n) % hercNFDBITS))) + +#ifdef _MSVC_ + +/* When using MSVC, just use the normal critical section functions: */ + +#undef initialize_lock +#undef LOCK +#undef obtain_lock +#undef release_lock + +#define initialize_lock InitializeCriticalSection +#define LOCK CRITICAL_SECTION +#define obtain_lock EnterCriticalSection +#define release_lock LeaveCriticalSection + +#endif + +#define hEMFILE 24 /* Too many open files */ +/* non-blocking and interrupt i/o */ +#define hEAGAIN 35 /* Resource temporarily unavailable */ +#define hEWOULDBLOCK hEAGAIN /* Operation would block */ +#define hEINPROGRESS 36 /* Operation now in progress */ +#define hEALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define hENOTSOCK 38 /* Socket operation on non-socket */ +#define hEDESTADDRREQ 39 /* Destination address required */ +#define hEMSGSIZE 40 /* Message too int */ +#define hEPROTOTYPE 41 /* Protocol wrong type for socket */ +#define hENOPROTOOPT 42 /* Protocol not available */ +#define hEPROTONOSUPPORT 43 /* Protocol not supported */ +#define hESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define hEOPNOTSUPP 45 /* Operation not supported */ +#define hEPFNOSUPPORT 46 /* Protocol family not supported */ +#define hEAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define hEADDRINUSE 48 /* Address already in use */ +#define hEADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define hENETDOWN 50 /* Network is down */ +#define hENETUNREACH 51 /* Network is unreachable */ +#define hENETRESET 52 /* Network dropped connection on reset */ +#define hECONNABORTED 53 /* Software caused connection abort */ +#define hECONNRESET 54 /* Connection reset by peer */ +#define hENOBUFS 55 /* No buffer space available */ +#define hEISCONN 56 /* Socket is already connected */ +#define hENOTCONN 57 /* Socket is not connected */ +#define hESHUTDOWN 58 /* Can't send after socket shutdown */ +#define hETOOMANYREFS 59 /* Too many references: can't splice */ +#define hETIMEDOUT 60 /* Operation timed out */ +#define hECONNREFUSED 61 /* Connection refused */ + +/* Other */ +#define hEINVAL 22 /* Invalid argument */ +#define hELOOP 62 /* Too many levels of symbolic links */ +#define hENAMETOOLONG 63 /* File name too int */ +#define hEHOSTDOWN 64 /* Host is down */ +#define hEHOSTUNREACH 65 /* No route to host */ +#define hENOTEMPTY 66 /* Directory not empty */ +#define hEPROCLIM 67 /* Too many processes */ +#define hEUSERS 68 /* Too many users */ +#define hEDQUOT 69 /* Disc quota exceeded */ +#define hESTALE 70 /* Stale NFS file handle */ +#define hEREMOTE 71 /* Too many levels of remote in path */ + +#ifndef _MSVC_ + +/* Reverse my MSVC changes for Non MSVC compilers: */ + +#define fEMFILE EMFILE +#define fEINVAL EINVAL +#define fENAMETOOLONG ENAMETOOLONG +#define fENOTEMPTY ENOTEMPTY + +#else + +/* New MSVC compilers have EMFILE, EINVAL, ENAMETOOLONG and ENOTEMPTY */ +/* defined in multiple places - so some new code here adds a 'f'ix! */ +/* This is what we need to do with error #s: Windows->Unix->Hercules */ + +#undef fEMFILE +#undef EWOULDBLOCK +#undef EINPROGRESS +#undef EALREADY + +#undef ENOTSOCK +#undef EDESTADDRREQ +#undef EMSGSIZE +#undef EPROTOTYPE +#undef ENOPROTOOPT +#undef EPROTONOSUPPORT +#undef ESOCKTNOSUPPORT +#undef EOPNOTSUPP +#undef EPFNOSUPPORT +#undef EAFNOSUPPORT +#undef EADDRINUSE +#undef EADDRNOTAVAIL + +#undef ENETDOWN +#undef ENETUNREACH +#undef ENETRESET +#undef ECONNABORTED +#undef ECONNRESET +#undef ENOBUFS +#undef EISCONN +#undef ENOTCONN +#undef ESHUTDOWN +#undef ETOOMANYREFS +#undef ETIMEDOUT +#undef ECONNREFUSED + +#undef fEINVAL +#undef ELOOP +#undef fENAMETOOLONG +#undef EHOSTDOWN +#undef EHOSTUNREACH +#undef fENOTEMPTY +#undef EPROCLIM +#undef EUSERS +#undef EDQUOT +#undef ESTALE +#undef EREMOTE + +#define fEMFILE WSAEMFILE +#define EWOULDBLOCK WSAEWOULDBLOCK /* Is also EAGAIN */ +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY + +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL + +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED + +#define fEINVAL WSAEINVAL +#define ELOOP WSAELOOP +#define fENAMETOOLONG WSAENAMETOOLONG +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#define fENOTEMPTY WSAENOTEMPTY +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE + +#endif + +static unsigned char DCCascii_to_ebcdic[] = { + "\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x15\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x1C\x1D\x1E\x1F" + "\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61" + "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F" + "\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6" + "\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D" + "\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96" + "\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x4F\xD0\xA1\x07" + "\x20\x21\x22\x23\x24\x25\x06\x17\x28\x29\x2A\x2B\x2C\x09\x0A\x1B" + "\x30\x31\x1A\x33\x34\x35\x36\x08\x38\x39\x3A\x3B\x04\x14\x3E\xFF" + "\x41\xAA\x4A\xB1\x9F\xB2\x6A\xB5\xBB\xB4\x9A\x8A\xB0\xCA\xAF\xBC" + "\x90\x8F\xEA\xFA\xBE\xA0\xB6\xB3\x9D\xDA\x9B\x8B\xB7\xB8\xB9\xAB" + "\x64\x65\x62\x66\x63\x67\x9E\x68\x74\x71\x72\x73\x78\x75\x76\x77" + "\xAC\x69\xED\xEE\xEB\xEF\xEC\xBF\x80\xFD\xFE\xFB\xFC\xBA\xAE\x59" + "\x44\x45\x42\x46\x43\x47\x9C\x48\x54\x51\x52\x53\x58\x55\x56\x57" + "\x8C\x49\xCD\xCE\xCB\xCF\xCC\xE1\x70\xDD\xDE\xDB\xDC\x8D\x8E\xDF" +}; + +static unsigned char DCCebcdic_to_ascii[] = { + "\x00\x01\x02\x03\x9C\x09\x86\x7F\x97\x8D\x8E\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x9D\x0A\x08\x87\x18\x19\x92\x8F\x1C\x1D\x1E\x1F" + "\x80\x81\x82\x83\x84\x85\x17\x1B\x88\x89\x8A\x8B\x8C\x05\x06\x07" + "\x90\x91\x16\x93\x94\x95\x96\x04\x98\x99\x9A\x9B\x14\x15\x9E\x1A" + "\x20\xA0\xE2\xE4\xE0\xE1\xE3\xE5\xE7\xF1\xA2\x2E\x3C\x28\x2B\x7C" + "\x26\xE9\xEA\xEB\xE8\xED\xEE\xEF\xEC\xDF\x21\x24\x2A\x29\x3B\x5E" + "\x2D\x2F\xC2\xC4\xC0\xC1\xC3\xC5\xC7\xD1\xA6\x2C\x25\x5F\x3E\x3F" + "\xF8\xC9\xCA\xCB\xC8\xCD\xCE\xCF\xCC\x60\x3A\x23\x40\x27\x3D\x22" + "\xD8\x61\x62\x63\x64\x65\x66\x67\x68\x69\xAB\xBB\xF0\xFD\xFE\xB1" + "\xB0\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\xAA\xBA\xE6\xB8\xC6\xA4" + "\xB5\x7E\x73\x74\x75\x76\x77\x78\x79\x7A\xA1\xBF\xD0\x5B\xDE\xAE" + "\xAC\xA3\xA5\xB7\xA9\xA7\xB6\xBC\xBD\xBE\xDD\xA8\xAF\x5D\xB4\xD7" + "\x7B\x41\x42\x43\x44\x45\x46\x47\x48\x49\xAD\xF4\xF6\xF2\xF3\xF5" + "\x7D\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\xB9\xFB\xFC\xF9\xFA\xFF" + "\x5C\xF7\x53\x54\x55\x56\x57\x58\x59\x5A\xB2\xD4\xD6\xD2\xD3\xD5" + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xB3\xDB\xDC\xD9\xDA\x9F" +}; + +static char Ccom_opn [Ccom]; +static char Ccom_blk [Ccom]; /* Is a blocking socket? */ +static SOCKET Ccom_han [Ccom]; + +static u_int CerrGen; /* Last error, thread-dodgy but it's only used for "non socket" errors */ +static u_int Cerr [Ccom]; /* Last error for specific socket, this one is thread safe. */ + +static selects_ptr Cselect [Ccom]; /* Array for the 3 arrays of select input/output data */ + +static LOCK tcpip_lock; + +static u_int tcpip_init_req = 1; + +ULONG_PTR map32[Ccom]; +#endif /*!defined( _X75_C_ )*/ diff --git a/x75.c b/x75.c new file mode 100644 index 000000000..152966c67 --- /dev/null +++ b/x75.c @@ -0,0 +1,140 @@ +/*-------------------------------------------------------------------*/ +/* X75.C (C) Copyright Jason Paul Winter, 2003,2010 */ +/* Minor adaptions for SDL Hyperion, Juergen Winkelmann 2019 */ +/* */ +/* This program was written by Jason Paul Winter. It was originally */ +/* named DYN75.C. */ +/* */ +/* Copyright (c) 2003-2010, Jason Paul Winter */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with */ +/* or without modification, are permitted provided that */ +/* the following conditions are met: */ +/* */ +/* Redistributions of source code must retain the above */ +/* copyright notice, this list of conditions and the */ +/* following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */ +/* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */ +/* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR */ +/* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS */ +/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ +/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ +/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH */ +/* DAMAGE. */ +/* */ +/*-------------------------------------------------------------------*/ +/* This module implements the TCPIP instruction, which allows guest */ +/* access to the host's TCP/IP stack. Register usage is as follows: */ +/* */ +/* R0 = 0 (Initially, but turns to > 0 after the native call. */ +/* R1 = Byte Counter */ +/* R2 = Source/Destination of PC buffer. 32bits. */ +/* R3 = Direction (0 = to Host PC, 1 = from Host PC) */ +/* R4 = Returned Bytes */ +/* */ +/* R7 \ */ +/* R8 |= Used by the lar_tcpip function (but not here.) */ +/* R9 / */ +/* */ +/* R14 = Identifier (returned & passed back for conversations.) */ +/* R15 = Work Variable / Return Code */ +/*-------------------------------------------------------------------*/ + +#include "hstdinc.h" + +#define _X75_C_ +#define _HENGINE_DLL_ + +#include "hercules.h" +#include "opcode.h" +#include "inline.h" + +#include "tcpip.h" +#include "x75.h" + +#if defined( FEATURE_TCPIP_EXTENSION ) +/*-------------------------------------------------------------------*/ +/* 75xx TCPIP Ra,yyy(Rb,Rc) Ra=anything, Rc>4<14, Rb=0/ditto [RX] */ +/*-------------------------------------------------------------------*/ +DEF_INST( tcpip ) +{ + int r1; /* Value of R field */ + int b2; /* Base of effective addr */ + VADR effective_addr2; /* Effective address */ + int i; + unsigned char * s; + + /* vv---vv---------------- input variables to TCPIP */ + RX(inst, regs, r1, b2, effective_addr2); + /* ^^-- becomes yyy+gr[b]+gr[c] */ + /* ^^------ becomes access register c */ + /* ^^---------- becomes to-store register a */ + + if (!FACILITY_ENABLED( HERC_TCPIP_PROB_STATE, regs )) PRIV_CHECK(regs); + + if (regs->GR_L(0) == 0) { /* Only run when R0 = 0, (restart) */ + + if (lar_tcpip (&(regs->gr [0])) == 0) { /* Get PC buffer */ + regs->GR_L(15) = -1; /* Error */ + return; + } + + regs->GR_L(0) = 1; /* Do not call native routine again */ + } + + if (regs->GR_L(1) != 0) s = (unsigned char *)(map32[regs->GR_L(2)]); + + while (regs->GR_L(1) != 0) { /* Finished > */ + + i = regs->GR_L(1) - 1; + if (i > 255) i = 255; + + if (regs->GR_L(3) == 0) { /* Going to host */ + /* Load bytes from operand address */ + ARCH_DEP(vfetchc) ( s, (unsigned char)i, effective_addr2, b2, regs ); + } else { /* Going from host */ + /* Store bytes at operand address */ + ARCH_DEP(vstorec) ( s, (unsigned char)i, effective_addr2, b2, regs ); + } + + i++; + effective_addr2 += i; /* No exception, quick copy without calc's */ + (regs->GR_L(b2)) += i; /* Exception, can recalculate if/when restart */ + s += i; /* Next PC byte segment location */ + (regs->GR_L(1)) -= i; /* One less segment to copy next time */ + } + + if (lar_tcpip (&(regs->gr [0])) == 0) { /* Run! */ + regs->GR_L(15) = -1; /* Error */ + return; + } + + regs->GR_L(15) = 0; /* No error */ +} +#endif /*defined( FEATURE_TCPIP_EXTENSION )*/ + +#if !defined( _GEN_ARCH ) + #if defined( _ARCH_NUM_1 ) + #define _GEN_ARCH _ARCH_NUM_1 + #include "x75.c" + #endif + #if defined( _ARCH_NUM_2 ) + #undef _GEN_ARCH + #define _GEN_ARCH _ARCH_NUM_2 + #include "x75.c" + #endif +#endif /*!defined( _GEN_ARCH )*/ diff --git a/x75.h b/x75.h new file mode 100644 index 000000000..cc54ff290 --- /dev/null +++ b/x75.h @@ -0,0 +1,8 @@ +/*-------------------------------------------------------------------*/ +/* X75.H (C) Copyright Jason Paul Winter, 2003,2010 */ +/* Minor adaptions for SDL Hyperion, Juergen Winkelmann 2019 */ +/*-------------------------------------------------------------------*/ + +extern int lar_tcpip (DW * regs); /* function in tcpip.c */ +extern ULONG_PTR map32[Ccom]; /* map 64-bit host addresses */ + /* to 32-bit guest registers */