* Sync the recent cmake branch changes.
[reactos.git] / lib / drivers / lwip / src / rostcp.c
1 #include "lwip/sys.h"
2 #include "lwip/tcpip.h"
3
4 #include "rosip.h"
5
6 #include <debug.h>
7
8 static const char * const tcp_state_str[] = {
9 "CLOSED",
10 "LISTEN",
11 "SYN_SENT",
12 "SYN_RCVD",
13 "ESTABLISHED",
14 "FIN_WAIT_1",
15 "FIN_WAIT_2",
16 "CLOSE_WAIT",
17 "CLOSING",
18 "LAST_ACK",
19 "TIME_WAIT"
20 };
21
22 /* The way that lwIP does multi-threading is really not ideal for our purposes but
23 * we best go along with it unless we want another unstable TCP library. lwIP uses
24 * a thread called the "tcpip thread" which is the only one allowed to call raw API
25 * functions. Since this is the case, for each of our LibTCP* functions, we queue a request
26 * for a callback to "tcpip thread" which calls our LibTCP*Callback functions. Yes, this is
27 * a lot of unnecessary thread swapping and it could definitely be faster, but I don't want
28 * to going messing around in lwIP because I have no desire to create another mess like oskittcp */
29
30 extern KEVENT TerminationEvent;
31
32 static
33 BOOLEAN
34 WaitForEventSafely(PRKEVENT Event)
35 {
36 PVOID WaitObjects[] = {Event, &TerminationEvent};
37
38 if (KeWaitForMultipleObjects(2,
39 WaitObjects,
40 WaitAny,
41 Executive,
42 KernelMode,
43 FALSE,
44 NULL,
45 NULL) == STATUS_WAIT_0)
46 {
47 /* Signalled by the caller's event */
48 return TRUE;
49 }
50 else /* if KeWaitForMultipleObjects() == STATUS_WAIT_1 */
51 {
52 /* Signalled by our termination event */
53 return FALSE;
54 }
55 }
56
57 static
58 err_t
59 InternalSendEventHandler(void *arg, struct tcp_pcb *pcb, u16_t space)
60 {
61 DbgPrint("[lwIP, InternalSendEventHandler] SendEvent (0x%x, 0x%x, %d)\n",
62 arg, pcb, (unsigned int)space);
63
64 /* Make sure the socket didn't get closed */
65 if (!arg) return ERR_OK;
66
67 TCPSendEventHandler(arg, space);
68
69 return ERR_OK;
70 }
71
72 static
73 err_t
74 InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
75 {
76 u32_t len;
77
78 DbgPrint("[lwIP, InternalRecvEventHandler] RecvEvent (0x%x, 0x%x, 0x%x, %d)\n",
79 arg, pcb, p, (unsigned int)err);
80
81 /* Make sure the socket didn't get closed */
82 if (!arg)
83 {
84 if (p) pbuf_free(p);
85 return ERR_OK;
86 }
87
88 if (!p)
89 {
90 TCPFinEventHandler(arg, ERR_OK);
91 }
92 else
93 {
94 DbgPrint("[lwIP, InternalRecvEventHandler] RECV - p:0x%x p->payload:0x%x p->len:%d p->tot_len:%d\n",
95 p, p->payload, p->len, p->tot_len);
96
97 if (err == ERR_OK)
98 {
99 len = TCPRecvEventHandler(arg, p);
100 if (len != 0)
101 {
102 tcp_recved(pcb, len);
103
104 pbuf_free(p);
105
106 return ERR_OK;
107 }
108 else
109 {
110 /* We want lwIP to store the pbuf on its queue for later */
111 return ERR_TIMEOUT;
112 }
113 }
114 else
115 {
116 pbuf_free(p);
117 }
118 }
119
120 return ERR_OK;
121 }
122
123 static
124 err_t
125 InternalAcceptEventHandler(void *arg, struct tcp_pcb *newpcb, err_t err)
126 {
127 DbgPrint("[lwIP, InternalAcceptEventHandler] AcceptEvent (0x%x, 0x%x, %d)\n",
128 arg, newpcb, (unsigned int)err);
129
130 /* Make sure the socket didn't get closed */
131 if (!arg)
132 return ERR_ABRT;
133
134 DbgPrint("[lwIP, InternalAcceptEventHandler] newpcb->state = %s\n",
135 tcp_state_str[newpcb->state]);
136
137 TCPAcceptEventHandler(arg, newpcb);
138
139 /* Set in LibTCPAccept (called from TCPAcceptEventHandler) */
140 if (newpcb->callback_arg)
141 return ERR_OK;
142 else
143 return ERR_ABRT;
144 }
145
146 static
147 err_t
148 InternalConnectEventHandler(void *arg, struct tcp_pcb *pcb, err_t err)
149 {
150 DbgPrint("[lwIP, InternalConnectEventHandler] ConnectEvent(0x%x, 0x%x, %d)\n",
151 arg, pcb, (unsigned int)err);
152
153 /* Make sure the socket didn't get closed */
154 if (!arg)
155 return ERR_OK;
156
157 TCPConnectEventHandler(arg, err);
158
159 tcp_recv(pcb, InternalRecvEventHandler);
160
161 return ERR_OK;
162 }
163
164 static
165 void
166 InternalErrorEventHandler(void *arg, err_t err)
167 {
168 DbgPrint("[lwIP, InternalErrorEventHandler] ErrorEvent(0x%x, %d)\n",
169 arg, (unsigned int)err);
170
171 /* Make sure the socket didn't get closed */
172 if (!arg) return;
173
174 TCPFinEventHandler(arg, err);
175 }
176
177 struct socket_callback_msg
178 {
179 /* Synchronization */
180 KEVENT Event;
181
182 /* Input */
183 PVOID Arg;
184
185 /* Output */
186 PVOID NewPcb;
187 };
188
189 static
190 void
191 LibTCPSocketCallback(void *arg)
192 {
193 struct socket_callback_msg *msg = arg;
194
195 ASSERT(msg);
196
197 msg->NewPcb = tcp_new();
198
199 if (msg->NewPcb)
200 {
201 tcp_arg((struct tcp_pcb*)msg->NewPcb, msg->Arg);
202 tcp_err((struct tcp_pcb*)msg->NewPcb, InternalErrorEventHandler);
203 }
204
205 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
206 }
207
208 struct tcp_pcb *
209 LibTCPSocket(void *arg)
210 {
211 struct socket_callback_msg *msg = ExAllocatePool(NonPagedPool, sizeof(struct socket_callback_msg));
212 void *ret;
213
214 if (msg)
215 {
216 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
217 msg->Arg = arg;
218
219 tcpip_callback_with_block(LibTCPSocketCallback, msg, 1);
220
221 if (WaitForEventSafely(&msg->Event))
222 ret = msg->NewPcb;
223 else
224 ret = NULL;
225
226 DbgPrint("[lwIP, LibTCPSocket] (0x%x) = 0x%x\n", arg, ret);
227
228 ExFreePool(msg);
229
230 return (struct tcp_pcb*)ret;
231 }
232
233 return NULL;
234 }
235
236 struct bind_callback_msg
237 {
238 /* Synchronization */
239 KEVENT Event;
240
241 /* Input */
242 struct tcp_pcb *Pcb;
243 struct ip_addr *IpAddress;
244 u16_t Port;
245
246 /* Output */
247 err_t Error;
248 };
249
250 static
251 void
252 LibTCPBindCallback(void *arg)
253 {
254 struct bind_callback_msg *msg = arg;
255
256 ASSERT(msg);
257
258 msg->Error = tcp_bind(msg->Pcb, msg->IpAddress, ntohs(msg->Port));
259
260 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
261 }
262
263 err_t
264 LibTCPBind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
265 {
266 struct bind_callback_msg *msg;
267 err_t ret;
268
269 if (!pcb)
270 return ERR_CLSD;
271
272 DbgPrint("[lwIP, LibTCPBind] Called\n");
273
274 msg = ExAllocatePool(NonPagedPool, sizeof(struct bind_callback_msg));
275 if (msg)
276 {
277 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
278 msg->Pcb = pcb;
279 msg->IpAddress = ipaddr;
280 msg->Port = port;
281
282 tcpip_callback_with_block(LibTCPBindCallback, msg, 1);
283
284 if (WaitForEventSafely(&msg->Event))
285 ret = msg->Error;
286 else
287 ret = ERR_CLSD;
288
289 DbgPrint("[lwIP, LibTCPBind] pcb = 0x%x\n", pcb);
290
291 DbgPrint("[lwIP, LibTCPBind] Done\n");
292
293 ExFreePool(msg);
294
295 return ret;
296 }
297
298 return ERR_MEM;
299 }
300
301 struct listen_callback_msg
302 {
303 /* Synchronization */
304 KEVENT Event;
305
306 /* Input */
307 struct tcp_pcb *Pcb;
308 u8_t Backlog;
309
310 /* Output */
311 struct tcp_pcb *NewPcb;
312 };
313
314 static
315 void
316 LibTCPListenCallback(void *arg)
317 {
318 struct listen_callback_msg *msg = arg;
319 void *p;
320
321 ASSERT(msg);
322
323 DbgPrint("[lwIP, LibTCPListenCallback] Called\n");
324
325 p = msg->Pcb->callback_arg;
326 msg->NewPcb = tcp_listen_with_backlog(msg->Pcb, msg->Backlog);
327
328 if (msg->NewPcb)
329 {
330 tcp_arg(msg->NewPcb, p);
331 tcp_accept(msg->NewPcb, InternalAcceptEventHandler);
332 tcp_err(msg->NewPcb, InternalErrorEventHandler);
333 }
334
335 DbgPrint("[lwIP, LibTCPListenCallback] Done\n");
336
337 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
338 }
339
340 struct tcp_pcb *
341 LibTCPListen(struct tcp_pcb *pcb, u8_t backlog)
342 {
343 struct listen_callback_msg *msg;
344 void *ret;
345
346 DbgPrint("[lwIP, LibTCPListen] Called\n");
347
348 if (!pcb)
349 return NULL;
350
351 msg = ExAllocatePool(NonPagedPool, sizeof(struct listen_callback_msg));
352 if (msg)
353 {
354 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
355 msg->Pcb = pcb;
356 msg->Backlog = backlog;
357
358 tcpip_callback_with_block(LibTCPListenCallback, msg, 1);
359
360 if (WaitForEventSafely(&msg->Event))
361 ret = msg->NewPcb;
362 else
363 ret = NULL;
364
365 DbgPrint("[lwIP, LibTCPListen] pcb = 0x%x \n", pcb);
366
367 DbgPrint("[lwIP, LibTCPListen] Done\n");
368
369 ExFreePool(msg);
370
371 return ret;
372 }
373
374 return NULL;
375 }
376
377 struct send_callback_msg
378 {
379 /* Synchronization */
380 KEVENT Event;
381
382 /* Input */
383 struct tcp_pcb *Pcb;
384 void *Data;
385 u16_t DataLength;
386
387 /* Output */
388 err_t Error;
389 };
390
391 static
392 void
393 LibTCPSendCallback(void *arg)
394 {
395 struct send_callback_msg *msg = arg;
396
397 ASSERT(msg);
398
399 if (tcp_sndbuf(msg->Pcb) < msg->DataLength)
400 {
401 msg->Error = ERR_INPROGRESS;
402 }
403 else
404 {
405 tcp_sent(msg->Pcb, InternalSendEventHandler);
406
407 msg->Error = tcp_write(msg->Pcb, msg->Data, msg->DataLength, TCP_WRITE_FLAG_COPY);
408
409 tcp_output(msg->Pcb);
410 }
411
412 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
413 }
414
415 err_t
416 LibTCPSend(struct tcp_pcb *pcb, void *dataptr, u16_t len)
417 {
418 struct send_callback_msg *msg;
419 err_t ret;
420
421 if (!pcb)
422 return ERR_CLSD;
423
424 msg = ExAllocatePool(NonPagedPool, sizeof(struct send_callback_msg));
425 if (msg)
426 {
427 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
428 msg->Pcb = pcb;
429 msg->Data = dataptr;
430 msg->DataLength = len;
431
432 tcpip_callback_with_block(LibTCPSendCallback, msg, 1);
433
434 if (WaitForEventSafely(&msg->Event))
435 ret = msg->Error;
436 else
437 ret = ERR_CLSD;
438
439 DbgPrint("LibTCPSend(0x%x)\n", pcb);
440
441 ExFreePool(msg);
442
443 return ret;
444 }
445
446 return ERR_MEM;
447 }
448
449 struct connect_callback_msg
450 {
451 /* Synchronization */
452 KEVENT Event;
453
454 /* Input */
455 struct tcp_pcb *Pcb;
456 struct ip_addr *IpAddress;
457 u16_t Port;
458
459 /* Output */
460 err_t Error;
461 };
462
463 static
464 void
465 LibTCPConnectCallback(void *arg)
466 {
467 struct connect_callback_msg *msg = arg;
468
469 DbgPrint("[lwIP, LibTCPConnectCallback] Called\n");
470
471 ASSERT(arg);
472
473 msg->Error = tcp_connect(msg->Pcb, msg->IpAddress, ntohs(msg->Port), InternalConnectEventHandler);
474 if (msg->Error == ERR_OK)
475 msg->Error = ERR_INPROGRESS;
476
477 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
478
479 DbgPrint("[lwIP, LibTCPConnectCallback] Done\n");
480 }
481
482 err_t
483 LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
484 {
485 struct connect_callback_msg *msg;
486 err_t ret;
487
488 DbgPrint("[lwIP, LibTCPConnect] Called\n");
489
490 if (!pcb)
491 return ERR_CLSD;
492
493 msg = ExAllocatePool(NonPagedPool, sizeof(struct connect_callback_msg));
494 if (msg)
495 {
496 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
497 msg->Pcb = pcb;
498 msg->IpAddress = ipaddr;
499 msg->Port = port;
500
501 tcpip_callback_with_block(LibTCPConnectCallback, msg, 1);
502
503 if (WaitForEventSafely(&msg->Event))
504 ret = msg->Error;
505 else
506 ret = ERR_CLSD;
507
508 ExFreePool(msg);
509
510 DbgPrint("[lwIP, LibTCPConnect] pcb = 0x%x\n", pcb);
511
512 DbgPrint("[lwIP, LibTCPConnect] Done\n");
513
514 return ret;
515 }
516
517 return ERR_MEM;
518 }
519
520 struct close_callback_msg
521 {
522 /* Synchronization */
523 KEVENT Event;
524
525 /* Input */
526 struct tcp_pcb *Pcb;
527
528 /* Output */
529 err_t Error;
530 };
531
532 static
533 void
534 LibTCPCloseCallback(void *arg)
535 {
536 struct close_callback_msg *msg = arg;
537
538 msg->Error = tcp_close(msg->Pcb);
539
540 KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
541 }
542
543 err_t
544 LibTCPClose(struct tcp_pcb *pcb)
545 {
546 struct close_callback_msg *msg;
547 err_t ret;
548
549 DbgPrint("[lwIP, LibTCPClose] Called\n");
550
551 if (!pcb)
552 {
553 DbgPrint("[lwIP, LibTCPClose] Done... NO pcb\n");
554 return ERR_CLSD;
555 }
556
557 DbgPrint("[lwIP, LibTCPClose] Removing pcb callbacks\n");
558
559 tcp_arg(pcb, NULL);
560 tcp_recv(pcb, NULL);
561 tcp_sent(pcb, NULL);
562 tcp_err(pcb, NULL);
563 tcp_accept(pcb, NULL);
564
565 DbgPrint("[lwIP, LibTCPClose] Attempting to allocate memory for msg\n");
566
567 msg = ExAllocatePool(NonPagedPool, sizeof(struct close_callback_msg));
568 if (msg)
569 {
570 DbgPrint("[lwIP, LibTCPClose] Initializing msg->Event\n");
571 KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
572
573 DbgPrint("[lwIP, LibTCPClose] Initializing msg->pcb = 0x%x\n", pcb);
574 msg->Pcb = pcb;
575
576 DbgPrint("[lwIP, LibTCPClose] Attempting to call LibTCPCloseCallback\n");
577
578 tcpip_callback_with_block(LibTCPCloseCallback, msg, 1);
579
580 if (WaitForEventSafely(&msg->Event))
581 ret = msg->Error;
582 else
583 ret = ERR_CLSD;
584
585 ExFreePool(msg);
586
587 DbgPrint("[lwIP, LibTCPClose] pcb = 0x%x\n", pcb);
588
589 DbgPrint("[lwIP, LibTCPClose] Done\n");
590
591 return ret;
592 }
593
594 DbgPrint("[lwIP, LibTCPClose] Failed to allocate memory\n");
595
596 return ERR_MEM;
597 }
598
599 void
600 LibTCPAccept(struct tcp_pcb *pcb, struct tcp_pcb *listen_pcb, void *arg)
601 {
602 DbgPrint("[lwIP, LibTCPAccept] Called. (pcb, arg) = (0x%x, 0x%x)\n", pcb, arg);
603
604 ASSERT(arg);
605
606 tcp_arg(pcb, NULL);
607 tcp_recv(pcb, InternalRecvEventHandler);
608 tcp_sent(pcb, InternalSendEventHandler);
609 tcp_arg(pcb, arg);
610
611 tcp_accepted(listen_pcb);
612
613 DbgPrint("[lwIP, LibTCPAccept] Done\n");
614 }
615
616 err_t
617 LibTCPGetHostName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port)
618 {
619 DbgPrint("[lwIP, LibTCPGetHostName] Called. pcb = (0x%x)\n", pcb);
620
621 if (!pcb)
622 return ERR_CLSD;
623
624 *ipaddr = pcb->local_ip;
625 *port = pcb->local_port;
626
627 DbgPrint("[lwIP, LibTCPGetHostName] Got host port: %d\n", *port);
628
629 DbgPrint("[lwIP, LibTCPGetHostName] Done\n");
630
631 return ERR_OK;
632 }
633
634 err_t
635 LibTCPGetPeerName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port)
636 {
637 DbgPrint("[lwIP, LibTCPGetPeerName] pcb = (0x%x)\n", pcb);
638
639 if (!pcb)
640 return ERR_CLSD;
641
642 *ipaddr = pcb->remote_ip;
643 *port = pcb->remote_port;
644
645 DbgPrint("[lwIP, LibTCPGetPeerName] Got remote port: %d\n", *port);
646
647 return ERR_OK;
648 }