static err_t InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; /* Make sure the socket didn't get closed */ if (!arg) { if (p) pbuf_free(p); return ERR_OK; } if (p) { LibTCPEnqueuePacket(Connection, p); tcp_recved(pcb, p->tot_len); TCPRecvEventHandler(arg); } else if (err == ERR_OK) { /* Complete pending reads with 0 bytes to indicate a graceful closure, * but note that send is still possible in this state so we don't close the * whole socket here (by calling tcp_close()) as that would violate TCP specs */ Connection->ReceiveShutdown = TRUE; Connection->ReceiveShutdownStatus = STATUS_SUCCESS; /* If we already did a send shutdown, we're in TIME_WAIT so we can't use this PCB anymore */ if (Connection->SendShutdown) { Connection->SocketContext = NULL; tcp_arg(pcb, NULL); } /* Indicate the graceful close event */ TCPRecvEventHandler(arg); /* If the PCB is gone, clean up the connection */ if (Connection->SendShutdown) { TCPFinEventHandler(Connection, ERR_CLSD); } } return ERR_OK; }
static err_t InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; /* Make sure the socket didn't get closed */ if (!arg) { if (p) pbuf_free(p); return ERR_OK; } if (p) { LibTCPEnqueuePacket(Connection, p); tcp_recved(pcb, p->tot_len); TCPRecvEventHandler(arg); } else if (err == ERR_OK) { /* Complete pending reads with 0 bytes to indicate a graceful closure, * but note that send is still possible in this state so we don't close the * whole socket here (by calling tcp_close()) as that would violate TCP specs */ Connection->ReceiveShutdown = TRUE; Connection->ReceiveShutdownStatus = STATUS_SUCCESS; /* This code path executes for both remotely and locally initiated closures, * and we need to distinguish between them */ if (Connection->SocketContext) { /* Remotely initiated close */ TCPRecvEventHandler(arg); } else { /* Locally initated close */ TCPFinEventHandler(arg, ERR_CLSD); } } return ERR_OK; }
static void InternalErrorEventHandler(void *arg, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; KIRQL OldIrql; /* Make sure the socket didn't get closed */ if (!arg) return; /* Check if data is left to be read */ LockObject(Connection, &OldIrql); if (IsListEmpty(&Connection->PacketQueue)) { UnlockObject(Connection, OldIrql); /* Deliver the error now */ TCPFinEventHandler(arg, err); } else { UnlockObject(Connection, OldIrql); /* Defer the error delivery until all data is gone */ Connection->ReceiveShutdown = TRUE; Connection->ReceiveShutdownStatus = TCPTranslateError(err); TCPRecvEventHandler(arg); } }
static void InternalErrorEventHandler(void *arg, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; /* Make sure the socket didn't get closed */ if (!arg || Connection->SocketContext == NULL) return; /* The PCB is dead now */ Connection->SocketContext = NULL; /* Give them one shot to receive the remaining data */ Connection->ReceiveShutdown = TRUE; Connection->ReceiveShutdownStatus = TCPTranslateError(err); TCPRecvEventHandler(Connection); /* Terminate the connection */ TCPFinEventHandler(Connection, err); }