ea06d75a7f477266ef192526f3a689b227c418c7
[reactos.git] / sdk / lib / drivers / lwip / src / rostcp.c
1 #include "lwip/sys.h"
2 #include "lwip/netif.h"
3 #include "lwip/tcpip.h"
4
5 #include "rosip.h"
6
7 #include <debug.h>
8
9 static const char * const tcp_state_str[] = {
10 "CLOSED",
11 "LISTEN",
12 "SYN_SENT",
13 "SYN_RCVD",
14 "ESTABLISHED",
15 "FIN_WAIT_1",
16 "FIN_WAIT_2",
17 "CLOSE_WAIT",
18 "CLOSING",
19 "LAST_ACK",
20 "TIME_WAIT"
21 };
22
23 /* The way that lwIP does multi-threading is really not ideal for our purposes but
24 * we best go along with it unless we want another unstable TCP library. lwIP uses
25 * a thread called the "tcpip thread" which is the only one allowed to call raw API
26 * functions. Since this is the case, for each of our LibTCP* functions, we queue a request
27 * for a callback to "tcpip thread" which calls our LibTCP*Callback functions. Yes, this is
28 * a lot of unnecessary thread swapping and it could definitely be faster, but I don't want
29 * to going messing around in lwIP because I have no desire to create another mess like oskittcp */
30
31 extern KEVENT TerminationEvent;
32 extern NPAGED_LOOKASIDE_LIST MessageLookasideList;
33 extern NPAGED_LOOKASIDE_LIST QueueEntryLookasideList;
34
35 /* Required for ERR_T to NTSTATUS translation in receive error handling */
36 NTSTATUS TCPTranslateError(const err_t err);
37
38 void
39 LibTCPDumpPcb(PVOID SocketContext)
40 {
41 struct tcp_pcb *pcb = (struct tcp_pcb*)SocketContext;
42 unsigned int addr = ntohl(pcb->remote_ip.addr);
43
44 DbgPrint("\tState: %s\n", tcp_state_str[pcb->state]);
45 DbgPrint("\tRemote: (%d.%d.%d.%d, %d)\n",
46 (addr >> 24) & 0xFF,
47 (addr >> 16) & 0xFF,
48 (addr >> 8) & 0xFF,
49 addr & 0xFF,
50 pcb->remote_port);
51 }
52
53 static
54 void
55 LibTCPEmptyQueue(PCONNECTION_ENDPOINT Connection)
56 {
57 PLIST_ENTRY Entry;
58 PQUEUE_ENTRY qp = NULL;
59
60 ReferenceObject(Connection);
61
62 while (!IsListEmpty(&Connection->PacketQueue))
63 {
64 Entry = RemoveHeadList(&Connection->PacketQueue);
65 qp = CONTAINING_RECORD(Entry, QUEUE_ENTRY, ListEntry);
66
67 /* We're in the tcpip thread here so this is safe */
68 pbuf_free(qp->p);
69
70 ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp);
71 }
72
73 DereferenceObject(Connection);
74 }
75
76 void LibTCPEnqueuePacket(PCONNECTION_ENDPOINT Connection, struct pbuf *p)
77 {
78 PQUEUE_ENTRY qp;
79
80 qp = (PQUEUE_ENTRY)ExAllocateFromNPagedLookasideList(&QueueEntryLookasideList);
81 qp->p = p;
82 qp->Offset = 0;
83
84 ExInterlockedInsertTailList(&Connection->PacketQueue, &qp->ListEntry, &Connection->Lock);
85 }
86
87 PQUEUE_ENTRY LibTCPDequeuePacket(PCONNECTION_ENDPOINT Connection)
88 {
89 PLIST_ENTRY Entry;
90 PQUEUE_ENTRY qp = NULL;
91
92 if (IsListEmpty(&Connection->PacketQueue)) return NULL;
93
94 Entry = RemoveHeadList(&Connection->PacketQueue);
95
96 qp = CONTAINING_RECORD(Entry, QUEUE_ENTRY, ListEntry);
97
98 return qp;
99 }
100
101 NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHAR RecvBuffer, UINT RecvLen, UINT *Received)
102 {
103 PQUEUE_ENTRY qp;
104 struct pbuf* p;
105 NTSTATUS Status;
106 UINT ReadLength, PayloadLength, Offset, Copied;
107 KIRQL OldIrql;
108
109 (*Received) = 0;
110
111 LockObject(Connection, &OldIrql);
112
113 if (!IsListEmpty(&Connection->PacketQueue))
114 {
115 while ((qp = LibTCPDequeuePacket(Connection)) != NULL)
116 {
117 p = qp->p;
118
119 /* Calculate the payload length first */
120 PayloadLength = p->tot_len;
121 PayloadLength -= qp->Offset;
122 Offset = qp->Offset;
123
124 /* Check if we're reading the whole buffer */
125 ReadLength = MIN(PayloadLength, RecvLen);
126 ASSERT(ReadLength != 0);
127 if (ReadLength != PayloadLength)
128 {
129 /* Save this one for later */
130 qp->Offset += ReadLength;
131 InsertHeadList(&Connection->PacketQueue, &qp->ListEntry);
132 qp = NULL;
133 }
134
135 UnlockObject(Connection, OldIrql);
136
137 Copied = pbuf_copy_partial(p, RecvBuffer, ReadLength, Offset);
138 ASSERT(Copied == ReadLength);
139
140 LockObject(Connection, &OldIrql);
141
142 /* Update trackers */
143 RecvLen -= ReadLength;
144 RecvBuffer += ReadLength;
145 (*Received) += ReadLength;
146
147 if (qp != NULL)
148 {
149 /* Use this special pbuf free callback function because we're outside tcpip thread */
150 pbuf_free_callback(qp->p);
151
152 ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp);
153 }
154 else
155 {
156 /* If we get here, it means we've filled the buffer */
157 ASSERT(RecvLen == 0);
158 }
159
160 ASSERT((*Received) != 0);
161 Status = STATUS_SUCCESS;
162
163 if (!RecvLen)
164 break;
165 }
166 }
167 else
168 {
169 if (Connection->ReceiveShutdown)
170 Status = Connection->ReceiveShutdownStatus;
171 else
172 Status = STATUS_PENDING;
173 }
174
175 UnlockObject(Connection, OldIrql);
176
177 return Status;
178 }
179
180 static
181 BOOLEAN
182 WaitForEventSafely(PRKEVENT Event)
183 {
184 PVOID WaitObjects[] = {Event, &TerminationEvent};
185
186 if (KeWaitForMultipleObjects(2,
187 WaitObjects,
188 WaitAny,
189 Executive,
190 KernelMode,
191 FALSE,
192 NULL,
193 NULL) == STATUS_WAIT_0)
194 {
195 /* Signalled by the caller's event */
196 return TRUE;
197 }
198 else /* if KeWaitForMultipleObjects() == STATUS_WAIT_1 */
199 {
200 /* Signalled by our termination event */
201 return FALSE;
202 }
203 }
204
205 static
206 err_t
207 InternalSendEventHandler(void *arg, PTCP_PCB pcb, const u16_t space)
208 {
209 /* Make sure the socket didn't get closed */
210 if (!arg) return ERR_OK;
211
212 TCPSendEventHandler(arg, space);
213
214 return ERR_OK;
215 }
216
217 static
218 err_t
219 InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t err)
220 {
221 PCONNECTION_ENDPOINT Connection = arg;
222
223 /* Make sure the socket didn't get closed */
224 if (!arg)
225 {
226 if (p)
227 pbuf_free(p);
228
229 return ERR_OK;
230 }
231
232 if (p)
233 {
234 LibTCPEnqueuePacket(Connection, p);
235
236 tcp_recved(pcb, p->tot_len);
237
238 TCPRecvEventHandler(arg);
239 }
240 else if (err == ERR_OK)
241 {
242 /* Complete pending reads with 0 bytes to indicate a graceful closure,
243 * but note that send is still possible in this state so we don't close the
244 * whole socket here (by calling tcp_close()) as that would violate TCP specs
245 */
246 Connection->ReceiveShutdown = TRUE;
247 Connection->ReceiveShutdownStatus = STATUS_SUCCESS;
248
249 /* If we already did a send shutdown, we're in TIME_WAIT so we can't use this PCB anymore */
250 if (Connection->SendShutdown)
251 {
252 Connection->SocketContext = NULL;
253 tcp_arg(pcb, NULL);
254 }
255
256 /* Indicate the graceful close event */
257 TCPRecvEventHandler(arg);
258
259 /* If the PCB is gone, clean up the connection */
260 if (Connection->SendShutdown)
261 {
262 TCPFinEventHandler(Connection, ERR_CLSD);
263 }
264 }
265
266 return ERR_OK;
267 }
268
269 /* This function MUST return an error value that is not ERR_ABRT or ERR_OK if the connection
270 * is not accepted to avoid leaking the new PCB */
271 static
272 err_t
273 InternalAcceptEventHandler(void *arg, PTCP_PCB newpcb, const err_t err)
274 {
275 /* Make sure the socket didn't get closed */
276 if (!arg)
277 return ERR_CLSD;
278
279 TCPAcceptEventHandler(arg, newpcb);
280
281 /* Set in LibTCPAccept (called from TCPAcceptEventHandler) */
282 if (newpcb->callback_arg)
283 return ERR_OK;
284 else
285 return ERR_CLSD;
286 }
287
288 static
289 err_t
290 InternalConnectEventHandler(void *arg, PTCP_PCB pcb, const err_t err)
291 {
292 /* Make sure the socket didn't get closed */
293 if (!arg)
294 return ERR_OK;
295
296 TCPConnectEventHandler(arg, err);
297
298 return ERR_OK;
299 }
300
301 static
302 void
303 InternalErrorEventHandler(void *arg, const err_t err)
304 {
305 PCONNECTION_ENDPOINT Connection = arg;
306
307 /* Make sure the socket didn't get closed */
308 if (!arg || Connection->SocketContext == NULL) return;
309
310 /* The PCB is dead now */
311 Connection->SocketContext = NULL;
312
313 /* Give them one shot to receive the remaining data */
314 Connection->ReceiveShutdown = TRUE;
315 Connection->ReceiveShutdownStatus = TCPTranslateError(err);
316 TCPRecvEventHandler(Connection);
317
318 /* Terminate the connection */
319 TCPFinEventHandler(Connection, err);
320 }
321
322 static
323 void
324 LibTCPSocketCallback(void *arg)
325 {
326 struct lwip_callback_msg *msg = arg;
327
328 ASSERT(msg);
329
330 msg->Output.Socket.NewPcb = tcp_new();
331
332 if (msg->Output.Socket.NewPcb)
333 {
334 tcp_arg(msg->Output.Socket.NewPcb, msg->Input.Socket.Arg);
335 tcp_err(msg->Output.Socket.NewPcb, InternalErrorEventHandler);
336 }
337
338 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
339 }
340
341 struct tcp_pcb *
342 LibTCPSocket(void *arg)
343 {
344 struct lwip_callback_msg *msg = ExAllocateFromNPagedLookasideList(&MessageLookasideList);
345 struct tcp_pcb *ret;
346
347 if (msg)
348 {
349 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
350 msg->Input.Socket.Arg = arg;
351
352 tcpip_callback_with_block(LibTCPSocketCallback, msg, 1);
353
354 if (WaitForEventSafely(&msg->Event))
355 ret = msg->Output.Socket.NewPcb;
356 else
357 ret = NULL;
358
359 ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
360
361 return ret;
362 }
363
364 return NULL;
365 }
366
367 static
368 void
369 LibTCPBindCallback(void *arg)
370 {
371 struct lwip_callback_msg *msg = arg;
372 PTCP_PCB pcb = msg->Input.Bind.Connection->SocketContext;
373
374 ASSERT(msg);
375
376 if (!msg->Input.Bind.Connection->SocketContext)
377 {
378 msg->Output.Bind.Error = ERR_CLSD;
379 goto done;
380 }
381
382 /* We're guaranteed that the local address is valid to bind at this point */
383 pcb->so_options |= SOF_REUSEADDR;
384
385 msg->Output.Bind.Error = tcp_bind(pcb,
386 msg->Input.Bind.IpAddress,
387 ntohs(msg->Input.Bind.Port));
388
389 done:
390 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
391 }
392
393 err_t
394 LibTCPBind(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port)
395 {
396 struct lwip_callback_msg *msg;
397 err_t ret;
398
399 msg = ExAllocateFromNPagedLookasideList(&MessageLookasideList);
400 if (msg)
401 {
402 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
403 msg->Input.Bind.Connection = Connection;
404 msg->Input.Bind.IpAddress = ipaddr;
405 msg->Input.Bind.Port = port;
406
407 tcpip_callback_with_block(LibTCPBindCallback, msg, 1);
408
409 if (WaitForEventSafely(&msg->Event))
410 ret = msg->Output.Bind.Error;
411 else
412 ret = ERR_CLSD;
413
414 ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
415
416 return ret;
417 }
418
419 return ERR_MEM;
420 }
421
422 static
423 void
424 LibTCPListenCallback(void *arg)
425 {
426 struct lwip_callback_msg *msg = arg;
427
428 ASSERT(msg);
429
430 if (!msg->Input.Listen.Connection->SocketContext)
431 {
432 msg->Output.Listen.NewPcb = NULL;
433 goto done;
434 }
435
436 msg->Output.Listen.NewPcb = tcp_listen_with_backlog((PTCP_PCB)msg->Input.Listen.Connection->SocketContext, msg->Input.Listen.Backlog);
437
438 if (msg->Output.Listen.NewPcb)
439 {
440 tcp_accept(msg->Output.Listen.NewPcb, InternalAcceptEventHandler);
441 }
442
443 done:
444 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
445 }
446
447 PTCP_PCB
448 LibTCPListen(PCONNECTION_ENDPOINT Connection, const u8_t backlog)
449 {
450 struct lwip_callback_msg *msg;
451 PTCP_PCB ret;
452
453 msg = ExAllocateFromNPagedLookasideList(&MessageLookasideList);
454 if (msg)
455 {
456 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
457 msg->Input.Listen.Connection = Connection;
458 msg->Input.Listen.Backlog = backlog;
459
460 tcpip_callback_with_block(LibTCPListenCallback, msg, 1);
461
462 if (WaitForEventSafely(&msg->Event))
463 ret = msg->Output.Listen.NewPcb;
464 else
465 ret = NULL;
466
467 ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
468
469 return ret;
470 }
471
472 return NULL;
473 }
474
475 static
476 void
477 LibTCPSendCallback(void *arg)
478 {
479 struct lwip_callback_msg *msg = arg;
480 PTCP_PCB pcb = msg->Input.Send.Connection->SocketContext;
481 ULONG SendLength;
482 UCHAR SendFlags;
483
484 ASSERT(msg);
485
486 if (!msg->Input.Send.Connection->SocketContext)
487 {
488 msg->Output.Send.Error = ERR_CLSD;
489 goto done;
490 }
491
492 if (msg->Input.Send.Connection->SendShutdown)
493 {
494 msg->Output.Send.Error = ERR_CLSD;
495 goto done;
496 }
497
498 SendFlags = TCP_WRITE_FLAG_COPY;
499 SendLength = msg->Input.Send.DataLength;
500 if (tcp_sndbuf(pcb) == 0)
501 {
502 /* No buffer space so return pending */
503 msg->Output.Send.Error = ERR_INPROGRESS;
504 goto done;
505 }
506 else if (tcp_sndbuf(pcb) < SendLength)
507 {
508 /* We've got some room so let's send what we can */
509 SendLength = tcp_sndbuf(pcb);
510
511 /* Don't set the push flag */
512 SendFlags |= TCP_WRITE_FLAG_MORE;
513 }
514
515 msg->Output.Send.Error = tcp_write(pcb,
516 msg->Input.Send.Data,
517 SendLength,
518 SendFlags);
519 if (msg->Output.Send.Error == ERR_OK)
520 {
521 /* Queued successfully so try to send it */
522 tcp_output((PTCP_PCB)msg->Input.Send.Connection->SocketContext);
523 msg->Output.Send.Information = SendLength;
524 }
525 else if (msg->Output.Send.Error == ERR_MEM)
526 {
527 /* The queue is too long */
528 msg->Output.Send.Error = ERR_INPROGRESS;
529 }
530
531 done:
532 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
533 }
534
535 err_t
536 LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, u32_t *sent, const int safe)
537 {
538 err_t ret;
539 struct lwip_callback_msg *msg;
540
541 msg = ExAllocateFromNPagedLookasideList(&MessageLookasideList);
542 if (msg)
543 {
544 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
545 msg->Input.Send.Connection = Connection;
546 msg->Input.Send.Data = dataptr;
547 msg->Input.Send.DataLength = len;
548
549 if (safe)
550 LibTCPSendCallback(msg);
551 else
552 tcpip_callback_with_block(LibTCPSendCallback, msg, 1);
553
554 if (WaitForEventSafely(&msg->Event))
555 ret = msg->Output.Send.Error;
556 else
557 ret = ERR_CLSD;
558
559 if (ret == ERR_OK)
560 *sent = msg->Output.Send.Information;
561 else
562 *sent = 0;
563
564 ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
565
566 return ret;
567 }
568
569 return ERR_MEM;
570 }
571
572 static
573 void
574 LibTCPConnectCallback(void *arg)
575 {
576 struct lwip_callback_msg *msg = arg;
577 err_t Error;
578
579 ASSERT(arg);
580
581 if (!msg->Input.Connect.Connection->SocketContext)
582 {
583 msg->Output.Connect.Error = ERR_CLSD;
584 goto done;
585 }
586
587 tcp_recv((PTCP_PCB)msg->Input.Connect.Connection->SocketContext, InternalRecvEventHandler);
588 tcp_sent((PTCP_PCB)msg->Input.Connect.Connection->SocketContext, InternalSendEventHandler);
589
590 Error = tcp_connect((PTCP_PCB)msg->Input.Connect.Connection->SocketContext,
591 msg->Input.Connect.IpAddress, ntohs(msg->Input.Connect.Port),
592 InternalConnectEventHandler);
593
594 msg->Output.Connect.Error = Error == ERR_OK ? ERR_INPROGRESS : Error;
595
596 done:
597 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
598 }
599
600 err_t
601 LibTCPConnect(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port)
602 {
603 struct lwip_callback_msg *msg;
604 err_t ret;
605
606 msg = ExAllocateFromNPagedLookasideList(&MessageLookasideList);
607 if (msg)
608 {
609 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
610 msg->Input.Connect.Connection = Connection;
611 msg->Input.Connect.IpAddress = ipaddr;
612 msg->Input.Connect.Port = port;
613
614 tcpip_callback_with_block(LibTCPConnectCallback, msg, 1);
615
616 if (WaitForEventSafely(&msg->Event))
617 {
618 ret = msg->Output.Connect.Error;
619 }
620 else
621 ret = ERR_CLSD;
622
623 ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
624
625 return ret;
626 }
627
628 return ERR_MEM;
629 }
630
631 static
632 void
633 LibTCPShutdownCallback(void *arg)
634 {
635 struct lwip_callback_msg *msg = arg;
636 PTCP_PCB pcb = msg->Input.Shutdown.Connection->SocketContext;
637
638 if (!msg->Input.Shutdown.Connection->SocketContext)
639 {
640 msg->Output.Shutdown.Error = ERR_CLSD;
641 goto done;
642 }
643
644 /* LwIP makes the (questionable) assumption that SHUTDOWN_RDWR is equivalent to tcp_close().
645 * This assumption holds even if the shutdown calls are done separately (even through multiple
646 * WinSock shutdown() calls). This assumption means that lwIP has the right to deallocate our
647 * PCB without telling us if we shutdown TX and RX. To avoid these problems, we'll clear the
648 * socket context if we have called shutdown for TX and RX.
649 */
650 if (msg->Input.Shutdown.shut_rx) {
651 msg->Output.Shutdown.Error = tcp_shutdown(pcb, TRUE, FALSE);
652 }
653 if (msg->Input.Shutdown.shut_tx) {
654 msg->Output.Shutdown.Error = tcp_shutdown(pcb, FALSE, TRUE);
655 }
656
657 if (!msg->Output.Shutdown.Error)
658 {
659 if (msg->Input.Shutdown.shut_rx)
660 {
661 msg->Input.Shutdown.Connection->ReceiveShutdown = TRUE;
662 msg->Input.Shutdown.Connection->ReceiveShutdownStatus = STATUS_FILE_CLOSED;
663 }
664
665 if (msg->Input.Shutdown.shut_tx)
666 msg->Input.Shutdown.Connection->SendShutdown = TRUE;
667
668 if (msg->Input.Shutdown.Connection->ReceiveShutdown &&
669 msg->Input.Shutdown.Connection->SendShutdown)
670 {
671 /* The PCB is not ours anymore */
672 msg->Input.Shutdown.Connection->SocketContext = NULL;
673 tcp_arg(pcb, NULL);
674 TCPFinEventHandler(msg->Input.Shutdown.Connection, ERR_CLSD);
675 }
676 }
677
678 done:
679 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
680 }
681
682 err_t
683 LibTCPShutdown(PCONNECTION_ENDPOINT Connection, const int shut_rx, const int shut_tx)
684 {
685 struct lwip_callback_msg *msg;
686 err_t ret;
687
688 msg = ExAllocateFromNPagedLookasideList(&MessageLookasideList);
689 if (msg)
690 {
691 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
692
693 msg->Input.Shutdown.Connection = Connection;
694 msg->Input.Shutdown.shut_rx = shut_rx;
695 msg->Input.Shutdown.shut_tx = shut_tx;
696
697 tcpip_callback_with_block(LibTCPShutdownCallback, msg, 1);
698
699 if (WaitForEventSafely(&msg->Event))
700 ret = msg->Output.Shutdown.Error;
701 else
702 ret = ERR_CLSD;
703
704 ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
705
706 return ret;
707 }
708
709 return ERR_MEM;
710 }
711
712 static
713 void
714 LibTCPCloseCallback(void *arg)
715 {
716 struct lwip_callback_msg *msg = arg;
717 PTCP_PCB pcb = msg->Input.Close.Connection->SocketContext;
718
719 /* Empty the queue even if we're already "closed" */
720 LibTCPEmptyQueue(msg->Input.Close.Connection);
721
722 /* Check if we've already been closed */
723 if (msg->Input.Close.Connection->Closing)
724 {
725 msg->Output.Close.Error = ERR_OK;
726 goto done;
727 }
728
729 /* Enter "closing" mode if we're doing a normal close */
730 if (msg->Input.Close.Callback)
731 msg->Input.Close.Connection->Closing = TRUE;
732
733 /* Check if the PCB was already "closed" but the client doesn't know it yet */
734 if (!msg->Input.Close.Connection->SocketContext)
735 {
736 msg->Output.Close.Error = ERR_OK;
737 goto done;
738 }
739
740 /* Clear the PCB pointer and stop callbacks */
741 msg->Input.Close.Connection->SocketContext = NULL;
742 tcp_arg(pcb, NULL);
743
744 /* This may generate additional callbacks but we don't care,
745 * because they're too inconsistent to rely on */
746 msg->Output.Close.Error = tcp_close(pcb);
747
748 if (msg->Output.Close.Error)
749 {
750 /* Restore the PCB pointer */
751 msg->Input.Close.Connection->SocketContext = pcb;
752 msg->Input.Close.Connection->Closing = FALSE;
753 }
754 else if (msg->Input.Close.Callback)
755 {
756 TCPFinEventHandler(msg->Input.Close.Connection, ERR_CLSD);
757 }
758
759 done:
760 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
761 }
762
763 err_t
764 LibTCPClose(PCONNECTION_ENDPOINT Connection, const int safe, const int callback)
765 {
766 err_t ret;
767 struct lwip_callback_msg *msg;
768
769 msg = ExAllocateFromNPagedLookasideList(&MessageLookasideList);
770 if (msg)
771 {
772 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
773
774 msg->Input.Close.Connection = Connection;
775 msg->Input.Close.Callback = callback;
776
777 if (safe)
778 LibTCPCloseCallback(msg);
779 else
780 tcpip_callback_with_block(LibTCPCloseCallback, msg, 1);
781
782 if (WaitForEventSafely(&msg->Event))
783 ret = msg->Output.Close.Error;
784 else
785 ret = ERR_CLSD;
786
787 ExFreeToNPagedLookasideList(&MessageLookasideList, msg);
788
789 return ret;
790 }
791
792 return ERR_MEM;
793 }
794
795 void
796 LibTCPAccept(PTCP_PCB pcb, struct tcp_pcb *listen_pcb, void *arg)
797 {
798 ASSERT(arg);
799
800 tcp_arg(pcb, NULL);
801 tcp_recv(pcb, InternalRecvEventHandler);
802 tcp_sent(pcb, InternalSendEventHandler);
803 tcp_err(pcb, InternalErrorEventHandler);
804 tcp_arg(pcb, arg);
805
806 tcp_accepted(listen_pcb);
807 }
808
809 err_t
810 LibTCPGetHostName(PTCP_PCB pcb, struct ip_addr *const ipaddr, u16_t *const port)
811 {
812 if (!pcb)
813 return ERR_CLSD;
814
815 *ipaddr = pcb->local_ip;
816 *port = pcb->local_port;
817
818 return ERR_OK;
819 }
820
821 err_t
822 LibTCPGetPeerName(PTCP_PCB pcb, struct ip_addr * const ipaddr, u16_t * const port)
823 {
824 if (!pcb)
825 return ERR_CLSD;
826
827 *ipaddr = pcb->remote_ip;
828 *port = pcb->remote_port;
829
830 return ERR_OK;
831 }
832
833 void
834 LibTCPSetNoDelay(
835 PTCP_PCB pcb,
836 BOOLEAN Set)
837 {
838 if (Set)
839 pcb->flags |= TF_NODELAY;
840 else
841 pcb->flags &= ~TF_NODELAY;
842 }