2010-09-21 06:11:24 +00:00
|
|
|
#include "lwip/sys.h"
|
|
|
|
#include "lwip/tcpip.h"
|
|
|
|
|
|
|
|
#include "rosip.h"
|
|
|
|
|
|
|
|
#include <debug.h>
|
|
|
|
|
2011-05-24 18:05:51 +00:00
|
|
|
static const char * const tcp_state_str[] = {
|
|
|
|
"CLOSED",
|
|
|
|
"LISTEN",
|
|
|
|
"SYN_SENT",
|
|
|
|
"SYN_RCVD",
|
|
|
|
"ESTABLISHED",
|
|
|
|
"FIN_WAIT_1",
|
|
|
|
"FIN_WAIT_2",
|
|
|
|
"CLOSE_WAIT",
|
|
|
|
"CLOSING",
|
|
|
|
"LAST_ACK",
|
|
|
|
"TIME_WAIT"
|
|
|
|
};
|
|
|
|
|
2010-09-21 06:11:24 +00:00
|
|
|
/* The way that lwIP does multi-threading is really not ideal for our purposes but
|
|
|
|
* we best go along with it unless we want another unstable TCP library. lwIP uses
|
|
|
|
* a thread called the "tcpip thread" which is the only one allowed to call raw API
|
|
|
|
* functions. Since this is the case, for each of our LibTCP* functions, we queue a request
|
|
|
|
* for a callback to "tcpip thread" which calls our LibTCP*Callback functions. Yes, this is
|
|
|
|
* a lot of unnecessary thread swapping and it could definitely be faster, but I don't want
|
|
|
|
* to going messing around in lwIP because I have no desire to create another mess like oskittcp */
|
|
|
|
|
|
|
|
extern KEVENT TerminationEvent;
|
|
|
|
|
2011-07-25 18:45:59 +00:00
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPEmptyQueue(PCONNECTION_ENDPOINT Connection)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY Entry;
|
|
|
|
PQUEUE_ENTRY qp = NULL;
|
|
|
|
|
|
|
|
ReferenceObject(Connection);
|
|
|
|
|
|
|
|
|
|
|
|
while (!IsListEmpty(&Connection->PacketQueue))
|
|
|
|
{
|
|
|
|
Entry = RemoveHeadList(&Connection->PacketQueue);
|
|
|
|
qp = CONTAINING_RECORD(Entry, QUEUE_ENTRY, ListEntry);
|
2011-08-01 20:10:55 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
/* We're in the tcpip thread here so this is safe */
|
2011-07-26 11:25:24 +00:00
|
|
|
pbuf_free(qp->p);
|
2011-07-25 18:45:59 +00:00
|
|
|
|
|
|
|
ExFreePoolWithTag(qp, LWIP_TAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
DereferenceObject(Connection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LibTCPEnqueuePacket(PCONNECTION_ENDPOINT Connection, struct pbuf *p)
|
|
|
|
{
|
|
|
|
PQUEUE_ENTRY qp;
|
|
|
|
|
|
|
|
qp = (PQUEUE_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(QUEUE_ENTRY), LWIP_TAG);
|
|
|
|
qp->p = p;
|
|
|
|
|
|
|
|
ExInterlockedInsertTailList(&Connection->PacketQueue, &qp->ListEntry, &Connection->Lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
PQUEUE_ENTRY LibTCPDequeuePacket(PCONNECTION_ENDPOINT Connection)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY Entry;
|
|
|
|
PQUEUE_ENTRY qp = NULL;
|
|
|
|
|
|
|
|
Entry = ExInterlockedRemoveHeadList(&Connection->PacketQueue, &Connection->Lock);
|
|
|
|
|
|
|
|
qp = CONTAINING_RECORD(Entry, QUEUE_ENTRY, ListEntry);
|
|
|
|
|
|
|
|
return qp;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHAR RecvBuffer, UINT RecvLen, UINT *Received)
|
|
|
|
{
|
|
|
|
PQUEUE_ENTRY qp;
|
|
|
|
struct pbuf* p;
|
|
|
|
NTSTATUS Status = STATUS_PENDING;
|
|
|
|
|
|
|
|
if (!IsListEmpty(&Connection->PacketQueue))
|
|
|
|
{
|
|
|
|
qp = LibTCPDequeuePacket(Connection);
|
|
|
|
p = qp->p;
|
|
|
|
|
|
|
|
RecvLen = MIN(p->tot_len, RecvLen);
|
|
|
|
|
2011-07-26 11:25:24 +00:00
|
|
|
for ((*Received) = 0; (*Received) < RecvLen; (*Received) += p->len, p = p->next)
|
2011-07-25 18:45:59 +00:00
|
|
|
{
|
|
|
|
RtlCopyMemory(RecvBuffer + (*Received), p->payload, p->len);
|
|
|
|
}
|
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
/* Use this special pbuf free callback function because we're outside tcpip thread */
|
|
|
|
pbuf_free_callback(qp->p);
|
|
|
|
|
2011-07-25 18:45:59 +00:00
|
|
|
ExFreePoolWithTag(qp, LWIP_TAG);
|
|
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = STATUS_PENDING;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2010-09-21 06:11:24 +00:00
|
|
|
static
|
|
|
|
BOOLEAN
|
|
|
|
WaitForEventSafely(PRKEVENT Event)
|
|
|
|
{
|
|
|
|
PVOID WaitObjects[] = {Event, &TerminationEvent};
|
|
|
|
|
|
|
|
if (KeWaitForMultipleObjects(2,
|
|
|
|
WaitObjects,
|
|
|
|
WaitAny,
|
|
|
|
Executive,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL,
|
|
|
|
NULL) == STATUS_WAIT_0)
|
|
|
|
{
|
|
|
|
/* Signalled by the caller's event */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else /* if KeWaitForMultipleObjects() == STATUS_WAIT_1 */
|
|
|
|
{
|
|
|
|
/* Signalled by our termination event */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
err_t
|
2011-07-25 18:45:59 +00:00
|
|
|
InternalSendEventHandler(void *arg, PTCP_PCB pcb, const u16_t space)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
/* Make sure the socket didn't get closed */
|
|
|
|
if (!arg) return ERR_OK;
|
|
|
|
|
|
|
|
TCPSendEventHandler(arg, space);
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
err_t
|
2011-07-25 18:45:59 +00:00
|
|
|
InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t err)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
u32_t len;
|
|
|
|
|
|
|
|
/* Make sure the socket didn't get closed */
|
|
|
|
if (!arg)
|
|
|
|
{
|
2011-06-22 15:32:46 +00:00
|
|
|
if (p)
|
|
|
|
pbuf_free(p);
|
|
|
|
|
2010-09-21 06:11:24 +00:00
|
|
|
return ERR_OK;
|
|
|
|
}
|
|
|
|
|
2011-06-12 19:21:56 +00:00
|
|
|
if (p)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
2011-06-12 19:21:56 +00:00
|
|
|
len = TCPRecvEventHandler(arg, p);
|
|
|
|
if (len == p->tot_len)
|
|
|
|
{
|
|
|
|
tcp_recved(pcb, len);
|
|
|
|
|
|
|
|
pbuf_free(p);
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
}
|
|
|
|
else if (len != 0)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
2011-06-12 19:21:56 +00:00
|
|
|
DbgPrint("UNTESTED CASE: NOT ALL DATA TAKEN! EXTRA DATA MAY BE LOST!\n");
|
|
|
|
|
|
|
|
tcp_recved(pcb, len);
|
|
|
|
|
|
|
|
/* Possible memory leak of pbuf here? */
|
|
|
|
|
|
|
|
return ERR_OK;
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-07-25 18:45:59 +00:00
|
|
|
LibTCPEnqueuePacket((PCONNECTION_ENDPOINT)arg, p);
|
|
|
|
|
|
|
|
tcp_recved(pcb, p->tot_len);
|
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
return ERR_OK;
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-12 19:21:56 +00:00
|
|
|
else if (err == ERR_OK)
|
|
|
|
{
|
2011-07-10 00:38:29 +00:00
|
|
|
/* 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
|
|
|
|
*/
|
2011-06-12 19:21:56 +00:00
|
|
|
TCPFinEventHandler(arg, ERR_OK);
|
|
|
|
}
|
2010-09-21 06:11:24 +00:00
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
err_t
|
2011-07-25 18:45:59 +00:00
|
|
|
InternalAcceptEventHandler(void *arg, PTCP_PCB newpcb, const err_t err)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
/* Make sure the socket didn't get closed */
|
2011-05-24 18:05:51 +00:00
|
|
|
if (!arg)
|
|
|
|
return ERR_ABRT;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
|
|
|
TCPAcceptEventHandler(arg, newpcb);
|
|
|
|
|
|
|
|
/* Set in LibTCPAccept (called from TCPAcceptEventHandler) */
|
|
|
|
if (newpcb->callback_arg)
|
|
|
|
return ERR_OK;
|
|
|
|
else
|
|
|
|
return ERR_ABRT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
err_t
|
2011-07-25 18:45:59 +00:00
|
|
|
InternalConnectEventHandler(void *arg, PTCP_PCB pcb, const err_t err)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
/* Make sure the socket didn't get closed */
|
2011-05-24 18:05:51 +00:00
|
|
|
if (!arg)
|
|
|
|
return ERR_OK;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
|
|
|
TCPConnectEventHandler(arg, err);
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
2011-07-11 17:33:17 +00:00
|
|
|
InternalErrorEventHandler(void *arg, const err_t err)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
/* Make sure the socket didn't get closed */
|
|
|
|
if (!arg) return;
|
|
|
|
|
|
|
|
TCPFinEventHandler(arg, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct socket_callback_msg
|
|
|
|
{
|
|
|
|
/* Synchronization */
|
|
|
|
KEVENT Event;
|
|
|
|
|
|
|
|
/* Input */
|
|
|
|
PVOID Arg;
|
|
|
|
|
|
|
|
/* Output */
|
2011-06-20 15:59:49 +00:00
|
|
|
struct tcp_pcb *NewPcb;
|
2010-09-21 06:11:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPSocketCallback(void *arg)
|
|
|
|
{
|
|
|
|
struct socket_callback_msg *msg = arg;
|
|
|
|
|
|
|
|
ASSERT(msg);
|
|
|
|
|
|
|
|
msg->NewPcb = tcp_new();
|
|
|
|
|
|
|
|
if (msg->NewPcb)
|
|
|
|
{
|
2011-06-20 15:59:49 +00:00
|
|
|
tcp_arg(msg->NewPcb, msg->Arg);
|
|
|
|
tcp_err(msg->NewPcb, InternalErrorEventHandler);
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tcp_pcb *
|
|
|
|
LibTCPSocket(void *arg)
|
|
|
|
{
|
|
|
|
struct socket_callback_msg *msg = ExAllocatePool(NonPagedPool, sizeof(struct socket_callback_msg));
|
2011-06-20 15:59:49 +00:00
|
|
|
struct tcp_pcb *ret;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
|
|
|
if (msg)
|
|
|
|
{
|
|
|
|
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
|
|
|
msg->Arg = arg;
|
|
|
|
|
|
|
|
tcpip_callback_with_block(LibTCPSocketCallback, msg, 1);
|
|
|
|
|
|
|
|
if (WaitForEventSafely(&msg->Event))
|
|
|
|
ret = msg->NewPcb;
|
|
|
|
else
|
|
|
|
ret = NULL;
|
|
|
|
|
|
|
|
ExFreePool(msg);
|
|
|
|
|
2011-06-20 15:59:49 +00:00
|
|
|
return ret;
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bind_callback_msg
|
|
|
|
{
|
|
|
|
/* Synchronization */
|
|
|
|
KEVENT Event;
|
|
|
|
|
|
|
|
/* Input */
|
2011-07-21 20:58:54 +00:00
|
|
|
PCONNECTION_ENDPOINT Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
struct ip_addr *IpAddress;
|
|
|
|
u16_t Port;
|
|
|
|
|
|
|
|
/* Output */
|
|
|
|
err_t Error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPBindCallback(void *arg)
|
|
|
|
{
|
|
|
|
struct bind_callback_msg *msg = arg;
|
|
|
|
|
|
|
|
ASSERT(msg);
|
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
if (!msg->Connection->SocketContext)
|
|
|
|
{
|
|
|
|
msg->Error = ERR_CLSD;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Error = tcp_bind((PTCP_PCB)msg->Connection->SocketContext,
|
|
|
|
msg->IpAddress,
|
|
|
|
ntohs(msg->Port));
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
done:
|
2010-09-21 06:11:24 +00:00
|
|
|
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
err_t
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPBind(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
struct bind_callback_msg *msg;
|
|
|
|
err_t ret;
|
|
|
|
|
|
|
|
msg = ExAllocatePool(NonPagedPool, sizeof(struct bind_callback_msg));
|
|
|
|
if (msg)
|
|
|
|
{
|
|
|
|
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Connection = Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
msg->IpAddress = ipaddr;
|
|
|
|
msg->Port = port;
|
|
|
|
|
|
|
|
tcpip_callback_with_block(LibTCPBindCallback, msg, 1);
|
|
|
|
|
|
|
|
if (WaitForEventSafely(&msg->Event))
|
|
|
|
ret = msg->Error;
|
|
|
|
else
|
|
|
|
ret = ERR_CLSD;
|
|
|
|
|
|
|
|
ExFreePool(msg);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERR_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct listen_callback_msg
|
|
|
|
{
|
|
|
|
/* Synchronization */
|
|
|
|
KEVENT Event;
|
|
|
|
|
|
|
|
/* Input */
|
2011-07-21 20:58:54 +00:00
|
|
|
PCONNECTION_ENDPOINT Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
u8_t Backlog;
|
|
|
|
|
|
|
|
/* Output */
|
2011-07-21 20:58:54 +00:00
|
|
|
PTCP_PCB NewPcb;
|
2010-09-21 06:11:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPListenCallback(void *arg)
|
|
|
|
{
|
|
|
|
struct listen_callback_msg *msg = arg;
|
|
|
|
|
|
|
|
ASSERT(msg);
|
2011-08-02 19:20:40 +00:00
|
|
|
|
|
|
|
if (!msg->Connection->SocketContext)
|
|
|
|
{
|
|
|
|
msg->NewPcb = NULL;
|
|
|
|
goto done;
|
|
|
|
}
|
2011-06-20 14:49:58 +00:00
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->NewPcb = tcp_listen_with_backlog((PTCP_PCB)msg->Connection->SocketContext, msg->Backlog);
|
2010-09-21 06:11:24 +00:00
|
|
|
|
|
|
|
if (msg->NewPcb)
|
|
|
|
{
|
|
|
|
tcp_accept(msg->NewPcb, InternalAcceptEventHandler);
|
|
|
|
}
|
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
done:
|
2010-09-21 06:11:24 +00:00
|
|
|
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
PTCP_PCB
|
|
|
|
LibTCPListen(PCONNECTION_ENDPOINT Connection, const u8_t backlog)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
struct listen_callback_msg *msg;
|
2011-07-21 20:58:54 +00:00
|
|
|
PTCP_PCB ret;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
|
|
|
msg = ExAllocatePool(NonPagedPool, sizeof(struct listen_callback_msg));
|
|
|
|
if (msg)
|
|
|
|
{
|
|
|
|
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Connection = Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
msg->Backlog = backlog;
|
|
|
|
|
|
|
|
tcpip_callback_with_block(LibTCPListenCallback, msg, 1);
|
|
|
|
|
|
|
|
if (WaitForEventSafely(&msg->Event))
|
|
|
|
ret = msg->NewPcb;
|
|
|
|
else
|
|
|
|
ret = NULL;
|
|
|
|
|
|
|
|
ExFreePool(msg);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct send_callback_msg
|
|
|
|
{
|
|
|
|
/* Synchronization */
|
|
|
|
KEVENT Event;
|
|
|
|
|
|
|
|
/* Input */
|
2011-07-21 20:58:54 +00:00
|
|
|
PCONNECTION_ENDPOINT Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
void *Data;
|
|
|
|
u16_t DataLength;
|
|
|
|
|
|
|
|
/* Output */
|
|
|
|
err_t Error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPSendCallback(void *arg)
|
|
|
|
{
|
|
|
|
struct send_callback_msg *msg = arg;
|
|
|
|
|
|
|
|
ASSERT(msg);
|
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
if (!msg->Connection->SocketContext)
|
|
|
|
{
|
|
|
|
msg->Error = ERR_CLSD;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
if (tcp_sndbuf((PTCP_PCB)msg->Connection->SocketContext) < msg->DataLength)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
msg->Error = ERR_INPROGRESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Error = tcp_write((PTCP_PCB)msg->Connection->SocketContext,
|
|
|
|
msg->Data,
|
|
|
|
msg->DataLength,
|
|
|
|
TCP_WRITE_FLAG_COPY);
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
tcp_output((PTCP_PCB)msg->Connection->SocketContext);
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
done:
|
2010-09-21 06:11:24 +00:00
|
|
|
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
err_t
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, const int safe)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
err_t ret;
|
2011-08-02 19:20:40 +00:00
|
|
|
struct send_callback_msg *msg;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
msg = ExAllocatePool(NonPagedPool, sizeof(struct send_callback_msg));
|
|
|
|
if (msg)
|
2011-07-11 12:36:07 +00:00
|
|
|
{
|
2011-08-02 19:20:40 +00:00
|
|
|
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
|
|
|
msg->Connection = Connection;
|
|
|
|
msg->Data = dataptr;
|
|
|
|
msg->DataLength = len;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
if (safe)
|
|
|
|
LibTCPSendCallback(msg);
|
|
|
|
else
|
2011-07-11 12:36:07 +00:00
|
|
|
tcpip_callback_with_block(LibTCPSendCallback, msg, 1);
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
if (WaitForEventSafely(&msg->Event))
|
|
|
|
ret = msg->Error;
|
|
|
|
else
|
|
|
|
ret = ERR_CLSD;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
ExFreePool(msg);
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
return ret;
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERR_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct connect_callback_msg
|
|
|
|
{
|
|
|
|
/* Synchronization */
|
|
|
|
KEVENT Event;
|
|
|
|
|
|
|
|
/* Input */
|
2011-07-21 20:58:54 +00:00
|
|
|
PCONNECTION_ENDPOINT Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
struct ip_addr *IpAddress;
|
|
|
|
u16_t Port;
|
|
|
|
|
|
|
|
/* Output */
|
|
|
|
err_t Error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPConnectCallback(void *arg)
|
|
|
|
{
|
|
|
|
struct connect_callback_msg *msg = arg;
|
|
|
|
|
|
|
|
ASSERT(arg);
|
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
if (!msg->Connection->SocketContext)
|
|
|
|
{
|
|
|
|
msg->Error = ERR_CLSD;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
tcp_recv((PTCP_PCB)msg->Connection->SocketContext, InternalRecvEventHandler);
|
|
|
|
tcp_sent((PTCP_PCB)msg->Connection->SocketContext, InternalSendEventHandler);
|
|
|
|
|
|
|
|
err_t Error = tcp_connect((PTCP_PCB)msg->Connection->SocketContext,
|
|
|
|
msg->IpAddress, ntohs(msg->Port),
|
|
|
|
InternalConnectEventHandler);
|
2011-07-11 12:36:07 +00:00
|
|
|
|
2011-06-23 07:57:59 +00:00
|
|
|
msg->Error = Error == ERR_OK ? ERR_INPROGRESS : Error;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
done:
|
2010-09-21 06:11:24 +00:00
|
|
|
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
err_t
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPConnect(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
struct connect_callback_msg *msg;
|
|
|
|
err_t ret;
|
|
|
|
|
|
|
|
msg = ExAllocatePool(NonPagedPool, sizeof(struct connect_callback_msg));
|
|
|
|
if (msg)
|
|
|
|
{
|
|
|
|
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Connection = Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
msg->IpAddress = ipaddr;
|
|
|
|
msg->Port = port;
|
|
|
|
|
|
|
|
tcpip_callback_with_block(LibTCPConnectCallback, msg, 1);
|
|
|
|
|
|
|
|
if (WaitForEventSafely(&msg->Event))
|
2011-06-22 15:32:46 +00:00
|
|
|
{
|
2010-09-21 06:11:24 +00:00
|
|
|
ret = msg->Error;
|
2011-06-22 15:32:46 +00:00
|
|
|
}
|
2010-09-21 06:11:24 +00:00
|
|
|
else
|
|
|
|
ret = ERR_CLSD;
|
|
|
|
|
|
|
|
ExFreePool(msg);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERR_MEM;
|
|
|
|
}
|
|
|
|
|
2011-06-12 18:25:16 +00:00
|
|
|
struct shutdown_callback_msg
|
|
|
|
{
|
|
|
|
/* Synchronization */
|
|
|
|
KEVENT Event;
|
|
|
|
|
|
|
|
/* Input */
|
2011-07-21 20:58:54 +00:00
|
|
|
PCONNECTION_ENDPOINT Connection;
|
2011-06-12 18:25:16 +00:00
|
|
|
int shut_rx;
|
|
|
|
int shut_tx;
|
|
|
|
|
|
|
|
/* Output */
|
|
|
|
err_t Error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPShutdownCallback(void *arg)
|
|
|
|
{
|
|
|
|
struct shutdown_callback_msg *msg = arg;
|
2011-08-02 19:20:40 +00:00
|
|
|
|
|
|
|
if (!msg->Connection->SocketContext)
|
|
|
|
{
|
|
|
|
msg->Error = ERR_CLSD;
|
|
|
|
goto done;
|
|
|
|
}
|
2011-07-18 19:20:12 +00:00
|
|
|
|
2011-07-20 11:11:40 +00:00
|
|
|
/*
|
|
|
|
We check here if the pcb is in state ESTABLISHED or SYN_RECV because otherwise
|
|
|
|
it means lwIP will take care of it anyway and if it does so before us it will
|
|
|
|
cause memory corruption.
|
|
|
|
*/
|
2011-07-21 20:58:54 +00:00
|
|
|
if ((((PTCP_PCB)msg->Connection->SocketContext)->state == ESTABLISHED) ||
|
|
|
|
(((PTCP_PCB)msg->Connection->SocketContext)->state == SYN_RCVD))
|
2011-07-18 19:20:12 +00:00
|
|
|
{
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Error =
|
|
|
|
tcp_shutdown((PTCP_PCB)msg->Connection->SocketContext,
|
|
|
|
msg->shut_rx, msg->shut_tx);
|
2011-07-18 19:20:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
msg->Error = ERR_OK;
|
2011-06-12 18:25:16 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
done:
|
2011-06-12 18:25:16 +00:00
|
|
|
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
err_t
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPShutdown(PCONNECTION_ENDPOINT Connection, const int shut_rx, const int shut_tx)
|
2011-06-12 18:25:16 +00:00
|
|
|
{
|
|
|
|
struct shutdown_callback_msg *msg;
|
|
|
|
err_t ret;
|
2011-07-17 12:32:33 +00:00
|
|
|
|
2011-06-12 18:25:16 +00:00
|
|
|
msg = ExAllocatePool(NonPagedPool, sizeof(struct shutdown_callback_msg));
|
|
|
|
if (msg)
|
|
|
|
{
|
|
|
|
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Connection = Connection;
|
2011-06-12 18:25:16 +00:00
|
|
|
msg->shut_rx = shut_rx;
|
|
|
|
msg->shut_tx = shut_tx;
|
|
|
|
|
|
|
|
tcpip_callback_with_block(LibTCPShutdownCallback, msg, 1);
|
|
|
|
|
|
|
|
if (WaitForEventSafely(&msg->Event))
|
|
|
|
ret = msg->Error;
|
|
|
|
else
|
|
|
|
ret = ERR_CLSD;
|
|
|
|
|
|
|
|
ExFreePool(msg);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERR_MEM;
|
|
|
|
}
|
|
|
|
|
2010-09-21 06:11:24 +00:00
|
|
|
struct close_callback_msg
|
|
|
|
{
|
|
|
|
/* Synchronization */
|
|
|
|
KEVENT Event;
|
|
|
|
|
|
|
|
/* Input */
|
2011-07-21 20:58:54 +00:00
|
|
|
PCONNECTION_ENDPOINT Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
|
|
|
/* Output */
|
|
|
|
err_t Error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
LibTCPCloseCallback(void *arg)
|
|
|
|
{
|
|
|
|
struct close_callback_msg *msg = arg;
|
2011-07-21 20:58:54 +00:00
|
|
|
|
|
|
|
if (!msg->Connection->SocketContext)
|
2011-07-20 11:11:40 +00:00
|
|
|
{
|
|
|
|
msg->Error = ERR_OK;
|
2011-08-02 19:20:40 +00:00
|
|
|
goto done;
|
2011-07-20 11:11:40 +00:00
|
|
|
}
|
|
|
|
|
2011-07-25 18:45:59 +00:00
|
|
|
LibTCPEmptyQueue(msg->Connection);
|
|
|
|
|
2011-07-21 20:58:54 +00:00
|
|
|
if (((PTCP_PCB)msg->Connection->SocketContext)->state == LISTEN)
|
2011-06-20 21:37:32 +00:00
|
|
|
{
|
2011-07-21 20:58:54 +00:00
|
|
|
msg->Error = tcp_close((PTCP_PCB)msg->Connection->SocketContext);
|
2011-06-20 21:37:32 +00:00
|
|
|
}
|
2011-07-18 19:20:12 +00:00
|
|
|
else
|
2011-06-20 21:37:32 +00:00
|
|
|
{
|
2011-07-21 20:58:54 +00:00
|
|
|
tcp_abort((PTCP_PCB)msg->Connection->SocketContext);
|
2011-06-20 21:37:32 +00:00
|
|
|
msg->Error = ERR_OK;
|
|
|
|
}
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
done:
|
2010-09-21 06:11:24 +00:00
|
|
|
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
err_t
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPClose(PCONNECTION_ENDPOINT Connection, const int safe)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
err_t ret;
|
2011-08-02 19:20:40 +00:00
|
|
|
struct close_callback_msg *msg;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
msg = ExAllocatePool(NonPagedPool, sizeof(struct close_callback_msg));
|
|
|
|
if (msg)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
2011-08-02 19:20:40 +00:00
|
|
|
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
2011-07-25 18:45:59 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
msg->Connection = Connection;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
if (safe)
|
|
|
|
LibTCPCloseCallback(msg);
|
|
|
|
else
|
2011-07-11 12:36:07 +00:00
|
|
|
tcpip_callback_with_block(LibTCPCloseCallback, msg, 1);
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
if (WaitForEventSafely(&msg->Event))
|
|
|
|
ret = msg->Error;
|
|
|
|
else
|
|
|
|
ret = ERR_CLSD;
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
ExFreePool(msg);
|
2010-09-21 06:11:24 +00:00
|
|
|
|
2011-08-02 19:20:40 +00:00
|
|
|
return ret;
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
2011-06-01 13:27:35 +00:00
|
|
|
|
2010-09-21 06:11:24 +00:00
|
|
|
return ERR_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPAccept(PTCP_PCB pcb, struct tcp_pcb *listen_pcb, void *arg)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
ASSERT(arg);
|
|
|
|
|
|
|
|
tcp_arg(pcb, NULL);
|
|
|
|
tcp_recv(pcb, InternalRecvEventHandler);
|
|
|
|
tcp_sent(pcb, InternalSendEventHandler);
|
2011-06-20 15:59:49 +00:00
|
|
|
tcp_err(pcb, InternalErrorEventHandler);
|
2010-09-21 06:11:24 +00:00
|
|
|
tcp_arg(pcb, arg);
|
|
|
|
|
2011-05-26 17:42:00 +00:00
|
|
|
tcp_accepted(listen_pcb);
|
2010-09-21 06:11:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err_t
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPGetHostName(PTCP_PCB pcb, struct ip_addr *const ipaddr, u16_t *const port)
|
2010-09-21 06:11:24 +00:00
|
|
|
{
|
|
|
|
if (!pcb)
|
|
|
|
return ERR_CLSD;
|
|
|
|
|
|
|
|
*ipaddr = pcb->local_ip;
|
|
|
|
*port = pcb->local_port;
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
err_t
|
2011-07-21 20:58:54 +00:00
|
|
|
LibTCPGetPeerName(PTCP_PCB pcb, struct ip_addr * const ipaddr, u16_t * const port)
|
2011-08-02 19:20:40 +00:00
|
|
|
{
|
2010-09-21 06:11:24 +00:00
|
|
|
if (!pcb)
|
|
|
|
return ERR_CLSD;
|
|
|
|
|
|
|
|
*ipaddr = pcb->remote_ip;
|
|
|
|
*port = pcb->remote_port;
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
}
|