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