📄 rpcserv.c
字号:
/*
* COPYRIGHT (c) 1995-1999 by Philips Semiconductors
*
* +-----------------------------------------------------------------+
* | THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED |
* | AND COPIED IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF SUCH |
* | A LICENSE AND WITH THE INCLUSION OF THE THIS COPY RIGHT NOTICE. |
* | THIS SOFTWARE OR ANY OTHER COPIES OF THIS SOFTWARE MAY NOT BE |
* | PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. THE |
* | OWNERSHIP AND TITLE OF THIS SOFTWARE IS NOT TRANSFERRED. |
* +-----------------------------------------------------------------+
*
* Module name : RPCServ.c 1.79
*
* Title : Implementation of HostCall interface
*
* Last update : 17:36:27 - 99/04/27
*
* Description :
*
* This module is part of an implementation of the server part
* for a HostCall interface. HostCall is the software component
* which is required by the TCS toolset to adapt the programs
* generated by this toolset to a specific host (see file
* HostCall.h in the TCS include dir).
*
* RPCServ is the part of the implementation which runs on the
* host, serving all IO requests of the TM-1 application.
* RPCServ is one of two modules of this host-resident part, and
* defines *how* messages should be served; it still is host
* independent. The other part of this implementation, TM1IF,
* contains all host specific issues which are communication
* with the target and the ability to start a number of server
* tasks.
*
* RPCServ is the counterpart of RPCClient on the target, and
* TM1IF is the counterpart of HostIF on the target. However,
* contrary to the target situation, where RPCClient is built
* on top of HostIF, on the host side TM1IF is built on top of
* RPCServ.
*
* The interface to this module is as follows:
*
* 1) An initialisation function is provided which takes
* a number of IO functions as input.
* By these IO functions, the actual host can control the IO
* while serving target IO requests.
* For instance, certain IO channels (typically standard
* in/out) can be redirected. This initialisation function
* must be called once before any other use.
*
* 2) A termination function is provided for cleanup.
*
* 3) A function for adding information on a new node is
* provided. Information consists of a node number,
* command line arguments, and values for the standard
* file descriptors. This function must be used before
* a command is passed to the serve routine (see next).
* A node is automatically removed from the internal
* administration when its 'exit' message is received.
* In this case, the client of this module is notified
* via the 'exit' I/O function.
*
* 4) A serve routine is provided for serving commands
* obtained from any of the previously `added` nodes.
* serving might call one of the IO functions provided
* with 1), and/or it might require specific node information
* provided with 3). Serving takes care of endian conversion,
* host/target address translation, and further interpretation
* of the provided command.
*
*
* NB: This interface does not provide for loading and
* starting the TM1 appication.
*
* NOTE: a hack for Win95 has been put in this module.
* for 'IO operations', the error status must be
* obtained from _doserrno iso errno.
*/
/*---------------------------- Includes --------------------------------------*/
#ifdef _WIN32
#include "windows.h"
#include "winsock.h"
#else
#ifndef __MWERKS__
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#endif
#include "Lib_Local.h"
#include <dirent.h>
#include <time.h>
#ifndef __MWERKS__
#include <sys/timeb.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include <setjmp.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __MWERKS__
#include <Errors.h>
#include <types.h>
#include <stat.h>
#include <unistd.h>
#include "WINSOCK.H"
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
/* #include "tmtypes.h"*/
#include "HostCall.h"
#include "TM1IF.h"
#include "RPCServ.h"
#include "RPC_Common.h"
#include "Lib_Util.h"
/*------------------------- Environment Patches ------------------------------*/
extern String mktemp(String);
#ifdef _WIN32
#define unlink _unlink
#define mktemp _mktemp
#endif
#ifdef __MWERKS__
#define ENOSYS TCS_ENOSYS
#define ENAMETOOLONG TCS_ENAMETOOLONG
#define mktemp tmpnam
/*
The Metrowerks MSL library used for MacOS runtime is not Posix.1 5.3.1.2 compliant.
I.e., if a file is open()'ed with O_APPEND the file offset shall be set to the
end of file prior to each write. Metrowerks will not fix this because MacOS is
not Posix compliant so we workaround here by keeping track of any MacOS files opened
with O_APPEND and then doing an lseek(fd, 0, SEEK_END) before any writes to that file.
These changes are conditionalized only for MacOS Metrowerks.
*/
Int32 mac_fd[FOPEN_MAX];
int number_mac_files = 0;
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef _O_BINARY
#define _O_BINARY 0
#endif
/*---------------------------- Module State ----------------------------------*/
#define MAX_NODE 32 /* when making larger, see VALID macros */
static UInt valid_nodes_mask;
static RPCServ_NodeInfo node_info[MAX_NODE];
#define VALIDATE_NODE(n) (valid_nodes_mask |= 1 << (n))
#define INVALIDATE_NODE(n) (valid_nodes_mask &= ~(1 << (n)))
#define IS_VALID_NODE(n) (valid_nodes_mask & 1 << (n))
/*
* Copied parameters of RPCServ_init:
*/
static RPCServ_OpenFunc parm_open;
static RPCServ_CloseFunc parm_close;
static RPCServ_ReadFunc parm_read;
static RPCServ_WriteFunc parm_write;
static RPCServ_SeekFunc parm_seek;
static RPCServ_IsattyFunc parm_isatty;
static RPCServ_FstatFunc parm_fstat;
static RPCServ_StatFunc parm_stat;
static RPCServ_ExitFunc parm_exit;
static RPCServ_FcntlFunc parm_fcntl;
static RPCServ_OpenDllFunc parm_open_dll;
/*--------------------------- Conversion routines ----------------------------*/
/* Conversion routines are
*
* convert_host_... take a host value and convert to tcs format
* convert_tcs_... take a tcs value and convert to host format
*
* Each function does the whole job, including any subobjects and endian
* conversion.
*/
#ifndef SERIAL_RPC
/*
* ninfo as implicit parameter, to keep
* the expressions a little bit decent:
*/
#define IN_BUFFER(x) TM1IF_tm2host(ninfo,(Address) (x))
#define IN_BUFFER2(x) TM1IF_tm2host(ninfo,(Address) (x))
#define RESULT_BUFFER(x) TM1IF_tm2host(ninfo,(Address) (x))
#define COMMAND_BUFFER(x) TM1IF_tm2host(ninfo,(Address) (x))
/*
This hack is to get around the problem that if you do an SDRAM write
followed by an MMIO write the MMIO write can take place BEFORE the SDRAM write
takes place.
*/
void PCI_STABILISE( Int32 *pci, Int32 *svd )
{
volatile Int32 *p = pci;
*svd= *p;
*p = 0; while (*p != 0) {}
*p = *svd; while (*p != *svd) {}
}
#else
#define PCI_STABILISE(a,b)
#define IN_BUFFER(x) TM1IF_in_buffer
#define IN_BUFFER2(x) TM1IF_in_buffer2
#define RESULT_BUFFER(x) TM1IF_result_buffer
#define COMMAND_BUFFER(x) TM1IF_command_buffer
#endif
static Int32 convert_host_long
(
Int32 value
)
{
return TM1IF_endian_swap (value);
}
/* -------------------------------------------- */
static Int32 convert_host_short
(
Int32 value
)
{
return TM1IF_endian_swap_short (value);
}
/* -------------------------------------------- */
static UInt32 convert_host_ulong
(
UInt32 value
)
{
return TM1IF_endian_swap (value);
}
/* -------------------------------------------- */
static UInt32 convert_host_ushort
(
UInt32 value
)
{
return TM1IF_endian_swap_short (value);
}
/* -------------------------------------------- */
static Int32 convert_tcs_long
(
Int32 value
)
{
return TM1IF_endian_swap (value);
}
/* -------------------------------------------- */
static Int32 convert_tcs_short
(
Int32 value
)
{
return TM1IF_endian_swap_short (value);
}
/* -------------------------------------------- */
static UInt32 convert_tcs_ulong
(
UInt32 value
)
{
return TM1IF_endian_swap (value);
}
/* -------------------------------------------- */
static UInt32 convert_tcs_ushort
(
UInt32 value
)
{
return TM1IF_endian_swap_short (value);
}
/* -------------------------------------------- */
/*
* Converts a (local) struct hostent, as returned by gethostby{addr,name}(),
* into a TCS_HostEnt suitable for use by the client.
* Returns 1 if all well, 0 if buffer too small.
*/
static int convert_host_hostent
(
struct hostent const *r, /*IN*/
TCS_HostEnt *result, /*OUT*/
char *buffer, /*OUT*/
int buflen
)
{
int i = 0;
/*
* Executes an expression (which should add some bytes to the buffer),
* checking first that the buffer is big enough; and increments
* the pointer afterwards.
*/
#define BUFFER_ADD(expr, len) \
{ \
int len_ = (len); \
\
if (i + len_ > buflen) \
{ \
return 0; \
} \
(expr); \
i += len_; \
}
/*h_name*/
result->h_name = convert_host_long (i);
BUFFER_ADD (strcpy (&buffer [i], r->h_name),
LROUND_UP (strlen (r->h_name) + 1, sizeof (int)))
/*h_aliases---this list is always 1 long as we discard all aliases*/
result->h_aliases = convert_host_long (i);
BUFFER_ADD (*(int *) &buffer [i] = 0, sizeof (int))
/*h_addrtype*/
result->h_addrtype = convert_host_short (r->h_addrtype);
/*h_length*/
result->h_length = convert_host_short (r->h_length);
/*h_addr_list---this list is always 2 long as we only keep 1 address*/
result->h_addr_list = convert_host_long (i);
BUFFER_ADD (*(int *) &buffer [i] = convert_host_long (i + 2*sizeof (int)),
sizeof (int))
BUFFER_ADD (*(int *) &buffer [i] = 0, sizeof (int))
BUFFER_ADD (memcpy (&buffer [i], r->h_addr_list [0], r->h_length),
LROUND_UP (r->h_length, 4))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -