//+------------------------------------------------------------------------- // // 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; } /************************************************************************/