xref: /haiku/src/tests/system/network/tcp_shell/tcp_shell.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #define _KERNEL_DEBUG_H
11 	// avoid including the private kernel debug.h header
12 
13 #include "argv.h"
14 #include "tcp.h"
15 #include "utility.h"
16 
17 #include <NetBufferUtilities.h>
18 #include <net_buffer.h>
19 #include <net_datalink.h>
20 #include <net_protocol.h>
21 #include <net_socket.h>
22 #include <net_stack.h>
23 #include <slab/Slab.h>
24 #include <util/AutoLock.h>
25 
26 #include <KernelExport.h>
27 #include <Select.h>
28 #include <module.h>
29 #include <Locker.h>
30 
31 #include <ctype.h>
32 #include <netinet/in.h>
33 #include <new>
34 #include <set>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 
40 struct context {
41 	BLocker		lock;
42 	sem_id		wait_sem;
43 	struct list list;
44 	net_route	route;
45 	bool		server;
46 	thread_id	thread;
47 };
48 
49 struct cmd_entry {
50 	char*	name;
51 	void	(*func)(int argc, char **argv);
52 	char*	help;
53 };
54 
55 struct net_socket_private : net_socket {
56 	struct list_link		link;
57 	team_id					owner;
58 	uint32					max_backlog;
59 	uint32					child_count;
60 	struct list				pending_children;
61 	struct list				connected_children;
62 
63 	struct select_sync_pool	*select_pool;
64 	mutex					lock;
65 };
66 
67 
68 extern "C" status_t _add_builtin_module(module_info *info);
69 extern "C" status_t _get_builtin_dependencies(void);
70 extern bool gDebugOutputEnabled;
71 	// from libkernelland_emu.so
72 
73 extern struct net_buffer_module_info gNetBufferModule;
74 	// from net_buffer.cpp
75 extern net_address_module_info gIPv4AddressModule;
76 	// from ipv4_address.cpp
77 extern module_info *modules[];
78 	// from tcp.cpp
79 
80 
81 extern struct net_protocol_module_info gDomainModule;
82 struct net_interface gInterface;
83 extern struct net_socket_module_info gNetSocketModule;
84 struct net_protocol_module_info *gTCPModule;
85 struct net_socket *gServerSocket, *gClientSocket;
86 static struct context sClientContext, sServerContext;
87 
88 static vint32 sPacketNumber = 1;
89 static double sRandomDrop = 0.0;
90 static set<uint32> sDropList;
91 static bigtime_t sRoundTripTime = 0;
92 static bool sIncreasingRoundTrip = false;
93 static bool sRandomRoundTrip = false;
94 static bool sTCPDump = true;
95 static bigtime_t sStartTime;
96 static double sRandomReorder = 0.0;
97 static set<uint32> sReorderList;
98 static bool sSimultaneousConnect = false;
99 static bool sSimultaneousClose = false;
100 static bool sServerActiveClose = false;
101 
102 static struct net_domain sDomain = {
103 	"ipv4",
104 	AF_INET,
105 	{},
106 	&gDomainModule,
107 	&gIPv4AddressModule
108 };
109 
110 
111 static bool
112 is_server(const sockaddr* addr)
113 {
114 	return ((sockaddr_in*)addr)->sin_port == htons(1024);
115 }
116 
117 
118 static uint8
119 tcp_segment_flags(net_buffer* buffer)
120 {
121 	NetBufferHeaderReader<tcp_header> bufferHeader(buffer);
122 	if (bufferHeader.Status() < B_OK)
123 		return bufferHeader.Status();
124 
125 	tcp_header &header = bufferHeader.Data();
126 	return header.flags;
127 }
128 
129 
130 static bool
131 is_syn(net_buffer* buffer)
132 {
133 	return (tcp_segment_flags(buffer) & TCP_FLAG_SYNCHRONIZE) != 0;
134 }
135 
136 
137 static bool
138 is_fin(net_buffer* buffer)
139 {
140 	return (tcp_segment_flags(buffer) & TCP_FLAG_FINISH) != 0;
141 }
142 
143 
144 //	#pragma mark - stack
145 
146 
147 status_t
148 std_ops(int32, ...)
149 {
150 	return B_OK;
151 }
152 
153 
154 net_domain *
155 get_domain(int family)
156 {
157 	return &sDomain;
158 }
159 
160 
161 status_t
162 register_domain_protocols(int family, int type, int protocol, ...)
163 {
164 	return B_OK;
165 }
166 
167 
168 status_t
169 register_domain_datalink_protocols(int family, int type, ...)
170 {
171 	return B_OK;
172 }
173 
174 
175 static status_t
176 register_domain_receiving_protocol(int family, int type, const char *moduleName)
177 {
178 	return B_OK;
179 }
180 
181 
182 static bool
183 dummy_is_syscall(void)
184 {
185 	return false;
186 }
187 
188 
189 static bool
190 dummy_is_restarted_syscall(void)
191 {
192 	return false;
193 }
194 
195 
196 static void
197 dummy_store_syscall_restart_timeout(bigtime_t timeout)
198 {
199 }
200 
201 
202 static net_stack_module_info gNetStackModule = {
203 	{
204 		NET_STACK_MODULE_NAME,
205 		0,
206 		std_ops
207 	},
208 	NULL, // register_domain,
209 	NULL, // unregister_domain,
210 	get_domain,
211 
212 	register_domain_protocols,
213 	register_domain_datalink_protocols,
214 	register_domain_receiving_protocol,
215 
216 	NULL, // get_domain_receiving_protocol,
217 	NULL, // put_domain_receiving_protocol,
218 
219 	NULL, // register_device_deframer,
220 	NULL, // unregister_device_deframer,
221 	NULL, // register_domain_device_handler,
222 	NULL, // register_device_handler,
223 	NULL, // unregister_device_handler,
224 	NULL, // register_device_monitor,
225 	NULL, // unregister_device_monitor,
226 	NULL, // device_link_changed,
227 	NULL, // device_removed,
228 	NULL, // device_enqueue_buffer,
229 
230 	notify_socket,
231 
232 	checksum,
233 
234 	init_fifo,
235 	uninit_fifo,
236 	fifo_enqueue_buffer,
237 	fifo_dequeue_buffer,
238 	clear_fifo,
239 	fifo_socket_enqueue_buffer,
240 
241 	init_timer,
242 	set_timer,
243 	cancel_timer,
244 	wait_for_timer,
245 	is_timer_active,
246 	is_timer_running,
247 
248 	dummy_is_syscall,
249 	dummy_is_restarted_syscall,
250 	dummy_store_syscall_restart_timeout,
251 	NULL, // restore_syscall_restart_timeout
252 
253 	// ancillary data is not used by TCP
254 };
255 
256 
257 //	#pragma mark - socket
258 
259 
260 status_t
261 socket_create(int family, int type, int protocol, net_socket **_socket)
262 {
263 	net_protocol* domainProtocol;
264 
265 	struct net_socket_private *socket = new (std::nothrow) net_socket_private;
266 	if (socket == NULL)
267 		return B_NO_MEMORY;
268 
269 	memset(socket, 0, sizeof(net_socket));
270 	socket->family = family;
271 	socket->type = type;
272 	socket->protocol = protocol;
273 
274 	mutex_init(&socket->lock, "socket");
275 
276 	// set defaults (may be overridden by the protocols)
277 	socket->send.buffer_size = 65535;
278 	socket->send.low_water_mark = 1;
279 	socket->send.timeout = B_INFINITE_TIMEOUT;
280 	socket->receive.buffer_size = 65535;
281 	socket->receive.low_water_mark = 1;
282 	socket->receive.timeout = B_INFINITE_TIMEOUT;
283 
284 	list_init_etc(&socket->pending_children, offsetof(net_socket_private, link));
285 	list_init_etc(&socket->connected_children, offsetof(net_socket_private, link));
286 
287 	socket->first_protocol = gTCPModule->init_protocol(socket);
288 	if (socket->first_protocol == NULL) {
289 		fprintf(stderr, "tcp_tester: cannot create protocol\n");
290 		mutex_destroy(&socket->lock);
291 		delete socket;
292 		return B_ERROR;
293 	}
294 
295 	socket->first_info = gTCPModule;
296 
297 	domainProtocol = new net_protocol;
298 	domainProtocol->module = &gDomainModule;
299 	domainProtocol->socket = socket;
300 
301 	socket->first_protocol->next = domainProtocol;
302 	socket->first_protocol->module = gTCPModule;
303 	socket->first_protocol->socket = socket;
304 
305 	*_socket = socket;
306 	return B_OK;
307 }
308 
309 
310 void
311 socket_delete(net_socket *_socket)
312 {
313 	net_socket_private *socket = (net_socket_private *)_socket;
314 
315 	if (socket->parent != NULL)
316 		panic("socket still has a parent!");
317 
318 	socket->first_info->uninit_protocol(socket->first_protocol);
319 	mutex_destroy(&socket->lock);
320 	delete socket;
321 }
322 
323 
324 int
325 socket_accept(net_socket *socket, struct sockaddr *address,
326 	socklen_t *_addressLength, net_socket **_acceptedSocket)
327 {
328 	net_socket *accepted;
329 	status_t status = socket->first_info->accept(socket->first_protocol,
330 		&accepted);
331 	if (status < B_OK)
332 		return status;
333 
334 	if (address && *_addressLength > 0) {
335 		memcpy(address, &accepted->peer, min_c(*_addressLength,
336 			accepted->peer.ss_len));
337 		*_addressLength = accepted->peer.ss_len;
338 	}
339 
340 	*_acceptedSocket = accepted;
341 	return B_OK;
342 }
343 
344 
345 int
346 socket_bind(net_socket *socket, const struct sockaddr *address, socklen_t addressLength)
347 {
348 	sockaddr empty;
349 	if (address == NULL) {
350 		// special - try to bind to an empty address, like INADDR_ANY
351 		memset(&empty, 0, sizeof(sockaddr));
352 		empty.sa_len = sizeof(sockaddr);
353 		empty.sa_family = socket->family;
354 
355 		address = &empty;
356 		addressLength = sizeof(sockaddr);
357 	}
358 
359 	if (socket->address.ss_len != 0) {
360 		status_t status = socket->first_info->unbind(socket->first_protocol,
361 			(sockaddr *)&socket->address);
362 		if (status < B_OK)
363 			return status;
364 	}
365 
366 	memcpy(&socket->address, address, sizeof(sockaddr));
367 
368 	status_t status = socket->first_info->bind(socket->first_protocol,
369 		(sockaddr *)address);
370 	if (status < B_OK) {
371 		// clear address again, as binding failed
372 		socket->address.ss_len = 0;
373 	}
374 
375 	return status;
376 }
377 
378 
379 int
380 socket_connect(net_socket *socket, const struct sockaddr *address, socklen_t addressLength)
381 {
382 	if (address == NULL || addressLength == 0)
383 		return ENETUNREACH;
384 
385 	if (socket->address.ss_len == 0) {
386 		// try to bind first
387 		status_t status = socket_bind(socket, NULL, 0);
388 		if (status < B_OK)
389 			return status;
390 	}
391 
392 	return socket->first_info->connect(socket->first_protocol, address);
393 }
394 
395 
396 int
397 socket_listen(net_socket *socket, int backlog)
398 {
399 	status_t status = socket->first_info->listen(socket->first_protocol, backlog);
400 	if (status == B_OK)
401 		socket->options |= SO_ACCEPTCONN;
402 
403 	return status;
404 }
405 
406 
407 ssize_t
408 socket_send(net_socket *socket, const void *data, size_t length, int flags)
409 {
410 	if (socket->peer.ss_len == 0)
411 		return EDESTADDRREQ;
412 
413 	if (socket->address.ss_len == 0) {
414 		// try to bind first
415 		status_t status = socket_bind(socket, NULL, 0);
416 		if (status < B_OK)
417 			return status;
418 	}
419 
420 	// TODO: useful, maybe even computed header space!
421 	net_buffer *buffer = gNetBufferModule.create(256);
422 	if (buffer == NULL)
423 		return ENOBUFS;
424 
425 	// copy data into buffer
426 	if (gNetBufferModule.append(buffer, data, length) < B_OK) {
427 		gNetBufferModule.free(buffer);
428 		return ENOBUFS;
429 	}
430 
431 	buffer->flags = flags;
432 	memcpy(buffer->source, &socket->address, socket->address.ss_len);
433 	memcpy(buffer->destination, &socket->peer, socket->peer.ss_len);
434 
435 	status_t status = socket->first_info->send_data(socket->first_protocol, buffer);
436 	if (status < B_OK) {
437 		gNetBufferModule.free(buffer);
438 		return status;
439 	}
440 
441 	return length;
442 }
443 
444 
445 ssize_t
446 socket_recv(net_socket *socket, void *data, size_t length, int flags)
447 {
448 	net_buffer *buffer;
449 	ssize_t status = socket->first_info->read_data(
450 		socket->first_protocol, length, flags, &buffer);
451 	if (status < B_OK)
452 		return status;
453 
454 	// if 0 bytes we're received, no buffer will be created
455 	if (buffer == NULL)
456 		return 0;
457 
458 	ssize_t bytesReceived = buffer->size;
459 	gNetBufferModule.read(buffer, 0, data, bytesReceived);
460 	gNetBufferModule.free(buffer);
461 
462 	return bytesReceived;
463 }
464 
465 
466 status_t
467 socket_spawn_pending(net_socket *_parent, net_socket **_socket)
468 {
469 	net_socket_private *parent = (net_socket_private *)_parent;
470 
471 	MutexLocker locker(parent->lock);
472 
473 	// We actually accept more pending connections to compensate for those
474 	// that never complete, and also make sure at least a single connection
475 	// can always be accepted
476 	if (parent->child_count > 3 * parent->max_backlog / 2)
477 		return ENOBUFS;
478 
479 	net_socket_private *socket;
480 	status_t status = socket_create(parent->family, parent->type, parent->protocol,
481 		(net_socket **)&socket);
482 	if (status < B_OK)
483 		return status;
484 
485 	// inherit parent's properties
486 	socket->send = parent->send;
487 	socket->receive = parent->receive;
488 	socket->options = parent->options & ~SO_ACCEPTCONN;
489 	socket->linger = parent->linger;
490 	memcpy(&socket->address, &parent->address, parent->address.ss_len);
491 	memcpy(&socket->peer, &parent->peer, parent->peer.ss_len);
492 
493 	// add to the parent's list of pending connections
494 	list_add_item(&parent->pending_children, socket);
495 	socket->parent = parent;
496 	parent->child_count++;
497 
498 	*_socket = socket;
499 	return B_OK;
500 }
501 
502 
503 status_t
504 socket_dequeue_connected(net_socket *_parent, net_socket **_socket)
505 {
506 	net_socket_private *parent = (net_socket_private *)_parent;
507 
508 	mutex_lock(&parent->lock);
509 
510 	net_socket *socket = (net_socket *)list_remove_head_item(&parent->connected_children);
511 	if (socket != NULL) {
512 		socket->parent = NULL;
513 		parent->child_count--;
514 		*_socket = socket;
515 	}
516 
517 	mutex_unlock(&parent->lock);
518 	return socket != NULL ? B_OK : B_ENTRY_NOT_FOUND;
519 }
520 
521 
522 ssize_t
523 socket_count_connected(net_socket *_parent)
524 {
525 	net_socket_private *parent = (net_socket_private *)_parent;
526 
527 	MutexLocker _(parent->lock);
528 
529 	ssize_t count = 0;
530 	void *item = NULL;
531 	while ((item = list_get_next_item(&parent->connected_children,
532 			item)) != NULL) {
533 		count++;
534 	}
535 
536 	return count;
537 }
538 
539 
540 status_t
541 socket_set_max_backlog(net_socket *_socket, uint32 backlog)
542 {
543 	net_socket_private *socket = (net_socket_private *)_socket;
544 
545 	// we enforce an upper limit of connections waiting to be accepted
546 	if (backlog > 256)
547 		backlog = 256;
548 
549 	mutex_lock(&socket->lock);
550 
551 	// first remove the pending connections, then the already connected ones as needed
552 	net_socket *child;
553 	while (socket->child_count > backlog
554 		&& (child = (net_socket *)list_remove_tail_item(&socket->pending_children)) != NULL) {
555 		child->parent = NULL;
556 		socket->child_count--;
557 	}
558 	while (socket->child_count > backlog
559 		&& (child = (net_socket *)list_remove_tail_item(&socket->connected_children)) != NULL) {
560 		child->parent = NULL;
561 		socket_delete(child);
562 		socket->child_count--;
563 	}
564 
565 	socket->max_backlog = backlog;
566 	mutex_unlock(&socket->lock);
567 	return B_OK;
568 }
569 
570 
571 /*!
572 	The socket has been connected. It will be moved to the connected queue
573 	of its parent socket.
574 */
575 status_t
576 socket_connected(net_socket *socket)
577 {
578 	net_socket_private *parent = (net_socket_private *)socket->parent;
579 	if (parent == NULL)
580 		return B_BAD_VALUE;
581 
582 	mutex_lock(&parent->lock);
583 
584 	list_remove_item(&parent->pending_children, socket);
585 	list_add_item(&parent->connected_children, socket);
586 
587 	mutex_unlock(&parent->lock);
588 	return B_OK;
589 }
590 
591 
592 status_t
593 socket_notify(net_socket *_socket, uint8 event, int32 value)
594 {
595 	net_socket_private *socket = (net_socket_private *)_socket;
596 
597 	mutex_lock(&socket->lock);
598 
599 	bool notify = true;
600 
601 	switch (event) {
602 		case B_SELECT_READ:
603 		{
604 			if ((ssize_t)socket->receive.low_water_mark > value && value >= B_OK)
605 				notify = false;
606 			break;
607 		}
608 		case B_SELECT_WRITE:
609 		{
610 			if ((ssize_t)socket->send.low_water_mark > value && value >= B_OK)
611 				notify = false;
612 			break;
613 		}
614 		case B_SELECT_ERROR:
615 			socket->error = value;
616 			break;
617 	}
618 
619 	if (notify)
620 		;
621 
622 	mutex_unlock(&socket->lock);
623 	return B_OK;
624 }
625 
626 
627 net_socket_module_info gNetSocketModule = {
628 	{
629 		NET_SOCKET_MODULE_NAME,
630 		0,
631 		std_ops
632 	},
633 	NULL, // open,
634 	NULL, // close,
635 	NULL, // free,
636 
637 	NULL, // readv,
638 	NULL, // writev,
639 	NULL, // control,
640 
641 	NULL, // read_avail,
642 	NULL, // send_avail,
643 
644 	NULL, // send_data,
645 	NULL, // receive_data,
646 
647 	NULL, // get_option,
648 	NULL, // set_option,
649 	NULL, // get_next_stat,
650 
651 	// connections
652 	socket_spawn_pending,
653 	socket_delete,
654 	socket_dequeue_connected,
655 	socket_count_connected,
656 	socket_set_max_backlog,
657 	socket_connected,
658 
659 	// notifications
660 	NULL, // request_notification,
661 	NULL, // cancel_notification,
662 	socket_notify,
663 
664 	// standard socket API
665 	NULL, // accept,
666 	NULL, // bind,
667 	NULL, // connect,
668 	NULL, // getpeername,
669 	NULL, // getsockname,
670 	NULL, // getsockopt,
671 	NULL, // listen,
672 	NULL, // receive,
673 	NULL, // send,
674 	NULL, // setsockopt,
675 	NULL, // shutdown,
676 	NULL, // socketpair
677 };
678 
679 
680 //	#pragma mark - protocol
681 
682 
683 net_protocol*
684 init_protocol(net_socket** _socket)
685 {
686 	net_socket *socket;
687 	status_t status = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &socket);
688 	if (status < B_OK)
689 		return NULL;
690 
691 	status = socket->first_info->open(socket->first_protocol);
692 	if (status < B_OK) {
693 		fprintf(stderr, "tcp_tester: cannot open client: %s\n", strerror(status));
694 		socket_delete(socket);
695 		return NULL;
696 	}
697 
698 	*_socket = socket;
699 	return socket->first_protocol;
700 }
701 
702 
703 void
704 close_protocol(net_protocol* protocol)
705 {
706 	gTCPModule->close(protocol);
707 	if (gTCPModule->free(protocol) == B_OK)
708 		gTCPModule->uninit_protocol(protocol);
709 		//socket_delete(protocol->socket);
710 }
711 
712 
713 //	#pragma mark - datalink
714 
715 
716 status_t
717 datalink_send_data(struct net_route *route, net_buffer *buffer)
718 {
719 	struct context* context = (struct context*)route->gateway;
720 
721 	buffer->interface = &gInterface;
722 
723 	context->lock.Lock();
724 	list_add_item(&context->list, buffer);
725 	context->lock.Unlock();
726 
727 	release_sem(context->wait_sem);
728 	return B_OK;
729 }
730 
731 
732 status_t
733 datalink_send_datagram(net_protocol *protocol, net_domain *domain,
734 	net_buffer *buffer)
735 {
736 	panic("called");
737 	return B_ERROR;
738 }
739 
740 
741 struct net_route *
742 get_route(struct net_domain *_domain, const struct sockaddr *address)
743 {
744 	if (is_server(address)) {
745 		// to the server
746 		return &sServerContext.route;
747 	}
748 
749 	return &sClientContext.route;
750 }
751 
752 
753 net_datalink_module_info gNetDatalinkModule = {
754 	{
755 		NET_DATALINK_MODULE_NAME,
756 		0,
757 		std_ops
758 	},
759 
760 	NULL, //datalink_control,
761 	datalink_send_data,
762 	datalink_send_datagram,
763 
764 	NULL, //is_local_address,
765 	NULL, //datalink_get_interface,
766 	NULL, //datalink_get_interface_with_address,
767 
768 	NULL, //add_route,
769 	NULL, //remove_route,
770 	get_route,
771 	NULL, //put_route,
772 	NULL, //register_route_info,
773 	NULL, //unregister_route_info,
774 	NULL, //update_route_info
775 };
776 
777 
778 //	#pragma mark - domain
779 
780 
781 status_t
782 domain_open(net_protocol *protocol)
783 {
784 	return B_OK;
785 }
786 
787 
788 status_t
789 domain_close(net_protocol *protocol)
790 {
791 	return B_OK;
792 }
793 
794 
795 status_t
796 domain_free(net_protocol *protocol)
797 {
798 	return B_OK;
799 }
800 
801 
802 status_t
803 domain_connect(net_protocol *protocol, const struct sockaddr *address)
804 {
805 	return B_ERROR;
806 }
807 
808 
809 status_t
810 domain_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
811 {
812 	return EOPNOTSUPP;
813 }
814 
815 
816 status_t
817 domain_control(net_protocol *protocol, int level, int option, void *value,
818 	size_t *_length)
819 {
820 	return B_ERROR;
821 }
822 
823 
824 status_t
825 domain_bind(net_protocol *protocol, const struct sockaddr *address)
826 {
827 	memcpy(&protocol->socket->address, address, sizeof(struct sockaddr_in));
828 	protocol->socket->address.ss_len = sizeof(struct sockaddr_in);
829 		// explicitly set length, as our callers can't be trusted to
830 		// always provide the correct length!
831 	return B_OK;
832 }
833 
834 
835 status_t
836 domain_unbind(net_protocol *protocol, struct sockaddr *address)
837 {
838 	return B_OK;
839 }
840 
841 
842 status_t
843 domain_listen(net_protocol *protocol, int count)
844 {
845 	return EOPNOTSUPP;
846 }
847 
848 
849 status_t
850 domain_shutdown(net_protocol *protocol, int direction)
851 {
852 	return EOPNOTSUPP;
853 }
854 
855 
856 status_t
857 domain_send_data(net_protocol *protocol, net_buffer *buffer)
858 {
859 	// find route
860 	struct net_route *route = get_route(&sDomain, (sockaddr *)&buffer->destination);
861 	if (route == NULL)
862 		return ENETUNREACH;
863 
864 	return datalink_send_data(route, buffer);
865 }
866 
867 
868 status_t
869 domain_send_routed_data(net_protocol *protocol, struct net_route *route,
870 	net_buffer *buffer)
871 {
872 	return datalink_send_data(route, buffer);
873 }
874 
875 
876 ssize_t
877 domain_send_avail(net_protocol *protocol)
878 {
879 	return B_ERROR;
880 }
881 
882 
883 status_t
884 domain_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
885 	net_buffer **_buffer)
886 {
887 	return B_ERROR;
888 }
889 
890 
891 ssize_t
892 domain_read_avail(net_protocol *protocol)
893 {
894 	return B_ERROR;
895 }
896 
897 
898 struct net_domain *
899 domain_get_domain(net_protocol *protocol)
900 {
901 	return &sDomain;
902 }
903 
904 
905 size_t
906 domain_get_mtu(net_protocol *protocol, const struct sockaddr *address)
907 {
908 	return 1480;
909 		// 1500 ethernet - IPv4 header
910 }
911 
912 
913 status_t
914 domain_receive_data(net_buffer *buffer)
915 {
916 	static bigtime_t lastTime = 0;
917 
918 	uint32 packetNumber = atomic_add(&sPacketNumber, 1);
919 
920 	bool drop = false;
921 	if (sDropList.find(packetNumber) != sDropList.end()
922 		|| (sRandomDrop > 0.0 && (1.0 * rand() / RAND_MAX) > sRandomDrop))
923 		drop = true;
924 
925 	if (!drop && (sRoundTripTime > 0 || sRandomRoundTrip || sIncreasingRoundTrip)) {
926 		bigtime_t add = 0;
927 		if (sRandomRoundTrip)
928 			add = (bigtime_t)(1.0 * rand() / RAND_MAX * 500000) - 250000;
929 		if (sIncreasingRoundTrip)
930 			sRoundTripTime += (bigtime_t)(1.0 * rand() / RAND_MAX * 150000);
931 
932 		snooze(sRoundTripTime / 2 + add);
933 	}
934 
935 	if (sTCPDump) {
936 		NetBufferHeaderReader<tcp_header> bufferHeader(buffer);
937 		if (bufferHeader.Status() < B_OK)
938 			return bufferHeader.Status();
939 
940 		tcp_header &header = bufferHeader.Data();
941 
942 		bigtime_t now = system_time();
943 		if (lastTime == 0)
944 			lastTime = now;
945 
946 		printf("\33[0m% 3ld %8.6f (%8.6f) ", packetNumber, (now - sStartTime) / 1000000.0,
947 			(now - lastTime) / 1000000.0);
948 		lastTime = now;
949 
950 		if (is_server((sockaddr *)buffer->source))
951 			printf("\33[31mserver > client: ");
952 		else
953 			printf("client > server: ");
954 
955 		int32 length = buffer->size - header.HeaderLength();
956 
957 		if ((header.flags & TCP_FLAG_PUSH) != 0)
958 			putchar('P');
959 		if ((header.flags & TCP_FLAG_SYNCHRONIZE) != 0)
960 			putchar('S');
961 		if ((header.flags & TCP_FLAG_FINISH) != 0)
962 			putchar('F');
963 		if ((header.flags & TCP_FLAG_RESET) != 0)
964 			putchar('R');
965 		if ((header.flags
966 			& (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_PUSH | TCP_FLAG_RESET)) == 0)
967 			putchar('.');
968 
969 		printf(" %lu:%lu (%lu)", header.Sequence(), header.Sequence() + length, length);
970 		if ((header.flags & TCP_FLAG_ACKNOWLEDGE) != 0)
971 			printf(" ack %lu", header.Acknowledge());
972 
973 		printf(" win %u", header.AdvertisedWindow());
974 
975 		if (header.HeaderLength() > sizeof(tcp_header)) {
976 			int32 size = header.HeaderLength() - sizeof(tcp_header);
977 
978 			tcp_option *option;
979 			uint8 optionsBuffer[1024];
980 			if (gBufferModule->direct_access(buffer, sizeof(tcp_header),
981 					size, (void **)&option) != B_OK) {
982 				if (size > 1024) {
983 					printf("options too large to take into account (%ld bytes)\n", size);
984 					size = 1024;
985 				}
986 
987 				gBufferModule->read(buffer, sizeof(tcp_header), optionsBuffer, size);
988 				option = (tcp_option *)optionsBuffer;
989 			}
990 
991 			while (size > 0) {
992 				uint32 length = 1;
993 				switch (option->kind) {
994 					case TCP_OPTION_END:
995 					case TCP_OPTION_NOP:
996 						break;
997 					case TCP_OPTION_MAX_SEGMENT_SIZE:
998 						printf(" <mss %u>", ntohs(option->max_segment_size));
999 						length = 4;
1000 						break;
1001 					case TCP_OPTION_WINDOW_SHIFT:
1002 						printf(" <ws %u>", option->window_shift);
1003 						length = 3;
1004 						break;
1005 					case TCP_OPTION_TIMESTAMP:
1006 						printf(" <ts %lu:%lu>", option->timestamp.value, option->timestamp.reply);
1007 						length = 10;
1008 						break;
1009 
1010 					default:
1011 						length = option->length;
1012 						// make sure we don't end up in an endless loop
1013 						if (length == 0)
1014 							size = 0;
1015 						break;
1016 				}
1017 
1018 				size -= length;
1019 				option = (tcp_option *)((uint8 *)option + length);
1020 			}
1021 		}
1022 
1023 		if (drop)
1024 			printf(" <DROPPED>");
1025 		printf("\33[0m\n");
1026 	} else if (drop)
1027 		printf("<**** DROPPED %ld ****>\n", packetNumber);
1028 
1029 	if (drop) {
1030 		gNetBufferModule.free(buffer);
1031 		return B_OK;
1032 	}
1033 
1034 	return gTCPModule->receive_data(buffer);
1035 }
1036 
1037 
1038 status_t
1039 domain_error(uint32 code, net_buffer *data)
1040 {
1041 	return B_ERROR;
1042 }
1043 
1044 
1045 status_t
1046 domain_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
1047 	void *errorData)
1048 {
1049 	return B_ERROR;
1050 }
1051 
1052 
1053 net_protocol_module_info gDomainModule = {
1054 	{
1055 		NULL,
1056 		0,
1057 		std_ops
1058 	},
1059 	NET_PROTOCOL_ATOMIC_MESSAGES,
1060 
1061 	NULL, // init
1062 	NULL, // uninit
1063 	domain_open,
1064 	domain_close,
1065 	domain_free,
1066 	domain_connect,
1067 	domain_accept,
1068 	domain_control,
1069 	NULL, // getsockopt
1070 	NULL, // setsockopt
1071 	domain_bind,
1072 	domain_unbind,
1073 	domain_listen,
1074 	domain_shutdown,
1075 	domain_send_data,
1076 	domain_send_routed_data,
1077 	domain_send_avail,
1078 	domain_read_data,
1079 	domain_read_avail,
1080 	domain_get_domain,
1081 	domain_get_mtu,
1082 	domain_receive_data,
1083 	NULL, // deliver_data
1084 	domain_error,
1085 	domain_error_reply,
1086 	NULL, // attach_ancillary_data
1087 	NULL, // process_ancillary_data
1088 };
1089 
1090 
1091 //	#pragma mark - test
1092 
1093 
1094 int32
1095 receiving_thread(void* _data)
1096 {
1097 	struct context* context = (struct context*)_data;
1098 	struct net_buffer* reorderBuffer = NULL;
1099 
1100 	while (true) {
1101 		status_t status;
1102 		do {
1103 			status = acquire_sem(context->wait_sem);
1104 		} while (status == B_INTERRUPTED);
1105 
1106 		if (status < B_OK)
1107 			break;
1108 
1109 		while (true) {
1110 			context->lock.Lock();
1111 			net_buffer* buffer = (net_buffer*)list_remove_head_item(
1112 				&context->list);
1113 			context->lock.Unlock();
1114 
1115 			if (buffer == NULL)
1116 				break;
1117 
1118 			if (sSimultaneousConnect && context->server && is_syn(buffer)) {
1119 				// delay getting the SYN request, and connect as well
1120 				sockaddr_in address;
1121 				memset(&address, 0, sizeof(address));
1122 				address.sin_family = AF_INET;
1123 				address.sin_port = htons(1023);
1124 				address.sin_addr.s_addr = htonl(0xc0a80001);
1125 
1126 				status_t status = socket_connect(gServerSocket,
1127 					(struct sockaddr *)&address, sizeof(struct sockaddr));
1128 				if (status < B_OK)
1129 					fprintf(stderr, "tcp_tester: simultaneous connect failed: %s\n", strerror(status));
1130 
1131 				sSimultaneousConnect = false;
1132 			}
1133 			if (sSimultaneousClose && !context->server && is_fin(buffer)) {
1134 				close_protocol(gClientSocket->first_protocol);
1135 				sSimultaneousClose = false;
1136 			}
1137 			if ((sRandomReorder > 0.0
1138 					|| sReorderList.find(sPacketNumber) != sReorderList.end())
1139 				&& reorderBuffer == NULL
1140 				&& (1.0 * rand() / RAND_MAX) > sRandomReorder) {
1141 				reorderBuffer = buffer;
1142 			} else {
1143 				if (sDomain.module->receive_data(buffer) < B_OK)
1144 					gNetBufferModule.free(buffer);
1145 
1146 				if (reorderBuffer != NULL) {
1147 					if (sDomain.module->receive_data(reorderBuffer) < B_OK)
1148 						gNetBufferModule.free(reorderBuffer);
1149 					reorderBuffer = NULL;
1150 				}
1151 			}
1152 		}
1153 	}
1154 
1155 	return 0;
1156 }
1157 
1158 
1159 int32
1160 server_thread(void*)
1161 {
1162 	while (true) {
1163 		// main accept() loop
1164 		net_socket* connectionSocket;
1165 		sockaddr_in address;
1166 		socklen_t size = sizeof(struct sockaddr_in);
1167 		status_t status = socket_accept(gServerSocket,
1168 			(struct sockaddr *)&address, &size, &connectionSocket);
1169 		if (status < B_OK) {
1170 			fprintf(stderr, "SERVER: accepting failed: %s\n", strerror(status));
1171 			break;
1172 		}
1173 
1174 		printf("server: got connection from %08x\n", address.sin_addr.s_addr);
1175 
1176 		char buffer[1024];
1177 		ssize_t bytesRead;
1178 		while ((bytesRead = socket_recv(connectionSocket, buffer,
1179 				sizeof(buffer), 0)) > 0) {
1180 			printf("server: received %ld bytes\n", bytesRead);
1181 
1182 			if (sServerActiveClose) {
1183 				printf("server: active close\n");
1184 				close_protocol(connectionSocket->first_protocol);
1185 				return 0;
1186 			}
1187 		}
1188 		if (bytesRead < 0)
1189 			printf("server: receiving failed: %s\n", strerror(bytesRead));
1190 		else
1191 			printf("server: peer closed connection.\n");
1192 
1193 		snooze(1000000);
1194 		close_protocol(connectionSocket->first_protocol);
1195 	}
1196 
1197 	return 0;
1198 }
1199 
1200 
1201 void
1202 setup_server()
1203 {
1204 	sockaddr_in address;
1205 	memset(&address, 0, sizeof(address));
1206 	address.sin_len = sizeof(sockaddr_in);
1207 	address.sin_family = AF_INET;
1208 	address.sin_port = htons(1024);
1209 	address.sin_addr.s_addr = INADDR_ANY;
1210 
1211 	status_t status = socket_bind(gServerSocket, (struct sockaddr*)&address,
1212 		sizeof(struct sockaddr));
1213 	if (status < B_OK) {
1214 		fprintf(stderr, "tcp_tester: cannot bind server: %s\n", strerror(status));
1215 		exit(1);
1216 	}
1217 	status = socket_listen(gServerSocket, 40);
1218 	if (status < B_OK) {
1219 		fprintf(stderr, "tcp_tester: server cannot listen: %s\n",
1220 			strerror(status));
1221 		exit(1);
1222 	}
1223 
1224 	thread_id serverThread = spawn_thread(server_thread, "server",
1225 		B_NORMAL_PRIORITY, NULL);
1226 	if (serverThread < B_OK) {
1227 		fprintf(stderr, "tcp_tester: cannot start server: %s\n",
1228 			strerror(serverThread));
1229 		exit(1);
1230 	}
1231 
1232 	resume_thread(serverThread);
1233 }
1234 
1235 
1236 void
1237 setup_context(struct context& context, bool server)
1238 {
1239 	list_init(&context.list);
1240 	context.route.interface = &gInterface;
1241 	context.route.gateway = (sockaddr *)&context;
1242 		// backpointer to the context
1243 	context.route.mtu = 1500;
1244 	context.server = server;
1245 	context.wait_sem = create_sem(0, "receive wait");
1246 
1247 	context.thread = spawn_thread(receiving_thread,
1248 		server ? "server receiver" : "client receiver", B_NORMAL_PRIORITY,
1249 		&context);
1250 	resume_thread(context.thread);
1251 }
1252 
1253 
1254 void
1255 cleanup_context(struct context& context)
1256 {
1257 	delete_sem(context.wait_sem);
1258 
1259 	status_t status;
1260 	wait_for_thread(context.thread, &status);
1261 }
1262 
1263 
1264 //	#pragma mark -
1265 
1266 
1267 static void do_help(int argc, char** argv);
1268 
1269 
1270 static void
1271 do_connect(int argc, char** argv)
1272 {
1273 	sSimultaneousConnect = false;
1274 
1275 	int port = 1024;
1276 	if (argc > 1) {
1277 		if (!strcmp(argv[1], "-s"))
1278 			sSimultaneousConnect = true;
1279 		else if (isdigit(argv[1][0]))
1280 			port = atoi(argv[1]);
1281 		else {
1282 			fprintf(stderr, "usage: connect [-s|<port-number>]\n");
1283 			return;
1284 		}
1285 	}
1286 
1287 	if (sSimultaneousConnect) {
1288 		// bind to a port first, so the other end can find us
1289 		sockaddr_in address;
1290 		memset(&address, 0, sizeof(address));
1291 		address.sin_family = AF_INET;
1292 		address.sin_port = htons(1023);
1293 		address.sin_addr.s_addr = htonl(0xc0a80001);
1294 
1295 		status_t status = socket_bind(gClientSocket, (struct sockaddr *)&address,
1296 			sizeof(struct sockaddr));
1297 		if (status < B_OK) {
1298 			fprintf(stderr, "Could not bind to port 1023: %s\n", strerror(status));
1299 			sSimultaneousConnect = false;
1300 			return;
1301 		}
1302 	}
1303 
1304 	sStartTime = system_time();
1305 
1306 	sockaddr_in address;
1307 	memset(&address, 0, sizeof(address));
1308 	address.sin_family = AF_INET;
1309 	address.sin_port = htons(port);
1310 	address.sin_addr.s_addr = htonl(0xc0a80001);
1311 
1312 	status_t status = socket_connect(gClientSocket, (struct sockaddr *)&address,
1313 		sizeof(struct sockaddr));
1314 	if (status < B_OK)
1315 		fprintf(stderr, "tcp_tester: could not connect: %s\n", strerror(status));
1316 }
1317 
1318 
1319 static void
1320 do_send(int argc, char** argv)
1321 {
1322 	size_t size = 1024;
1323 	if (argc > 1 && isdigit(argv[1][0])) {
1324 		char *unit;
1325 		size = strtoul(argv[1], &unit, 0);
1326 		if (unit != NULL && unit[0]) {
1327 			if (unit[0] == 'k' || unit[0] == 'K')
1328 				size *= 1024;
1329 			else if (unit[0] == 'm' || unit[0] == 'M')
1330 				size *= 1024 * 1024;
1331 			else {
1332 				fprintf(stderr, "unknown unit specified!\n");
1333 				return;
1334 			}
1335 		}
1336 	} else if (argc > 1) {
1337 		fprintf(stderr, "invalid args!\n");
1338 		return;
1339 	}
1340 
1341 	if (size > 4 * 1024 * 1024) {
1342 		printf("amount to send will be limited to 4 MB\n");
1343 		size = 4 * 1024 * 1024;
1344 	}
1345 
1346 	char *buffer = (char *)malloc(size);
1347 	if (buffer == NULL) {
1348 		fprintf(stderr, "not enough memory!\n");
1349 		return;
1350 	}
1351 
1352 	// initialize buffer with some not so random data
1353 	for (uint32 i = 0; i < size; i++) {
1354 		buffer[i] = (char)(i & 0xff);
1355 	}
1356 
1357 	ssize_t bytesWritten = socket_send(gClientSocket, buffer, size, 0);
1358 	if (bytesWritten < B_OK) {
1359 		fprintf(stderr, "failed sending buffer: %s\n", strerror(bytesWritten));
1360 		return;
1361 	}
1362 }
1363 
1364 
1365 static void
1366 do_close(int argc, char** argv)
1367 {
1368 	sSimultaneousClose = false;
1369 	sServerActiveClose = true;
1370 
1371 	if (argc > 1) {
1372 		if (!strcmp(argv[1], "-s"))
1373 			sSimultaneousClose = true;
1374 		else {
1375 			fprintf(stderr, "usage: close [-s]\n");
1376 			return;
1377 		}
1378 	}
1379 
1380 	gClientSocket->send.timeout = 0;
1381 
1382 	char buffer[32767] = {'q'};
1383 	ssize_t bytesWritten = socket_send(gClientSocket, buffer, sizeof(buffer), 0);
1384 	if (bytesWritten < B_OK) {
1385 		fprintf(stderr, "failed sending buffer: %s\n", strerror(bytesWritten));
1386 		return;
1387 	}
1388 }
1389 
1390 
1391 static void
1392 do_drop(int argc, char** argv)
1393 {
1394 	if (argc == 1) {
1395 		// show list of dropped packets
1396 		if (sRandomDrop > 0.0)
1397 			printf("Drop probability is %f\n", sRandomDrop);
1398 
1399 		printf("Drop pakets:\n");
1400 
1401 		set<uint32>::iterator iterator = sDropList.begin();
1402 		uint32 count = 0;
1403 		for (; iterator != sDropList.end(); iterator++) {
1404 			printf("%4lu\n", *iterator);
1405 			count++;
1406 		}
1407 
1408 		if (count == 0)
1409 			printf("<empty>\n");
1410 	} else if (!strcmp(argv[1], "-f")) {
1411 		// flush drop list
1412 		sDropList.clear();
1413 		puts("drop list cleared.");
1414 	} else if (!strcmp(argv[1], "-r")) {
1415 		if (argc < 3) {
1416 			fprintf(stderr, "No drop probability specified.\n");
1417 			return;
1418 		}
1419 
1420 		sRandomDrop = atof(argv[2]);
1421 		if (sRandomDrop < 0.0)
1422 			sRandomDrop = 0;
1423 		else if (sRandomDrop > 1.0)
1424 			sRandomDrop = 1.0;
1425 	} else if (isdigit(argv[1][0])) {
1426 		// add to drop list
1427 		for (int i = 1; i < argc; i++) {
1428 			uint32 packet = strtoul(argv[i], NULL, 0);
1429 			if (packet == 0) {
1430 				fprintf(stderr, "invalid packet number: %s\n", argv[i]);
1431 				break;
1432 			}
1433 
1434 			sDropList.insert(packet);
1435 		}
1436 	} else {
1437 		// print usage
1438 		puts("usage: drop <packet-number> [...]\n"
1439 			"   or: drop -r <probability>\n\n"
1440 			"   or: drop [-f]\n\n"
1441 			"Specifiying -f flushes the drop list, -r sets the probability a packet\n"
1442 			"is dropped; if you called drop without any arguments, the current\n"
1443 			"drop list is dumped.");
1444 	}
1445 }
1446 
1447 
1448 static void
1449 do_reorder(int argc, char** argv)
1450 {
1451 	if (argc == 1) {
1452 		// show list of dropped packets
1453 		if (sRandomReorder > 0.0)
1454 			printf("Reorder probability is %f\n", sRandomReorder);
1455 
1456 		printf("Reorder packets:\n");
1457 
1458 		set<uint32>::iterator iterator = sReorderList.begin();
1459 		uint32 count = 0;
1460 		for (; iterator != sReorderList.end(); iterator++) {
1461 			printf("%4lu\n", *iterator);
1462 			count++;
1463 		}
1464 
1465 		if (count == 0)
1466 			printf("<empty>\n");
1467 	} else if (!strcmp(argv[1], "-f")) {
1468 		// flush reorder list
1469 		sReorderList.clear();
1470 		puts("reorder list cleared.");
1471 	} else if (!strcmp(argv[1], "-r")) {
1472 		if (argc < 3) {
1473 			fprintf(stderr, "No reorder probability specified.\n");
1474 			return;
1475 		}
1476 
1477 		sRandomReorder = atof(argv[2]);
1478 		if (sRandomReorder < 0.0)
1479 			sRandomReorder = 0;
1480 		else if (sRandomReorder > 1.0)
1481 			sRandomReorder = 1.0;
1482 	} else if (isdigit(argv[1][0])) {
1483 		// add to reorder list
1484 		for (int i = 1; i < argc; i++) {
1485 			uint32 packet = strtoul(argv[i], NULL, 0);
1486 			if (packet == 0) {
1487 				fprintf(stderr, "invalid packet number: %s\n", argv[i]);
1488 				break;
1489 			}
1490 
1491 			sReorderList.insert(packet);
1492 		}
1493 	} else {
1494 		// print usage
1495 		puts("usage: reorder <packet-number> [...]\n"
1496 			"   or: reorder -r <probability>\n\n"
1497 			"   or: reorder [-f]\n\n"
1498 			"Specifiying -f flushes the reorder list, -r sets the probability a packet\n"
1499 			"is reordered; if you called reorder without any arguments, the current\n"
1500 			"reorder list is dumped.");
1501 	}
1502 }
1503 
1504 
1505 static void
1506 do_round_trip_time(int argc, char** argv)
1507 {
1508 	if (argc == 1) {
1509 		// show current time
1510 		printf("Current round trip time: %g ms\n", sRoundTripTime / 1000.0);
1511 	} else if (!strcmp(argv[1], "-r")) {
1512 		// toggle random time
1513 		sRandomRoundTrip = !sRandomRoundTrip;
1514 		printf("Round trip time is now %s.\n", sRandomRoundTrip ? "random" : "fixed");
1515 	} else if (!strcmp(argv[1], "-i")) {
1516 		// toggle increasing time
1517 		sIncreasingRoundTrip = !sIncreasingRoundTrip;
1518 		printf("Round trip time is now %s.\n", sIncreasingRoundTrip ? "increasing" : "fixed");
1519 	} else if (isdigit(argv[1][0])) {
1520 		// set time
1521 		sRoundTripTime = 1000LL * strtoul(argv[1], NULL, 0);
1522 	} else {
1523 		// print usage
1524 		puts("usage: rtt <time in ms>\n"
1525 			"   or: rtt [-r|-i]\n\n"
1526 			"Specifiying -r sets random time, -i causes the times to increase over time;\n"
1527 			"witout any arguments, the current time is printed.");
1528 	}
1529 }
1530 
1531 
1532 static void
1533 do_dprintf(int argc, char** argv)
1534 {
1535 	if (argc > 1)
1536 		gDebugOutputEnabled = !strcmp(argv[1], "on");
1537 	else
1538 		gDebugOutputEnabled = !gDebugOutputEnabled;
1539 
1540 	printf("debug output turned %s.\n", gDebugOutputEnabled ? "on" : "off");
1541 }
1542 
1543 
1544 static cmd_entry sBuiltinCommands[] = {
1545 	{"connect", do_connect, "Connects the client"},
1546 	{"send", do_send, "Sends data from the client to the server"},
1547 	{"close", do_close, "Performs an active or simultaneous close"},
1548 	{"dprintf", do_dprintf, "Toggles debug output"},
1549 	{"drop", do_drop, "Lets you drop packets during transfer"},
1550 	{"reorder", do_reorder, "Lets you reorder packets during transfer"},
1551 	{"help", do_help, "prints this help text"},
1552 	{"rtt", do_round_trip_time, "Specifies the round trip time"},
1553 	{"quit", NULL, "exits the application"},
1554 	{NULL, NULL, NULL},
1555 };
1556 
1557 
1558 static void
1559 do_help(int argc, char** argv)
1560 {
1561 	printf("Available commands:\n");
1562 
1563 	for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) {
1564 		printf("%8s - %s\n", command->name, command->help);
1565 	}
1566 }
1567 
1568 
1569 //	#pragma mark -
1570 
1571 
1572 int
1573 main(int argc, char** argv)
1574 {
1575 	status_t status = init_timers();
1576 	if (status < B_OK) {
1577 		fprintf(stderr, "tcp_tester: Could not initialize timers: %s\n",
1578 			strerror(status));
1579 		return 1;
1580 	}
1581 
1582 	_add_builtin_module((module_info*)&gNetStackModule);
1583 	_add_builtin_module((module_info*)&gNetBufferModule);
1584 	_add_builtin_module((module_info*)&gNetSocketModule);
1585 	_add_builtin_module((module_info*)&gNetDatalinkModule);
1586 	_add_builtin_module(modules[0]);
1587 	if (_get_builtin_dependencies() < B_OK) {
1588 		fprintf(stderr, "tcp_tester: Could not initialize modules: %s\n",
1589 			strerror(status));
1590 		return 1;
1591 	}
1592 
1593 	sockaddr_in interfaceAddress;
1594 	interfaceAddress.sin_len = sizeof(sockaddr_in);
1595 	interfaceAddress.sin_family = AF_INET;
1596 	interfaceAddress.sin_addr.s_addr = htonl(0xc0a80001);
1597 	gInterface.address = (sockaddr*)&interfaceAddress;
1598 	gInterface.domain = &sDomain;
1599 
1600 	status = get_module("network/protocols/tcp/v1", (module_info **)&gTCPModule);
1601 	if (status < B_OK) {
1602 		fprintf(stderr, "tcp_tester: Could not open TCP module: %s\n",
1603 			strerror(status));
1604 		return 1;
1605 	}
1606 
1607 	net_protocol* client = init_protocol(&gClientSocket);
1608 	if (client == NULL)
1609 		return 1;
1610 	net_protocol* server = init_protocol(&gServerSocket);
1611 	if (server == NULL)
1612 		return 1;
1613 
1614 	setup_context(sClientContext, false);
1615 	setup_context(sServerContext, true);
1616 
1617 	printf("*** Server: %p (%ld), Client: %p (%ld)\n", server,
1618 		sServerContext.thread, client, sClientContext.thread);
1619 
1620 	setup_server();
1621 
1622 	while (true) {
1623 		printf("> ");
1624 		fflush(stdout);
1625 
1626 		char line[1024];
1627 		if (fgets(line, sizeof(line), stdin) == NULL)
1628 			break;
1629 
1630         argc = 0;
1631         argv = build_argv(line, &argc);
1632         if (argv == NULL || argc == 0)
1633             continue;
1634 
1635         int length = strlen(argv[0]);
1636 
1637 #if 0
1638 		char *newLine = strchr(line, '\n');
1639 		if (newLine != NULL)
1640 			newLine[0] = '\0';
1641 #endif
1642 
1643 		if (!strcmp(argv[0], "quit")
1644 			|| !strcmp(argv[0], "exit")
1645 			|| !strcmp(argv[0], "q"))
1646 			break;
1647 
1648 		bool found = false;
1649 
1650 		for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) {
1651 			if (!strncmp(command->name, argv[0], length)) {
1652 				command->func(argc, argv);
1653 				found = true;
1654 				break;
1655 			}
1656 		}
1657 
1658 		if (!found)
1659 			fprintf(stderr, "Unknown command \"%s\". Type \"help\" for a list of commands.\n", argv[0]);
1660 
1661 		free(argv);
1662 	}
1663 
1664 	close_protocol(client);
1665 	close_protocol(server);
1666 
1667 	snooze(2000000);
1668 
1669 	cleanup_context(sClientContext);
1670 	cleanup_context(sServerContext);
1671 
1672 	put_module("network/protocols/tcp/v1");
1673 	uninit_timers();
1674 	return 0;
1675 }
1676