346 lines
10 KiB
C
346 lines
10 KiB
C
|
/*
|
||
|
* Copyright (c) Microsoft Corporation
|
||
|
*
|
||
|
* Module Name :
|
||
|
* bridge.c
|
||
|
*
|
||
|
* This contains the main worker thread that passes information between the clients
|
||
|
* the Com port.
|
||
|
*
|
||
|
* Sadagopan Rajaram -- Oct 15, 1999
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "tcsrv.h"
|
||
|
#include "tcsrvc.h"
|
||
|
#include "proto.h"
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
bridge(
|
||
|
PCOM_PORT_INFO pComPortInfo
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PCONNECTION_INFO pTemp;
|
||
|
DWORD waitStatus;
|
||
|
int SocketStatus;
|
||
|
|
||
|
|
||
|
Status = ReadFile(pComPortInfo->ComPortHandle,
|
||
|
pComPortInfo->Buffer,
|
||
|
MAX_QUEUE_SIZE,
|
||
|
&(pComPortInfo->BytesRead),
|
||
|
&(pComPortInfo->Overlapped)
|
||
|
);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
TCDebugPrint(("Could not read from Com Port %x\n",GetLastError()));
|
||
|
goto end;
|
||
|
}
|
||
|
|
||
|
while(1){
|
||
|
MutexLock(pComPortInfo);
|
||
|
// Get the new sockets that have been added to the port since
|
||
|
// you were asleep. Send them the requested information and add
|
||
|
// them to the connections list so that they are primed to receive
|
||
|
// information.
|
||
|
while(pComPortInfo->Sockets != NULL){
|
||
|
pTemp = pComPortInfo->Sockets;
|
||
|
SocketStatus = 1;
|
||
|
if(pTemp->Flags){
|
||
|
SocketStatus=GetBufferInfo(pTemp, pComPortInfo);
|
||
|
pTemp->Flags = 0;
|
||
|
}
|
||
|
TCDebugPrint(("Got conn\n"));
|
||
|
pComPortInfo->Sockets = pTemp->Next;
|
||
|
pTemp->Next = pComPortInfo->Connections;
|
||
|
pComPortInfo->Connections = pTemp;
|
||
|
if (SocketStatus == SOCKET_ERROR) {
|
||
|
TCDebugPrint(("something wrong with socket %d\n",
|
||
|
WSAGetLastError()));
|
||
|
CleanupSocket(pTemp);
|
||
|
continue;
|
||
|
}
|
||
|
SocketStatus = WSARecv(pTemp->Socket,
|
||
|
&(pTemp->Buffer),
|
||
|
1 ,
|
||
|
&(pTemp->BytesRecvd),
|
||
|
&(pTemp->Flags),
|
||
|
&(pTemp->Overlapped),
|
||
|
updateComPort
|
||
|
);
|
||
|
if (SocketStatus == SOCKET_ERROR ) {
|
||
|
SocketStatus = WSAGetLastError();
|
||
|
if (SocketStatus != WSA_IO_PENDING) {
|
||
|
TCDebugPrint(("something wrong with socket %d\n",
|
||
|
SocketStatus));
|
||
|
CleanupSocket(pTemp);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
MutexRelease(pComPortInfo);
|
||
|
wait:
|
||
|
waitStatus=NtWaitForMultipleObjects(4,
|
||
|
pComPortInfo->Events,
|
||
|
WaitAny,
|
||
|
TRUE,
|
||
|
NULL
|
||
|
);
|
||
|
if(waitStatus == WAIT_FAILED){
|
||
|
TCDebugPrint(("Fatal Error %x", waitStatus));
|
||
|
closesocket(MainSocket);
|
||
|
goto end;
|
||
|
}
|
||
|
else{
|
||
|
if(waitStatus == WAIT_IO_COMPLETION){
|
||
|
goto wait;
|
||
|
}
|
||
|
waitStatus = waitStatus - WAIT_OBJECT_0;
|
||
|
switch(waitStatus){
|
||
|
case 0:
|
||
|
Status = STATUS_SUCCESS;
|
||
|
goto end;
|
||
|
break;
|
||
|
case 1:
|
||
|
ResetEvent(pComPortInfo->Events[1]);
|
||
|
break;
|
||
|
case 2:
|
||
|
ResetEvent(pComPortInfo->Events[2]);
|
||
|
updateClients(pComPortInfo);
|
||
|
goto wait;
|
||
|
break;
|
||
|
case 3:
|
||
|
Status = STATUS_SUCCESS;
|
||
|
ResetEvent(pComPortInfo->Events[3]);
|
||
|
goto end;
|
||
|
break;
|
||
|
default:
|
||
|
goto wait;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
end:
|
||
|
|
||
|
// Cancel the pending IRPs and close all the sockets.
|
||
|
TCDebugPrint(("Cancelling all irps and shutting down the thread\n"));
|
||
|
MutexLock(pComPortInfo);
|
||
|
CancelIo(pComPortInfo->ComPortHandle);
|
||
|
NtClose(pComPortInfo->ComPortHandle);
|
||
|
while(pComPortInfo->Sockets != NULL){
|
||
|
pTemp = pComPortInfo->Sockets;
|
||
|
closesocket(pTemp->Socket);
|
||
|
pComPortInfo->Sockets = pTemp->Next;
|
||
|
pTemp->Next = NULL;
|
||
|
TCFree(pTemp);
|
||
|
}
|
||
|
pTemp = pComPortInfo->Connections;
|
||
|
while(pTemp != NULL){
|
||
|
closesocket(pTemp->Socket);
|
||
|
pTemp = pTemp->Next;
|
||
|
}
|
||
|
pComPortInfo->ShuttingDown = TRUE;
|
||
|
if(pComPortInfo->Connections == NULL) SetEvent(pComPortInfo->TerminateEvent);
|
||
|
MutexRelease(pComPortInfo);
|
||
|
wait2:
|
||
|
waitStatus=NtWaitForSingleObject(pComPortInfo->TerminateEvent,TRUE,NULL);
|
||
|
if(waitStatus == WAIT_IO_COMPLETION){
|
||
|
goto wait2;
|
||
|
}
|
||
|
TCDebugPrint(("End of COM port\n"));
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CALLBACK
|
||
|
updateComPort(
|
||
|
IN DWORD dwError,
|
||
|
IN DWORD cbTransferred,
|
||
|
IN LPWSAOVERLAPPED lpOverlapped,
|
||
|
IN DWORD dwFlags
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
Writes the data that it has gotten from the socket to all the connection
|
||
|
that it currently has and to the com port.
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
|
||
|
PCONNECTION_INFO pTemp = (PCONNECTION_INFO) lpOverlapped->hEvent;
|
||
|
PCONNECTION_INFO pConn;
|
||
|
PCOM_PORT_INFO pComPort;
|
||
|
int Status;
|
||
|
|
||
|
pComPort = pTemp->pComPortInfo;
|
||
|
MutexLock(pComPort);
|
||
|
if((cbTransferred == 0) && (dwError == 0)) {
|
||
|
// For byte stream socket, this indicates graceful closure
|
||
|
CleanupSocket(pTemp);
|
||
|
MutexRelease(pComPort);
|
||
|
return;
|
||
|
}
|
||
|
// If socket closed, remove it from the connection list.
|
||
|
if(pComPort->ShuttingDown){
|
||
|
CleanupSocket(pTemp);
|
||
|
if(pComPort->Connections == NULL){
|
||
|
SetEvent(pComPort->TerminateEvent);
|
||
|
MutexRelease(pComPort);
|
||
|
return;
|
||
|
}
|
||
|
MutexRelease(pComPort);
|
||
|
return;
|
||
|
}
|
||
|
if (dwError != 0) {
|
||
|
// Something wrong with the connection. Close the socket and
|
||
|
// delete it from the listeners list.
|
||
|
CleanupSocket(pTemp);
|
||
|
MutexRelease(pComPort);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Status =WriteFile(pComPort->ComPortHandle,
|
||
|
(pTemp->Buffer).buf,
|
||
|
cbTransferred,
|
||
|
&(pTemp->BytesRecvd),
|
||
|
&(pComPort->WriteOverlapped)
|
||
|
);
|
||
|
if(!Status){
|
||
|
if(GetLastError() != ERROR_IO_PENDING)
|
||
|
TCDebugPrint(("Error writing to comport %d",GetLastError()));
|
||
|
}
|
||
|
Status = WSARecv(pTemp->Socket,
|
||
|
&(pTemp->Buffer),
|
||
|
1 ,
|
||
|
&(pTemp->BytesRecvd),
|
||
|
&(pTemp->Flags),
|
||
|
&(pTemp->Overlapped),
|
||
|
updateComPort
|
||
|
);
|
||
|
if (Status == SOCKET_ERROR ) {
|
||
|
Status = WSAGetLastError();
|
||
|
if (Status != WSA_IO_PENDING) {
|
||
|
TCDebugPrint(("something wrong with socket %d\n",
|
||
|
Status));
|
||
|
CleanupSocket(pTemp);
|
||
|
}
|
||
|
}
|
||
|
MutexRelease(pComPort);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
updateClients(
|
||
|
PCOM_PORT_INFO pComPortInfo
|
||
|
|
||
|
)
|
||
|
/*++
|
||
|
Writes the data that it has gotten from the com port to all the connection
|
||
|
that it currently has
|
||
|
--*/
|
||
|
{
|
||
|
PCONNECTION_INFO pConn;
|
||
|
BOOL Status;
|
||
|
DWORD Error;
|
||
|
NTSTATUS stat;
|
||
|
|
||
|
|
||
|
|
||
|
if((pComPortInfo->Overlapped.InternalHigh == 0)||
|
||
|
(!NT_SUCCESS(pComPortInfo->Overlapped.Internal))){
|
||
|
TCDebugPrint(("Problem with Com Port %x\n", pComPortInfo->Overlapped.Internal));
|
||
|
MutexLock(pComPortInfo);
|
||
|
if(pComPortInfo->ShuttingDown){
|
||
|
// will never occur because this is a procedure called from
|
||
|
// the thread
|
||
|
MutexRelease(pComPortInfo);
|
||
|
return;
|
||
|
}
|
||
|
if (pComPortInfo->Overlapped.Internal == STATUS_CANCELLED){
|
||
|
// something wrong, try reinitializing the com port
|
||
|
// this thing happens every time the m/c on the other end
|
||
|
// reboots. Pretty painful.Probably can improve this later.
|
||
|
// Why should the reboot cause this com port
|
||
|
// to go awry ??
|
||
|
stat = NtClose(pComPortInfo->ComPortHandle);
|
||
|
if(!NT_SUCCESS(stat)){
|
||
|
TCDebugPrint(("Cannot close handle\n"));
|
||
|
}
|
||
|
stat = InitializeComPort(pComPortInfo);
|
||
|
if(!NT_SUCCESS(stat)){
|
||
|
TCDebugPrint(("Cannot reinitialize com port\n"));
|
||
|
MutexRelease(pComPortInfo);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
Status = ReadFile(pComPortInfo->ComPortHandle,
|
||
|
pComPortInfo->Buffer,
|
||
|
MAX_QUEUE_SIZE,
|
||
|
&(pComPortInfo->BytesRead),
|
||
|
&(pComPortInfo->Overlapped)
|
||
|
);
|
||
|
if(Status == 0){
|
||
|
if ((Error = GetLastError()) != ERROR_IO_PENDING) {
|
||
|
TCDebugPrint(("Error = %d\n", Error));
|
||
|
}
|
||
|
}
|
||
|
MutexRelease(pComPortInfo);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
MutexLock(pComPortInfo);
|
||
|
Enqueue(pComPortInfo);
|
||
|
pConn = pComPortInfo->Connections;
|
||
|
while(pConn!=NULL){
|
||
|
send(pConn->Socket,
|
||
|
pComPortInfo->Buffer,
|
||
|
(int)pComPortInfo->Overlapped.InternalHigh,
|
||
|
0
|
||
|
);
|
||
|
pConn = pConn->Next;
|
||
|
}
|
||
|
Status = ReadFile(pComPortInfo->ComPortHandle,
|
||
|
pComPortInfo->Buffer,
|
||
|
MAX_QUEUE_SIZE,
|
||
|
&(pComPortInfo->BytesRead),
|
||
|
&(pComPortInfo->Overlapped)
|
||
|
);
|
||
|
if (Status == 0) {
|
||
|
if((Error=GetLastError())!= ERROR_IO_PENDING){
|
||
|
TCDebugPrint(("Problem with Com Port %x\n", Error));
|
||
|
}
|
||
|
}
|
||
|
MutexRelease(pComPortInfo);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID CleanupSocket(
|
||
|
PCONNECTION_INFO pConn
|
||
|
)
|
||
|
{
|
||
|
PCOM_PORT_INFO pTemp;
|
||
|
PCONNECTION_INFO pPrevConn;
|
||
|
|
||
|
// Assume that the structure is locked earlier.
|
||
|
// the socket connection is closed when this occurs.
|
||
|
// We free the socket either if the TCP port on the
|
||
|
// client end has died or we are deleting this com port.
|
||
|
pTemp = pConn->pComPortInfo;
|
||
|
if(pConn == pTemp->Connections) {
|
||
|
pTemp->Connections = pConn->Next;
|
||
|
}
|
||
|
else{
|
||
|
pPrevConn = pTemp->Connections;
|
||
|
while((pPrevConn !=NULL) &&(pPrevConn->Next != pConn)){
|
||
|
pPrevConn=pPrevConn->Next;
|
||
|
}
|
||
|
if(pPrevConn == NULL) return;
|
||
|
pPrevConn->Next = pConn->Next;
|
||
|
}
|
||
|
pConn->Next = NULL;
|
||
|
TCFree(pConn);
|
||
|
|
||
|
}
|
||
|
|