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