611 lines
16 KiB
C
611 lines
16 KiB
C
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1994 - 1999
|
|
//
|
|
// File: scx.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Filename: scx.c
|
|
//
|
|
// Description: This file contains the source code for common routines
|
|
// use for Socket I/O.
|
|
// This module is written using win32 API calls.
|
|
//
|
|
// Authors: Scott Holden (Translator from NT API to win32 API)
|
|
// Mahesh Keni (Mahesh wrote this application using mostly
|
|
// NT native API calls)
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "rawcom.h"
|
|
#include "scx.h"
|
|
#include "msipx.h"
|
|
|
|
/************************************************************************/
|
|
// Socket specific functions
|
|
/************************************************************************/
|
|
INTEGER
|
|
SPXSocket_Connect(
|
|
IN int AddrFly,
|
|
IN USHORT CIndex,
|
|
IN PCHAR srvaddr)
|
|
{
|
|
|
|
INTEGER RetCode;
|
|
SOCKADDR csockaddr; // socket address for connecting
|
|
// CHAR Tmp[12];
|
|
|
|
PSOCKADDR_NS paddr_ns = (PSOCKADDR_NS)&csockaddr;
|
|
|
|
paddr_ns->sa_family = (short)AddrFly;
|
|
paddr_ns->sa_socket = htons((USHORT)(SERV_SPX_PORT + CIndex));
|
|
|
|
// Now copy both 6 byte NodeNumber and 4 byte NetNumber
|
|
|
|
RtlCopyMemory(paddr_ns->sa_nodenum,srvaddr,6);
|
|
RtlCopyMemory(paddr_ns->sa_netnum,srvaddr+6,4);
|
|
|
|
/*
|
|
RtlCopyMemory(Tmp, srvaddr, 10); Tmp[10] = '\0';
|
|
DbgPrint("Server address %s %X\n",Tmp, Tmp);
|
|
*/
|
|
|
|
RetCode=connect(Clients[CIndex].c_Sock.c_Sockid,
|
|
&csockaddr,
|
|
sizeof(SOCKADDR));
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Error: Connect:%ld\n",WSAGetLastError());
|
|
}
|
|
|
|
// MyDbgPrint("Successfully connected \n");
|
|
|
|
return(RetCode);
|
|
}
|
|
/************************************************************************/
|
|
/*++
|
|
This routine just initializes for socket programming
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_Initialize(
|
|
|
|
IN USHORT NClients, // Number of clients
|
|
IN PCHAR ServerName, // Server IP address
|
|
IN USHORT SrvCli) // server or client
|
|
{
|
|
|
|
INTEGER RetCode = 0;
|
|
WSADATA WsaData; // got from RCP prog
|
|
|
|
RetCode = WSAStartup(0x0101, &WsaData);
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Error: WSAStartup : %ld \n",WSAGetLastError());
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
/************************************************************************/
|
|
|
|
/*++
|
|
This routine is responsible Creating a Socket instance and doing bind for
|
|
for a thread.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_PerClientInit(
|
|
IN USHORT CIndex, // client index
|
|
IN USHORT SrvCli )
|
|
{
|
|
//NTSTATUS pstatus;
|
|
INTEGER RetCode;
|
|
SOCKADDR saddr; // socket address
|
|
//INTEGER saddrlen;
|
|
SOCKET isockid;
|
|
|
|
// We can combine this with SPX routines later
|
|
PSOCKADDR_NS paddr_ns = (SOCKADDR_NS *) &saddr;
|
|
int protocol = NSPROTO_SPX;
|
|
|
|
// First create a socket for this client
|
|
if ((isockid = socket(AddrFly, SOCK_STREAM, protocol)) == INVALID_SOCKET) {
|
|
//DbgPrint("Error: Invalid Socket: %ld \n",WSAGetLastError());
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
Clients[CIndex].c_Sock.c_Sockid = isockid;
|
|
|
|
// now do the address binding part
|
|
// should get ip address from Name
|
|
|
|
ClearSocket(&saddr); // cleanup the structure
|
|
paddr_ns->sa_family = (short)AddrFly;
|
|
|
|
if (SrvCli) { // if it's a server only then do the binding
|
|
paddr_ns->sa_socket = htons((USHORT)(SERV_SPX_PORT + CIndex));
|
|
}
|
|
else { // for client assign socket id.
|
|
paddr_ns->sa_socket = 0;
|
|
}
|
|
|
|
RetCode = bind(isockid, &saddr, sizeof(saddr));
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Error: Bind: %ld\n",WSAGetLastError());;
|
|
closesocket(isockid);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
else {
|
|
if (SrvCli) {
|
|
Clients[CIndex].c_Sock.c_Listenid = isockid;
|
|
}
|
|
else {
|
|
Clients[CIndex].c_Sock.c_Sockid = isockid;
|
|
}
|
|
}
|
|
|
|
// post a listen if it's a server
|
|
if (SrvCli) {
|
|
if (RetCode = Socket_Listen(CIndex) == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Listen %d\n", RetCode);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
// Listen posted Successfully
|
|
// DbgPrint("SPX Srv: Listen posted successfully\n");
|
|
}
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/*++
|
|
This routine is responsible for issueing Listen and waiting till a
|
|
client is connected. When this routine returns successfully we can
|
|
assume that a connection is established.
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_Wait_For_Client(
|
|
IN USHORT CIndex) // client index and namedpipe instance number
|
|
{
|
|
//NTSTATUS wstatus;
|
|
INTEGER RetCode;
|
|
|
|
if (RetCode = Socket_Accept(CIndex) == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Accept %d\n", RetCode);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
//DbgPrint("SPX: Client connection accepted\n");
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/*++
|
|
This routine is responsible for issueing Disconnect to close the
|
|
connection with a client.
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_Disconnect_Client(
|
|
IN USHORT CIndex) // client index and namedpipe instance number
|
|
{
|
|
INTEGER RetCode;
|
|
|
|
//Close the socket so that it can disconnect
|
|
if ( (RetCode = Socket_Close(CIndex)) == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Close Sockid %d\n", RetCode);
|
|
// return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/*++
|
|
This routine is responsible for establishing a connection to the
|
|
server side. When this routine returns successfully we can assume that
|
|
a connection is established.
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_Connect_To_Server(
|
|
IN USHORT CIndex) // client index and namedpipe instance number
|
|
{
|
|
INTEGER RetCode;
|
|
|
|
RetCode = SPXSocket_Connect(AddrFly, CIndex, ServerName);
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Connect %d\n", RetCode);
|
|
printf("SPXSocket_Connecy error \n");
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
//DbgPrint("SPX: Client connected to the server \n");
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/*++
|
|
This routine allocates memory required for all the buffers for a client.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_Allocate_Memory(
|
|
IN USHORT CIndex) // client index and namedpipe instance number
|
|
{
|
|
NTSTATUS astatus = STATUS_SUCCESS;
|
|
ULONG AllocSize;
|
|
|
|
// AllocSize = Clients[CIndex].c_reqbuf.SendSize;
|
|
AllocSize = MAXBUFSIZE;
|
|
|
|
(LPVOID) Clients[CIndex].c_pSendBuf = VirtualAlloc(
|
|
(LPVOID) Clients[CIndex].c_pSendBuf,
|
|
(DWORD)AllocSize,
|
|
(DWORD)MEM_COMMIT,
|
|
(DWORD)PAGE_READWRITE);
|
|
|
|
sprintf(Clients[CIndex].c_pSendBuf,"Client%d Send Data",CIndex+1);
|
|
if (Clients[CIndex].c_pSendBuf == NULL) {
|
|
astatus = GetLastError();
|
|
}
|
|
// AllocSize = Clients[CIndex].c_reqbuf.RecvSize;
|
|
AllocSize = MAXBUFSIZE;
|
|
|
|
(LPVOID) Clients[CIndex].c_pRecvBuf = VirtualAlloc(
|
|
(LPVOID) Clients[CIndex].c_pRecvBuf,
|
|
(DWORD)AllocSize,
|
|
(DWORD)MEM_COMMIT,
|
|
(DWORD)PAGE_READWRITE);
|
|
|
|
sprintf(Clients[CIndex].c_pRecvBuf,"Client%d Recv Data",CIndex+1);
|
|
if (Clients[CIndex].c_pRecvBuf == NULL) {
|
|
astatus = GetLastError();
|
|
}
|
|
return astatus;
|
|
}
|
|
/************************************************************************/
|
|
/*++
|
|
This routine deallocates memory for a client.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_Deallocate_Memory(
|
|
IN USHORT CIndex) // client index and namedpipe instance number
|
|
{
|
|
NTSTATUS dstatus;
|
|
ULONG DeallocSize;
|
|
|
|
// Deallocate memory for Send Buffer
|
|
// DeallocSize = Clients[CIndex].c_reqbuf.SendSize;
|
|
DeallocSize = MAXBUFSIZE;
|
|
/*
|
|
dstatus = NtFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
(PVOID *) (&(Clients[CIndex].c_pSendBuf)),
|
|
&(DeallocSize),
|
|
MEM_DECOMMIT);
|
|
*/
|
|
dstatus = VirtualFree(
|
|
(LPVOID) Clients[CIndex].c_pSendBuf,
|
|
DeallocSize,
|
|
MEM_DECOMMIT);
|
|
|
|
if (!NT_SUCCESS(dstatus)) {
|
|
//DbgPrint("Nmp SendBuf: Deallocate memory failed: err: %lx \n", dstatus);
|
|
return dstatus;
|
|
}
|
|
|
|
// DeallocSize = Clients[CIndex].c_reqbuf.RecvSize;
|
|
DeallocSize = MAXBUFSIZE;
|
|
|
|
// Deallocate memory for Receive Buffer
|
|
/*
|
|
dstatus = NtFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
(PVOID *) (&(Clients[CIndex].c_pRecvBuf)),
|
|
&(DeallocSize),
|
|
MEM_DECOMMIT);
|
|
*/
|
|
dstatus = VirtualFree(
|
|
(LPVOID) Clients[CIndex].c_pRecvBuf,
|
|
DeallocSize,
|
|
MEM_DECOMMIT);
|
|
|
|
if (!NT_SUCCESS(dstatus)) {
|
|
//DbgPrint("Nmp RecvBuf :Deallocate memory failed: err: %lx \n", dstatus);
|
|
}
|
|
|
|
return dstatus;
|
|
|
|
}
|
|
/************************************************************************/
|
|
/*++
|
|
This routine is responsible for disconnecting a session.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_Disconnect_From_Server(
|
|
IN USHORT CIndex) // client index and namedpipe instance number
|
|
{
|
|
|
|
INTEGER RetCode;
|
|
|
|
//Close the socket so that it can disconnect
|
|
if ( (RetCode = Socket_Close(CIndex)) == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Close Sockid %d\n", RetCode);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/*++
|
|
This routine does handshake with it's peer. For Server this means
|
|
receiving request message from a client. For Client it means just the
|
|
opposite.
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_DoHandshake(
|
|
IN USHORT CIndex, // client index
|
|
IN USHORT SrvCli // if it's a server or client
|
|
)
|
|
{
|
|
ULONG RWreqLen;
|
|
INTEGER RetCode = 0;
|
|
|
|
RWreqLen = sizeof(struct reqbuf);
|
|
|
|
// for server do receive for a request buffer
|
|
if (SrvCli) {
|
|
RetCode = Socket_Recv(
|
|
CIndex,
|
|
(PVOID) &(Clients[CIndex].c_reqbuf),
|
|
(PULONG) &RWreqLen);
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Recv %d\n", RetCode);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
//DbgPrint("Srv handshake recv ok\n");
|
|
}
|
|
else { // for Client do send of reqbuf size
|
|
|
|
// Based on TestCmd make changes i.e. 'U'->'P'
|
|
RetCode = Socket_Send(
|
|
CIndex,
|
|
(PVOID) &(Clients[CIndex].c_reqbuf),
|
|
(PULONG) &RWreqLen);
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Send %d\n", RetCode);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
//DbgPrint("Cli handshake Send ok\n");
|
|
}
|
|
|
|
// check if read/write length is ok
|
|
if (RWreqLen != sizeof(struct reqbuf)) {
|
|
//DbgPrint("Sock:Read/Write Len mismatch: read %ld \n", RWreqLen);
|
|
}
|
|
|
|
/*
|
|
MyDbgPrint("handshake: Sendl:%ld Recvl:%ld \n",
|
|
Clients[CIndex].c_reqbuf.SendSize,
|
|
Clients[CIndex].c_reqbuf.RecvSize);
|
|
*/
|
|
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
/************************************************************************/
|
|
/*++
|
|
This routine Reads data from IPC. For server it means reading data
|
|
NumSends times in SendBuffers and for a client NumRecvs times into
|
|
RecvBuffer.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_ReadFromIPC(
|
|
IN USHORT CIndex, // client index and namedpipe instance number
|
|
IN OUT PULONG pReadDone,
|
|
IN USHORT SrvCli // if it's a server or client
|
|
)
|
|
|
|
{
|
|
ULONG NumReads;
|
|
ULONG ReadLen;
|
|
PCHAR ReadBuf;
|
|
INTEGER RetCode;
|
|
|
|
if (SrvCli) { // set proper iterations and buffer for Server
|
|
NumReads = Clients[CIndex].c_reqbuf.NumSends;
|
|
ReadBuf = Clients[CIndex].c_pSendBuf;
|
|
ReadLen = Clients[CIndex].c_reqbuf.SendSize;
|
|
}
|
|
else { // for client do proper settings
|
|
NumReads = Clients[CIndex].c_reqbuf.NumRecvs;
|
|
ReadBuf = Clients[CIndex].c_pRecvBuf;
|
|
ReadLen = Clients[CIndex].c_reqbuf.RecvSize;
|
|
}
|
|
|
|
while (NumReads--) {
|
|
RetCode = Socket_Recv(
|
|
CIndex,
|
|
(PVOID) ReadBuf,
|
|
(PULONG)&ReadLen);
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Recv %d\n", RetCode);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
// Assign the read length
|
|
*pReadDone = ReadLen;
|
|
}
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/*++
|
|
This routine Writes data to IPC. For server it means writing data
|
|
NumRecvs times in RecvBuffers and for a client NumSends times into
|
|
SendBuffer.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_WriteToIPC(
|
|
IN USHORT CIndex, // client index and namedpipe instance number
|
|
IN OUT PULONG pWriteDone,
|
|
IN USHORT SrvCli // if it's a server or client
|
|
)
|
|
|
|
{
|
|
ULONG NumWrites;
|
|
ULONG WriteLen;
|
|
PCHAR WriteBuf;
|
|
INTEGER RetCode;
|
|
|
|
if (SrvCli) { // set proper iterations and buffer for Server
|
|
NumWrites = Clients[CIndex].c_reqbuf.NumRecvs;
|
|
WriteBuf = Clients[CIndex].c_pRecvBuf;
|
|
WriteLen = Clients[CIndex].c_reqbuf.RecvSize;
|
|
}
|
|
else { // for client do proper settings
|
|
NumWrites = Clients[CIndex].c_reqbuf.NumSends;
|
|
WriteBuf = Clients[CIndex].c_pSendBuf;
|
|
WriteLen = Clients[CIndex].c_reqbuf.SendSize;
|
|
}
|
|
|
|
while (NumWrites--) {
|
|
RetCode = Socket_Send(
|
|
CIndex,
|
|
(PVOID) WriteBuf,
|
|
(PULONG) &WriteLen);
|
|
|
|
if (RetCode == SOCKET_ERROR) {
|
|
//DbgPrint("Sock: Error in Send %d\n", RetCode);
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
*pWriteDone = WriteLen;
|
|
}
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
/************************************************************************/
|
|
/*++
|
|
This routine does transaction type IO to IPC. This just assumes that
|
|
both Number of reads and writes are equal and will use Number of reads
|
|
as it's basis.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_XactIO(
|
|
IN USHORT CIndex, // client index and namedpipe instance number
|
|
IN OUT PULONG pReadDone,
|
|
IN OUT PULONG pWriteDone,
|
|
IN USHORT SrvCli, // if it's a server or client
|
|
IN BOOLEAN FirstIter
|
|
)
|
|
|
|
{
|
|
ULONG NumReads;
|
|
ULONG ReadLen;
|
|
PCHAR ReadBuf;
|
|
ULONG WriteLen;
|
|
PCHAR WriteBuf;
|
|
//INTEGER RetCode;
|
|
|
|
NumReads = Clients[CIndex].c_reqbuf.NumRecvs;
|
|
|
|
if (SrvCli) { // set proper iterations and buffer for Server
|
|
ReadBuf = Clients[CIndex].c_pSendBuf;
|
|
ReadLen = Clients[CIndex].c_reqbuf.SendSize;
|
|
WriteBuf = Clients[CIndex].c_pRecvBuf;
|
|
WriteLen = Clients[CIndex].c_reqbuf.RecvSize;
|
|
}
|
|
else { // for client do proper settings
|
|
ReadBuf = Clients[CIndex].c_pRecvBuf;
|
|
ReadLen = Clients[CIndex].c_reqbuf.RecvSize;
|
|
WriteBuf = Clients[CIndex].c_pSendBuf;
|
|
WriteLen = Clients[CIndex].c_reqbuf.SendSize;
|
|
}
|
|
/*
|
|
while (NumReads--) {
|
|
|
|
*pReadDone = ReadLen;
|
|
*pWriteDone = WriteLen;
|
|
}
|
|
*/
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SCXNS_Cleanup(VOID)
|
|
{
|
|
//USHORT Cindex = 0; // client index
|
|
//NTSTATUS cstatus;
|
|
//NTSTATUS exitstatus = 0;
|
|
|
|
/*
|
|
for (Cindex = 0; Cindex < NClients; Cindex++) {
|
|
|
|
// if the client was used then close the NamedPipe handle
|
|
cstatus = NtClose (Clients[Cindex].c_Nmp.c_PipeHandle);
|
|
|
|
if (!NT_SUCCESS(cstatus)) {
|
|
printf("Failed to close NMPhandle thno:%d err=%lx\n",
|
|
Cindex,cstatus);
|
|
}
|
|
|
|
// terminate the thread
|
|
cstatus = NtTerminateThread(
|
|
Clients[Cindex].c_hThHandle,
|
|
exitstatus);
|
|
|
|
if (!NT_SUCCESS(cstatus)) {
|
|
printf("Failed to terminate thread no:%d err=%lx\n",
|
|
Cindex,cstatus);
|
|
}
|
|
}
|
|
*/
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
/************************************************************************/
|
|
/*++
|
|
This routine does a client specific cleanup work.
|
|
--*/
|
|
|
|
NTSTATUS
|
|
SCXNS_ThreadCleanUp(
|
|
IN USHORT CIndex
|
|
)
|
|
|
|
{
|
|
//NTSTATUS tstatus;
|
|
// For Server Close the ListenId
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
/************************************************************************/
|