Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

345 lines
10 KiB

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