1/*
2 * Copyright 2007, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * 		Hugo Santos <hugosantos@gmail.com>
7 * 		Ingo Weinhold <bonefish@cs.tu-berlin.de>
8 */
9
10#include <arpa/inet.h>
11#include <signal.h>
12#include <sys/poll.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
15#include <sys/un.h>
16
17#include <map>
18#include <utility>
19
20#include "Context.h"
21#include "MemoryReader.h"
22#include "TypeHandler.h"
23
24using std::map;
25using std::pair;
26
27
28template<typename Type>
29static bool
30obtain_pointer_data(Context &context, Type *data, void *address, uint32 what)
31{
32	if (address == NULL || !context.GetContents(what))
33		return false;
34
35	int32 bytesRead;
36
37	status_t err = context.Reader().Read(address, data, sizeof(Type), bytesRead);
38	if (err != B_OK || bytesRead < (int32)sizeof(Type))
39		return false;
40
41	return true;
42}
43
44
45static string
46format_number(uint32 value)
47{
48	char tmp[32];
49	snprintf(tmp, sizeof(tmp), "%u", (unsigned int)value);
50	return tmp;
51}
52
53
54static string
55read_fdset(Context &context, void *data)
56{
57	// default FD_SETSIZE is 1024
58	unsigned long tmp[1024 / (sizeof(unsigned long) * 8)];
59	int32 bytesRead;
60
61	status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead);
62	if (err != B_OK)
63		return context.FormatPointer(data);
64
65	/* implicitly align to unsigned long lower boundary */
66	int count = bytesRead / sizeof(unsigned long);
67	int added = 0;
68
69	string r;
70	r.reserve(16);
71
72	r = "[";
73
74	for (int i = 0; i < count && added < 8; i++) {
75		for (int j = 0;
76			 j < (int)(sizeof(unsigned long) * 8) && added < 8; j++) {
77			if (tmp[i] & (1UL << j)) {
78				if (added > 0)
79					r += " ";
80				unsigned int fd = i * sizeof(unsigned long) * 8 + j;
81				r += format_number(fd);
82				added++;
83			}
84		}
85	}
86
87	if (added >= 8)
88		r += " ...";
89
90	r += "]";
91
92	return r;
93}
94
95
96template<>
97string
98TypeHandlerImpl<fd_set *>::GetParameterValue(Context &context, Parameter *,
99	const void *address)
100{
101	void *data = *(void **)address;
102	if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
103		return read_fdset(context, data);
104	return context.FormatPointer(data);
105}
106
107
108template<>
109string
110TypeHandlerImpl<fd_set *>::GetReturnValue(Context &context, uint64 value)
111{
112	return context.FormatPointer((void *)value);
113}
114
115
116static string
117format_ltype(Context &context, int ltype)
118{
119	if (context.GetContents(Context::ENUMERATIONS)) {
120#define LTYPE(type) \
121		case type: \
122			return #type
123
124		switch (ltype) {
125			LTYPE(F_RDLCK);
126			LTYPE(F_UNLCK);
127			LTYPE(F_WRLCK);
128		}
129	}
130
131	return context.FormatSigned(ltype);
132}
133
134
135static string
136format_lwhence(Context &context, int lwhence)
137{
138	if (context.GetContents(Context::ENUMERATIONS)) {
139#define LWHENCE(whence) \
140		case whence: \
141			return #whence
142
143		switch (lwhence) {
144			LWHENCE(SEEK_SET);
145			LWHENCE(SEEK_CUR);
146			LWHENCE(SEEK_END);
147			LWHENCE(SEEK_DATA);
148			LWHENCE(SEEK_HOLE);
149		}
150	}
151
152	return context.FormatSigned(lwhence);
153}
154
155
156
157static string
158format_pointer(Context &context, flock *lock)
159{
160	string r;
161
162	r = "l_type=" + format_ltype(context, lock->l_type) + ", ";
163	r += "l_whence=" + format_lwhence(context, lock->l_whence) + ", ";
164	r += "l_start=" + context.FormatSigned(lock->l_start) + ", ";
165	r += "l_len=" + context.FormatSigned(lock->l_len);
166
167	return r;
168}
169
170
171
172static string
173format_signed_number(int32 value)
174{
175	char tmp[32];
176	snprintf(tmp, sizeof(tmp), "%d", (signed int)value);
177	return tmp;
178}
179
180
181static string
182read_pollfd(Context &context, void *data)
183{
184	nfds_t numfds = context.ReadValue<nfds_t>(context.GetSibling(1));
185	if ((int64)numfds <= 0)
186		return string();
187
188	pollfd tmp[numfds];
189	int32 bytesRead;
190
191	status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead);
192	if (err != B_OK)
193		return context.FormatPointer(data);
194
195	int added = 0;
196
197	string r;
198	r.reserve(16);
199
200	r = "[";
201
202	for (nfds_t i = 0; i < numfds && added < 8; i++) {
203		if ((tmp[i].fd == -1 || tmp[i].revents == 0)
204			&& context.GetContents(Context::OUTPUT_VALUES)) {
205			continue;
206		}
207		if (added > 0)
208			r += ", ";
209		r += "{fd=" + format_signed_number(tmp[i].fd);
210		if (tmp[i].fd != -1 && context.GetContents(Context::INPUT_VALUES)) {
211			r += ", events=";
212			int flags = 0;
213			if ((tmp[i].events & POLLIN) != 0) {
214				if (flags > 0)
215					r += "|";
216				r += "POLLIN";
217				flags++;
218			}
219			if ((tmp[i].events & POLLOUT) != 0) {
220				if (flags > 0)
221					r += "|";
222				r += "POLLOUT";
223				flags++;
224			}
225		}
226		if (context.GetContents(Context::OUTPUT_VALUES)) {
227			r += ", revents=";
228			int flags = 0;
229			if ((tmp[i].revents & POLLIN) != 0) {
230				if (flags > 0)
231					r += "|";
232				r += "POLLIN";
233				flags++;
234			}
235			if ((tmp[i].revents & POLLOUT) != 0) {
236				if (flags > 0)
237					r += "|";
238				r += "POLLOUT";
239				flags++;
240			}
241			if ((tmp[i].revents & POLLERR) != 0) {
242				if (flags > 0)
243					r += "|";
244				r += "POLLERR";
245				flags++;
246			}
247			if ((tmp[i].revents & POLLHUP) != 0) {
248				if (flags > 0)
249					r += "|";
250				r += "POLLHUP";
251				flags++;
252			}
253			if ((tmp[i].revents & POLLNVAL) != 0) {
254				if (flags > 0)
255					r += "|";
256				r += "POLLNVAL";
257				flags++;
258			}
259		}
260		added++;
261		r += "}";
262	}
263
264	if (added >= 8)
265		r += " ...";
266
267	r += "]";
268
269	return r;
270}
271
272
273template<>
274string
275TypeHandlerImpl<pollfd *>::GetParameterValue(Context &context, Parameter *,
276	const void *address)
277{
278	void *data = *(void **)address;
279	if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
280		return read_pollfd(context, data);
281	return context.FormatPointer(data);
282}
283
284
285template<>
286string
287TypeHandlerImpl<pollfd *>::GetReturnValue(Context &context, uint64 value)
288{
289	return context.FormatPointer((void *)value);
290}
291
292
293template<typename Type>
294static string
295format_pointer_value(Context &context, void *address)
296{
297	Type data;
298
299	if (obtain_pointer_data(context, &data, address, Context::COMPLEX_STRUCTS))
300		return "{" + format_pointer(context, &data) + "}";
301
302	return context.FormatPointer(address);
303}
304
305
306static string
307get_ipv4_address(in_addr *addr)
308{
309	char tmp[32];
310	snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u",
311		 (unsigned int)(htonl(addr->s_addr) >> 24) & 0xff,
312		 (unsigned int)(htonl(addr->s_addr) >> 16) & 0xff,
313		 (unsigned int)(htonl(addr->s_addr) >>  8) & 0xff,
314		 (unsigned int)(htonl(addr->s_addr) >>  0) & 0xff);
315	return tmp;
316}
317
318
319static string
320format_socket_family(Context &context, int family)
321{
322	if (context.GetContents(Context::ENUMERATIONS)) {
323#define SOCKET_FAMILY(family) \
324		case family: \
325			return #family
326
327		switch (family) {
328			SOCKET_FAMILY(AF_UNSPEC);
329			SOCKET_FAMILY(AF_INET);
330			SOCKET_FAMILY(AF_APPLETALK);
331			SOCKET_FAMILY(AF_ROUTE);
332			SOCKET_FAMILY(AF_LINK);
333			SOCKET_FAMILY(AF_INET6);
334			SOCKET_FAMILY(AF_LOCAL);
335		}
336	}
337
338	return "family = " + context.FormatSigned(family);
339}
340
341
342#if 0
343static string
344format_socket_type(Context &context, int type)
345{
346	if (context.GetContents(Context::ENUMERATIONS)) {
347		switch (type) {
348			case SOCK_RAW:
349				return "SOCK_RAW";
350			case SOCK_DGRAM:
351				return "SOCK_DGRAM";
352			case SOCK_STREAM:
353				return "SOCK_STREAM";
354		}
355	}
356
357	return "type = " + context.FormatSigned(type);
358}
359
360
361static string
362format_socket_protocol(Context &context, int protocol)
363{
364	if (context.GetContents(Context::ENUMERATIONS)) {
365		switch (protocol) {
366			case IPPROTO_IP:
367				return "IPPROTO_IP";
368			case IPPROTO_RAW:
369				return "IPPROTO_RAW";
370			case IPPROTO_ICMP:
371				return "IPPROTO_ICMP";
372			case IPPROTO_UDP:
373				return "IPPROTO_UDP";
374			case IPPROTO_TCP:
375				return "IPPROTO_TCP";
376		}
377	}
378
379	return "protocol = " + context.FormatSigned(protocol);
380}
381#endif
382
383
384static string
385format_pointer(Context &context, sockaddr *saddr)
386{
387	string r;
388
389	r = format_socket_family(context, saddr->sa_family) + ", ";
390
391	switch (saddr->sa_family) {
392		case AF_INET:
393		{
394			sockaddr_in *sin = (sockaddr_in *)saddr;
395			r += get_ipv4_address(&sin->sin_addr);
396			r += "/";
397			r += format_number(ntohs(sin->sin_port));
398			break;
399		}
400		case AF_UNIX:
401		{
402			sockaddr_un *sun = (sockaddr_un *)saddr;
403			r += "path = \"" + string(sun->sun_path) + "\"";
404			break;
405		}
406		default:
407			r += "...";
408			break;
409	}
410
411	return r;
412}
413
414
415static string
416read_sockaddr(Context &context, Parameter *param, void *address)
417{
418	param = context.GetNextSibling(param);
419	if (param == NULL)
420		return context.FormatPointer(address);
421
422	socklen_t addrlen = context.ReadValue<socklen_t>(param);
423
424	sockaddr_storage data;
425
426	if (addrlen > sizeof(data))
427		return context.FormatPointer(address);
428
429	int32 bytesRead;
430	status_t err = context.Reader().Read(address, &data, addrlen, bytesRead);
431	if (err != B_OK)
432		return context.FormatPointer(address);
433
434	return "{" + format_pointer(context, (sockaddr *)&data) + "}";
435}
436
437
438template<>
439string
440TypeHandlerImpl<sockaddr *>::GetParameterValue(Context &context,
441	Parameter *param, const void *address)
442{
443	void *data = *(void **)address;
444	if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
445		return read_sockaddr(context, param, data);
446	return context.FormatPointer(data);
447}
448
449
450template<>
451string
452TypeHandlerImpl<sockaddr *>::GetReturnValue(Context &context, uint64 value)
453{
454	return context.FormatPointer((void *)value);
455}
456
457
458#if 0
459static string
460format_pointer(Context &context, sockaddr_args *args)
461{
462	string r;
463
464	r  =   "addr = " + format_pointer_value<sockaddr>(context, args->address);
465	r += ", len = " + context.FormatUnsigned(args->address_length);
466
467	return r;
468}
469
470
471struct socket_option_info {
472	int level;
473	int option;
474	const char *name;
475	TypeHandler *handler;
476	int length;
477};
478
479#define SOCKET_OPTION_INFO_ENTRY(level, option) \
480	{ level, option, #option, NULL, 0 }
481
482#define SOCKET_OPTION_INFO_ENTRY_TYPE(level, option, type) \
483	{ level, option, #option, TypeHandlerFactory<type *>::Create(), sizeof(type) }
484
485static const socket_option_info kSocketOptions[] = {
486	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_ACCEPTCONN),
487	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_BROADCAST, int32),
488	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_DEBUG, int32),
489	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_DONTROUTE, int32),
490	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_KEEPALIVE, int32),
491	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_OOBINLINE, int32),
492	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_REUSEADDR, int32),
493	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_REUSEPORT, int32),
494	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_USELOOPBACK, int32),
495	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_LINGER),
496	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_SNDBUF, uint32),
497	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_SNDLOWAT),
498	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_SNDTIMEO),
499	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_RCVBUF, uint32),
500	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_RCVLOWAT),
501	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_RCVTIMEO),
502	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_ERROR),
503	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_TYPE),
504	SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_NONBLOCK, int32),
505	SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_BINDTODEVICE),
506	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_OPTIONS),
507	SOCKET_OPTION_INFO_ENTRY_TYPE(IPPROTO_IP, IP_HDRINCL, int),
508	SOCKET_OPTION_INFO_ENTRY_TYPE(IPPROTO_IP, IP_TOS, int),
509	SOCKET_OPTION_INFO_ENTRY_TYPE(IPPROTO_IP, IP_TTL, int),
510	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RECVOPTS),
511	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RECVRETOPTS),
512	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RECVDSTADDR),
513	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RETOPTS),
514	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_MULTICAST_IF),
515	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_MULTICAST_TTL),
516	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_MULTICAST_LOOP),
517	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_ADD_MEMBERSHIP),
518	SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_DROP_MEMBERSHIP),
519	{ -1, -1, NULL, NULL }
520};
521
522class SocketOptionsMap {
523public:
524	typedef map<pair<int, int>, const socket_option_info *> ThisMap;
525
526	SocketOptionsMap()
527	{
528		for (int i = 0; kSocketOptions[i].name != NULL; i++) {
529			fMap.insert(make_pair(
530					std::make_pair(kSocketOptions[i].level,
531						  kSocketOptions[i].option),
532					&kSocketOptions[i]));
533		}
534	}
535
536	const socket_option_info *GetEntry(int level, int option) const
537	{
538		ThisMap::const_iterator i = fMap.find(std::make_pair(level, option));
539		if (i == fMap.end())
540			return NULL;
541
542		return i->second;
543	}
544
545private:
546	ThisMap fMap;
547};
548
549static const SocketOptionsMap kSocketOptionsMap;
550
551
552static string
553format_pointer(Context &context, sockopt_args *args)
554{
555	const socket_option_info *info =
556		kSocketOptionsMap.GetEntry(args->level, args->option);
557
558	string level, option, value;
559
560	if (context.GetContents(Context::ENUMERATIONS)) {
561		switch (args->level) {
562		case SOL_SOCKET:
563			level = "SOL_SOCKET";
564			break;
565		case IPPROTO_IP:
566			level = "IPPROTO_IP";
567			break;
568		}
569
570		if (info != NULL)
571			option = info->name;
572	}
573
574	if (info != NULL && info->length == args->length)
575		value = info->handler->GetParameterValue(context, NULL, &args->value);
576	else {
577		value  = "value = " + context.FormatPointer(args->value);
578		value += ", len = " + context.FormatUnsigned(args->length);
579	}
580
581	if (level.empty())
582		level = "level = " + context.FormatSigned(args->level, sizeof(int));
583
584	if (option.empty())
585		option = "option = " + context.FormatSigned(args->option, sizeof(int));
586
587	return level + ", " + option + ", " + value;
588}
589
590
591static string
592format_pointer(Context &context, socket_args *args)
593{
594	string r;
595
596	r  = format_socket_family(context, args->family) + ", ";
597	r += format_socket_type(context, args->type) + ", ";
598	r += format_socket_protocol(context, args->protocol);
599
600	return r;
601}
602
603
604static string
605format_pointer(Context &context, message_args *msg)
606{
607	string r;
608
609	r +=   "header = " + format_pointer_value<msghdr>(context, msg->header);
610	r += ", flags = " + context.FormatFlags(msg->flags);
611	r += ", data = " + context.FormatPointer(msg->data);
612	r += ", length = " + context.FormatUnsigned(msg->length);
613
614	return r;
615}
616#endif
617
618
619static string
620get_iovec(Context &context, iovec *iov, int iovlen)
621{
622	if (iov == NULL && iovlen == 0)
623		return "(empty)";
624
625	iovec vecs[iovlen];
626	int32 bytesRead;
627
628	string r = "[";
629	status_t err = context.Reader().Read(iov, vecs, sizeof(vecs), bytesRead);
630	if (err != B_OK) {
631		r += context.FormatPointer(iov);
632		r += ", " + context.FormatSigned(iovlen);
633	} else {
634		for (int i = 0; i < iovlen; i++) {
635			if (i > 0)
636				r += ", ";
637			r += "{iov_base=" + context.FormatPointer(vecs[i].iov_base);
638			r += ", iov_len=" + context.FormatUnsigned(vecs[i].iov_len);
639			r += "}";
640		}
641	}
642	return r + "]";
643}
644
645
646static string
647format_pointer(Context &context, msghdr *h)
648{
649	string r;
650
651	r  =   "name = " + format_pointer_value<sockaddr>(context, h->msg_name);
652	r += ", name_len = " + context.FormatUnsigned(h->msg_namelen);
653	r += ", iov = " + get_iovec(context, h->msg_iov, h->msg_iovlen);
654	if (h->msg_control != NULL || h->msg_controllen != 0) {
655		r += ", control = " + context.FormatPointer(h->msg_control);
656		r += ", control_len = " + context.FormatUnsigned(h->msg_controllen);
657	}
658	r += ", flags = " + context.FormatFlags(h->msg_flags);
659
660	return r;
661}
662
663
664static string
665format_pointer(Context &context, ifreq *ifr)
666{
667	return string(ifr->ifr_name) + ", ...";
668}
669
670
671static string
672format_pointer(Context &context, ifconf *conf)
673{
674	unsigned char buffer[sizeof(ifreq) * 8];
675	int maxData = sizeof(buffer);
676	int32 bytesRead;
677
678	if (conf->ifc_len < maxData)
679		maxData = conf->ifc_len;
680
681	string r = "len = " + context.FormatSigned(conf->ifc_len);
682
683	if (conf->ifc_len == 0)
684		return r;
685
686	status_t err = context.Reader().Read(conf->ifc_buf, buffer,
687					     maxData, bytesRead);
688	if (err != B_OK)
689		return r + ", buf = " + context.FormatPointer(conf->ifc_buf);
690
691	r += ", [";
692
693	uint8 *current = buffer, *bufferEnd = buffer + bytesRead;
694	for (int i = 0; i < 8; i++) {
695		if ((bufferEnd - current) < (IF_NAMESIZE + 1))
696			break;
697
698		ifreq *ifr = (ifreq *)current;
699		int size = IF_NAMESIZE + ifr->ifr_addr.sa_len;
700
701		if ((bufferEnd - current) < size)
702			break;
703
704		if (i > 0)
705			r += ", ";
706
707		r += "{" + string(ifr->ifr_name) + ", {"
708			 + format_pointer(context, &ifr->ifr_addr) + "}}";
709
710		current += size;
711	}
712
713	if (current < bufferEnd)
714		r += ", ...";
715
716	return r + "]";
717}
718
719
720static string
721format_pointer(Context &context, siginfo_t *info)
722{
723	string r;
724
725	switch (info->si_code) {
726		case CLD_EXITED:
727			r = "WIFEXITED(s) && WEXITSTATUS(s) == " + context.FormatUnsigned(info->si_status & 0xff);
728			break;
729	}
730	return r;
731}
732
733
734
735template<typename Type>
736class SpecializedPointerTypeHandler : public TypeHandler {
737	string GetParameterValue(Context &context, Parameter *,
738		const void *address)
739	{
740		return format_pointer_value<Type>(context, *(void **)address);
741	}
742
743	string GetReturnValue(Context &context, uint64 value)
744	{
745		return format_pointer_value<Type>(context, (void *)value);
746	}
747};
748
749#define DEFINE_TYPE(name, type) \
750	TypeHandler *create_##name##_type_handler() \
751	{ \
752		return new TypeHandlerImpl<type>(); \
753	}
754
755#define POINTER_TYPE(name, type) \
756	TypeHandler *create_##name##_type_handler() \
757	{ \
758		return new SpecializedPointerTypeHandler<type>(); \
759	}
760
761DEFINE_TYPE(fdset_ptr, fd_set *);
762POINTER_TYPE(flock_ptr, flock);
763POINTER_TYPE(ifconf_ptr, ifconf);
764POINTER_TYPE(ifreq_ptr, ifreq);
765DEFINE_TYPE(pollfd_ptr, pollfd *);
766POINTER_TYPE(siginfo_t_ptr, siginfo_t);
767POINTER_TYPE(msghdr_ptr, msghdr);
768DEFINE_TYPE(sockaddr_ptr, sockaddr *);
769#if 0
770POINTER_TYPE(message_args_ptr, message_args);
771POINTER_TYPE(sockaddr_args_ptr, sockaddr_args);
772POINTER_TYPE(sockopt_args_ptr, sockopt_args);
773POINTER_TYPE(socket_args_ptr, socket_args);
774#endif
775
776