- Implement proper support for partial sends on TCP sockets
- This prevents a deadlock when a very very large packet is queued to be sent

svn path=/trunk/; revision=57186
This commit is contained in:
Cameron Gutman 2012-08-27 23:58:40 +00:00
parent c71cca6db6
commit f65fc45ba2
4 changed files with 40 additions and 20 deletions

View file

@ -383,6 +383,7 @@ TCPSendEventHandler(void *arg, u16_t space)
PIRP Irp; PIRP Irp;
NTSTATUS Status; NTSTATUS Status;
PMDL Mdl; PMDL Mdl;
ULONG BytesSent;
ReferenceObject(Connection); ReferenceObject(Connection);
@ -412,9 +413,9 @@ TCPSendEventHandler(void *arg, u16_t space)
Status = TCPTranslateError(LibTCPSend(Connection, Status = TCPTranslateError(LibTCPSend(Connection,
SendBuffer, SendBuffer,
SendLen, TRUE)); SendLen, &BytesSent, TRUE));
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", SendLen)); TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", BytesSent));
if( Status == STATUS_PENDING ) if( Status == STATUS_PENDING )
{ {
@ -430,7 +431,7 @@ TCPSendEventHandler(void *arg, u16_t space)
Bucket->Request, Status)); Bucket->Request, Status));
Bucket->Status = Status; Bucket->Status = Status;
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? SendLen : 0; Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? BytesSent : 0;
CompleteBucket(Connection, Bucket, FALSE); CompleteBucket(Connection, Bucket, FALSE);
} }

View file

@ -544,6 +544,7 @@ NTSTATUS TCPSendData
Status = TCPTranslateError(LibTCPSend(Connection, Status = TCPTranslateError(LibTCPSend(Connection,
BufferData, BufferData,
SendLength, SendLength,
BytesSent,
FALSE)); FALSE));
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength));
@ -562,19 +563,10 @@ NTSTATUS TCPSendData
Bucket->Request.RequestNotifyObject = Complete; Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context; Bucket->Request.RequestContext = Context;
*BytesSent = 0;
InsertTailList( &Connection->SendRequest, &Bucket->Entry ); InsertTailList( &Connection->SendRequest, &Bucket->Entry );
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n")); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n"));
} }
else if (Status == STATUS_SUCCESS)
{
*BytesSent = SendLength;
}
else
{
*BytesSent = 0;
}
UnlockObject(Connection, OldIrql); UnlockObject(Connection, OldIrql);

View file

@ -72,6 +72,7 @@ struct lwip_callback_msg
} Listen; } Listen;
struct { struct {
err_t Error; err_t Error;
u32_t Information;
} Send; } Send;
struct { struct {
err_t Error; err_t Error;
@ -98,7 +99,7 @@ extern void TCPRecvEventHandler(void *arg);
PTCP_PCB LibTCPSocket(void *arg); PTCP_PCB LibTCPSocket(void *arg);
err_t LibTCPBind(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port); err_t LibTCPBind(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port);
PTCP_PCB LibTCPListen(PCONNECTION_ENDPOINT Connection, const u8_t backlog); PTCP_PCB LibTCPListen(PCONNECTION_ENDPOINT Connection, const u8_t backlog);
err_t LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, const int safe); err_t LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, u32_t *sent, const int safe);
err_t LibTCPConnect(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port); err_t LibTCPConnect(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port);
err_t LibTCPShutdown(PCONNECTION_ENDPOINT Connection, const int shut_rx, const int shut_tx); err_t LibTCPShutdown(PCONNECTION_ENDPOINT Connection, const int shut_rx, const int shut_tx);
err_t LibTCPClose(PCONNECTION_ENDPOINT Connection, const int safe, const int callback); err_t LibTCPClose(PCONNECTION_ENDPOINT Connection, const int safe, const int callback);

View file

@ -443,6 +443,9 @@ void
LibTCPSendCallback(void *arg) LibTCPSendCallback(void *arg)
{ {
struct lwip_callback_msg *msg = arg; struct lwip_callback_msg *msg = arg;
PTCP_PCB pcb = msg->Input.Send.Connection->SocketContext;
ULONG SendLength;
UCHAR SendFlags;
ASSERT(msg); ASSERT(msg);
@ -458,19 +461,37 @@ LibTCPSendCallback(void *arg)
goto done; goto done;
} }
msg->Output.Send.Error = tcp_write((PTCP_PCB)msg->Input.Send.Connection->SocketContext, SendFlags = TCP_WRITE_FLAG_COPY;
msg->Input.Send.Data, SendLength = msg->Input.Send.DataLength;
msg->Input.Send.DataLength, if (tcp_sndbuf(pcb) == 0)
TCP_WRITE_FLAG_COPY);
if (msg->Output.Send.Error == ERR_MEM)
{ {
/* No buffer space so return pending */ /* No buffer space so return pending */
msg->Output.Send.Error = ERR_INPROGRESS; msg->Output.Send.Error = ERR_INPROGRESS;
goto done;
} }
else if (msg->Output.Send.Error == ERR_OK) else if (tcp_sndbuf(pcb) < SendLength)
{
/* We've got some room so let's send what we can */
SendLength = tcp_sndbuf(pcb);
/* Don't set the push flag */
SendFlags |= TCP_WRITE_FLAG_MORE;
}
msg->Output.Send.Error = tcp_write(pcb,
msg->Input.Send.Data,
SendLength,
SendFlags);
if (msg->Output.Send.Error == ERR_OK)
{ {
/* Queued successfully so try to send it */ /* Queued successfully so try to send it */
tcp_output((PTCP_PCB)msg->Input.Send.Connection->SocketContext); tcp_output((PTCP_PCB)msg->Input.Send.Connection->SocketContext);
msg->Output.Send.Information = SendLength;
}
else if (msg->Output.Send.Error == ERR_MEM)
{
/* The queue is too long */
msg->Output.Send.Error = ERR_INPROGRESS;
} }
done: done:
@ -478,7 +499,7 @@ done:
} }
err_t err_t
LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, const int safe) LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, u32_t *sent, const int safe)
{ {
err_t ret; err_t ret;
struct lwip_callback_msg *msg; struct lwip_callback_msg *msg;
@ -501,6 +522,11 @@ LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len
else else
ret = ERR_CLSD; ret = ERR_CLSD;
if (ret == ERR_OK)
*sent = msg->Output.Send.Information;
else
*sent = 0;
ExFreeToNPagedLookasideList(&MessageLookasideList, msg); ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
return ret; return ret;