1 /* 2 * Copyright 2005-2009, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 10 #include <Message.h> 11 #include <MessageAdapter.h> 12 #include <MessagePrivate.h> 13 #include <MessageUtils.h> 14 15 #include <DirectMessageTarget.h> 16 #include <MessengerPrivate.h> 17 #include <TokenSpace.h> 18 #include <util/KMessage.h> 19 20 #include <Application.h> 21 #include <AppMisc.h> 22 #include <BlockCache.h> 23 #include <Entry.h> 24 #include <MessageQueue.h> 25 #include <Messenger.h> 26 #include <Path.h> 27 #include <Point.h> 28 #include <Rect.h> 29 #include <String.h> 30 31 #include <assert.h> 32 #include <ctype.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 37 #include "tracing_config.h" 38 // kernel tracing configuration 39 40 //#define VERBOSE_DEBUG_OUTPUT 41 #ifdef VERBOSE_DEBUG_OUTPUT 42 #define DEBUG_FUNCTION_ENTER \ 43 debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \ 44 " data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \ 45 find_thread(NULL), this, fHeader, fFields, fData, what, (char *)&what, \ 46 __LINE__, __PRETTY_FUNCTION__); 47 48 #define DEBUG_FUNCTION_ENTER2 \ 49 debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \ 50 __LINE__, __PRETTY_FUNCTION__); 51 #else 52 #define DEBUG_FUNCTION_ENTER /* nothing */ 53 #define DEBUG_FUNCTION_ENTER2 /* nothing */ 54 #endif 55 56 #if BMESSAGE_TRACING 57 # define KTRACE(format...) ktrace_printf(format) 58 #else 59 # define KTRACE(format...) 60 #endif 61 62 63 const char *B_SPECIFIER_ENTRY = "specifiers"; 64 const char *B_PROPERTY_ENTRY = "property"; 65 const char *B_PROPERTY_NAME_ENTRY = "name"; 66 67 68 static status_t handle_reply(port_id replyPort, int32 *pCode, bigtime_t timeout, 69 BMessage *reply); 70 71 extern "C" { 72 // private os function to set the owning team of an area 73 status_t _kern_transfer_area(area_id area, void **_address, 74 uint32 addressSpec, team_id target); 75 } 76 77 78 BBlockCache *BMessage::sMsgCache = NULL; 79 port_id BMessage::sReplyPorts[sNumReplyPorts]; 80 long BMessage::sReplyPortInUse[sNumReplyPorts]; 81 82 83 template<typename Type> 84 static void 85 print_to_stream_type(uint8 *pointer) 86 { 87 Type *item = (Type *)pointer; 88 item->PrintToStream(); 89 } 90 91 92 template<typename Type> 93 static void 94 print_type(const char *format, uint8 *pointer) 95 { 96 Type *item = (Type *)pointer; 97 printf(format, *item, *item); 98 } 99 100 101 static status_t 102 handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout, 103 BMessage *reply) 104 { 105 DEBUG_FUNCTION_ENTER2; 106 ssize_t size; 107 do { 108 size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout); 109 } while (size == B_INTERRUPTED); 110 111 if (size < 0) 112 return size; 113 114 status_t result; 115 char *buffer = (char *)malloc(size); 116 if (buffer == NULL) 117 return B_NO_MEMORY; 118 119 do { 120 result = read_port(replyPort, _code, buffer, size); 121 } while (result == B_INTERRUPTED); 122 123 if (result < 0 || *_code != kPortMessageCode) { 124 free(buffer); 125 return result < 0 ? result : B_ERROR; 126 } 127 128 result = reply->Unflatten(buffer); 129 free(buffer); 130 return result; 131 } 132 133 134 // #pragma mark - 135 136 137 BMessage::BMessage() 138 { 139 DEBUG_FUNCTION_ENTER; 140 _InitCommon(true); 141 } 142 143 144 BMessage::BMessage(BMessage *other) 145 { 146 DEBUG_FUNCTION_ENTER; 147 _InitCommon(false); 148 *this = *other; 149 } 150 151 152 BMessage::BMessage(uint32 _what) 153 { 154 DEBUG_FUNCTION_ENTER; 155 _InitCommon(true); 156 fHeader->what = what = _what; 157 } 158 159 160 BMessage::BMessage(const BMessage &other) 161 { 162 DEBUG_FUNCTION_ENTER; 163 _InitCommon(false); 164 *this = other; 165 } 166 167 168 BMessage::~BMessage() 169 { 170 DEBUG_FUNCTION_ENTER; 171 _Clear(); 172 } 173 174 175 BMessage & 176 BMessage::operator=(const BMessage &other) 177 { 178 DEBUG_FUNCTION_ENTER; 179 180 if (this == &other) 181 return *this; 182 183 _Clear(); 184 185 fHeader = (message_header *)malloc(sizeof(message_header)); 186 if (fHeader == NULL) 187 return *this; 188 189 memcpy(fHeader, other.fHeader, sizeof(message_header)); 190 191 // Clear some header flags inherited from the original message that don't 192 // apply to the clone. 193 fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE 194 | MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED 195 | MESSAGE_FLAG_WAS_DROPPED | MESSAGE_FLAG_PASS_BY_AREA); 196 // Note, that BeOS R5 seems to keep the reply info. 197 198 if (fHeader->field_count > 0) { 199 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 200 fFields = (field_header *)malloc(fieldsSize); 201 if (fFields == NULL) { 202 fHeader->field_count = 0; 203 fHeader->data_size = 0; 204 } else 205 memcpy(fFields, other.fFields, fieldsSize); 206 } 207 208 if (fHeader->data_size > 0) { 209 fData = (uint8 *)malloc(fHeader->data_size); 210 if (fData == NULL) { 211 fHeader->field_count = 0; 212 free(fFields); 213 fFields = NULL; 214 } else 215 memcpy(fData, other.fData, fHeader->data_size); 216 } 217 218 fHeader->what = what = other.what; 219 fHeader->message_area = -1; 220 fFieldsAvailable = 0; 221 fDataAvailable = 0; 222 223 return *this; 224 } 225 226 227 void * 228 BMessage::operator new(size_t size) 229 { 230 DEBUG_FUNCTION_ENTER2; 231 void *pointer = sMsgCache->Get(size); 232 return pointer; 233 } 234 235 236 void * 237 BMessage::operator new(size_t, void *pointer) 238 { 239 DEBUG_FUNCTION_ENTER2; 240 return pointer; 241 } 242 243 244 void 245 BMessage::operator delete(void *pointer, size_t size) 246 { 247 DEBUG_FUNCTION_ENTER2; 248 sMsgCache->Save(pointer, size); 249 } 250 251 252 bool 253 BMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder, 254 bool deep) const 255 { 256 if (this == &other) 257 return true; 258 259 if (fHeader->field_count != other.fHeader->field_count) 260 return false; 261 262 for (uint32 i = 0; i < fHeader->field_count; i++) { 263 field_header *field = &fFields[i]; 264 field_header *otherField = NULL; 265 266 const char *name = (const char *)fData + field->offset; 267 if (ignoreFieldOrder) { 268 if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK) 269 return false; 270 } else { 271 otherField = &other.fFields[i]; 272 if (otherField->name_length != field->name_length) 273 return false; 274 275 const char *otherName = (const char *)other.fData 276 + otherField->offset; 277 if (strncmp(name, otherName, field->name_length) != 0) 278 return false; 279 } 280 281 if (otherField->type != field->type || otherField->count != field->count) 282 return false; 283 284 uint8 *data = fData + field->offset + field->name_length; 285 uint8 *otherData = other.fData + otherField->offset 286 + otherField->name_length; 287 288 bool needsMemCompare = true; 289 if (deep && field->type == B_MESSAGE_TYPE) { 290 BMessage message, otherMessage; 291 if (message.Unflatten((const char *)data) == B_OK 292 && otherMessage.Unflatten((const char *)otherData) == B_OK) { 293 if (!message.HasSameData(ignoreFieldOrder, deep)) 294 return false; 295 needsMemCompare = false; 296 } 297 } 298 299 if (needsMemCompare) { 300 if (otherField->data_size != field->data_size) 301 return false; 302 if (memcmp(data, otherData, field->data_size) != 0) 303 return false; 304 } 305 } 306 307 return true; 308 } 309 310 311 status_t 312 BMessage::_InitCommon(bool initHeader) 313 { 314 DEBUG_FUNCTION_ENTER; 315 what = 0; 316 317 fHeader = NULL; 318 fFields = NULL; 319 fData = NULL; 320 321 fFieldsAvailable = 0; 322 fDataAvailable = 0; 323 324 fOriginal = NULL; 325 fQueueLink = NULL; 326 327 if (initHeader) 328 return _InitHeader(); 329 330 fHeader = NULL; 331 return B_OK; 332 } 333 334 335 status_t 336 BMessage::_InitHeader() 337 { 338 DEBUG_FUNCTION_ENTER; 339 if (fHeader == NULL) { 340 fHeader = (message_header *)malloc(sizeof(message_header)); 341 if (fHeader == NULL) 342 return B_NO_MEMORY; 343 } 344 345 memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table)); 346 347 fHeader->format = MESSAGE_FORMAT_HAIKU; 348 fHeader->flags = MESSAGE_FLAG_VALID; 349 fHeader->what = what; 350 fHeader->current_specifier = -1; 351 fHeader->message_area = -1; 352 353 fHeader->target = B_NULL_TOKEN; 354 fHeader->reply_target = B_NULL_TOKEN; 355 fHeader->reply_port = -1; 356 fHeader->reply_team = -1; 357 358 // initializing the hash table to -1 because 0 is a valid index 359 fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE; 360 memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table)); 361 return B_OK; 362 } 363 364 365 status_t 366 BMessage::_Clear() 367 { 368 DEBUG_FUNCTION_ENTER; 369 if (fHeader != NULL) { 370 // We're going to destroy all information of this message. If there's 371 // still someone waiting for a reply to this message, we have to send 372 // one now. 373 if (IsSourceWaiting()) 374 SendReply(B_NO_REPLY); 375 376 if (fHeader->message_area >= 0) 377 _Dereference(); 378 379 free(fHeader); 380 fHeader = NULL; 381 } 382 383 free(fFields); 384 fFields = NULL; 385 free(fData); 386 fData = NULL; 387 388 fFieldsAvailable = 0; 389 fDataAvailable = 0; 390 391 delete fOriginal; 392 fOriginal = NULL; 393 394 return B_OK; 395 } 396 397 398 status_t 399 BMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound, 400 type_code *typeFound, int32 *countFound) const 401 { 402 DEBUG_FUNCTION_ENTER; 403 if (index < 0 || (uint32)index >= fHeader->field_count) 404 return B_BAD_INDEX; 405 406 if (typeRequested == B_ANY_TYPE) { 407 if (nameFound) 408 *nameFound = (char *)fData + fFields[index].offset; 409 if (typeFound) 410 *typeFound = fFields[index].type; 411 if (countFound) 412 *countFound = fFields[index].count; 413 return B_OK; 414 } 415 416 int32 counter = -1; 417 field_header *field = fFields; 418 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 419 if (field->type == typeRequested) 420 counter++; 421 422 if (counter == index) { 423 if (nameFound) 424 *nameFound = (char *)fData + field->offset; 425 if (typeFound) 426 *typeFound = field->type; 427 if (countFound) 428 *countFound = field->count; 429 return B_OK; 430 } 431 } 432 433 if (counter == -1) 434 return B_BAD_TYPE; 435 436 return B_BAD_INDEX; 437 } 438 439 440 status_t 441 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound) 442 const 443 { 444 DEBUG_FUNCTION_ENTER; 445 if (countFound) 446 *countFound = 0; 447 448 field_header *field = NULL; 449 status_t result = _FindField(name, B_ANY_TYPE, &field); 450 if (result < B_OK || field == NULL) 451 return result; 452 453 if (typeFound) 454 *typeFound = field->type; 455 if (countFound) 456 *countFound = field->count; 457 458 return B_OK; 459 } 460 461 462 status_t 463 BMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize) 464 const 465 { 466 DEBUG_FUNCTION_ENTER; 467 field_header *field = NULL; 468 status_t result = _FindField(name, B_ANY_TYPE, &field); 469 if (result < B_OK || field == NULL) 470 return result; 471 472 if (typeFound) 473 *typeFound = field->type; 474 if (fixedSize) 475 *fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0; 476 477 return B_OK; 478 } 479 480 481 int32 482 BMessage::CountNames(type_code type) const 483 { 484 DEBUG_FUNCTION_ENTER; 485 if (type == B_ANY_TYPE) 486 return fHeader->field_count; 487 488 int32 count = 0; 489 field_header *field = fFields; 490 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 491 if (field->type == type) 492 count++; 493 } 494 495 return count; 496 } 497 498 499 bool 500 BMessage::IsEmpty() const 501 { 502 DEBUG_FUNCTION_ENTER; 503 return fHeader->field_count == 0; 504 } 505 506 507 bool 508 BMessage::IsSystem() const 509 { 510 DEBUG_FUNCTION_ENTER; 511 char a = char(what >> 24); 512 char b = char(what >> 16); 513 char c = char(what >> 8); 514 char d = char(what); 515 516 // The BeBook says: 517 // ... we've adopted a strict convention for assigning values to all 518 // Be-defined constants. The value assigned will always be formed by 519 // combining four characters into a multicharacter constant, with the 520 // characters limited to uppercase letters and the underbar 521 // Between that and what's in AppDefs.h, this algo seems like a safe bet: 522 if (a == '_' && isupper(b) && isupper(c) && isupper(d)) 523 return true; 524 525 return false; 526 } 527 528 529 bool 530 BMessage::IsReply() const 531 { 532 DEBUG_FUNCTION_ENTER; 533 return (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0; 534 } 535 536 537 void 538 BMessage::PrintToStream() const 539 { 540 _PrintToStream(""); 541 printf("}\n"); 542 } 543 544 545 void 546 BMessage::_PrintToStream(const char* indent) const 547 { 548 DEBUG_FUNCTION_ENTER; 549 550 int32 value = B_BENDIAN_TO_HOST_INT32(what); 551 printf("BMessage("); 552 if (isprint(*(char *)&value)) 553 printf("'%.4s'", (char *)&value); 554 else 555 printf("0x%lx", what); 556 printf(") {\n"); 557 558 if (fHeader == NULL || fFields == NULL || fData == NULL) 559 return; 560 561 field_header *field = fFields; 562 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 563 value = B_BENDIAN_TO_HOST_INT32(field->type); 564 ssize_t size = 0; 565 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0) 566 size = field->data_size / field->count; 567 568 uint8 *pointer = fData + field->offset + field->name_length; 569 for (uint32 j = 0; j < field->count; j++) { 570 if (field->count == 1) { 571 printf("%s %s = ", indent, 572 (char *)(fData + field->offset)); 573 } else { 574 printf("%s %s[%ld] = ", indent, 575 (char *)(fData + field->offset), j); 576 } 577 578 switch (field->type) { 579 case B_RECT_TYPE: 580 print_to_stream_type<BRect>(pointer); 581 break; 582 583 case B_POINT_TYPE: 584 print_to_stream_type<BPoint>(pointer); 585 break; 586 587 case B_STRING_TYPE: 588 { 589 size = *(uint32 *)pointer; 590 pointer += sizeof(uint32); 591 printf("string(\"%s\", %ld bytes)\n", (char *)pointer, 592 size); 593 break; 594 } 595 596 case B_INT8_TYPE: 597 print_type<int8>("int8(0x%hx or %d or '%.1s')\n", pointer); 598 break; 599 600 case B_UINT8_TYPE: 601 print_type<uint8>("uint8(0x%hx or %u or '%.1s')\n", 602 pointer); 603 break; 604 605 case B_INT16_TYPE: 606 print_type<int16>("int16(0x%x or %d)\n", pointer); 607 break; 608 609 case B_UINT16_TYPE: 610 print_type<uint16>("uint16(0x%x or %u\n", pointer); 611 break; 612 613 case B_INT32_TYPE: 614 print_type<int32>("int32(0x%lx or %ld)\n", pointer); 615 break; 616 617 case B_UINT32_TYPE: 618 print_type<uint32>("uint32(0x%lx or %lu\n", pointer); 619 break; 620 621 case B_INT64_TYPE: 622 print_type<int64>("int64(0x%Lx or %Ld)\n", pointer); 623 break; 624 625 case B_UINT64_TYPE: 626 print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer); 627 break; 628 629 case B_BOOL_TYPE: 630 printf("bool(%s)\n", *((bool *)pointer) != 0 631 ? "true" : "false"); 632 break; 633 634 case B_FLOAT_TYPE: 635 print_type<float>("float(%.4f)\n", pointer); 636 break; 637 638 case B_DOUBLE_TYPE: 639 print_type<double>("double(%.8f)\n", pointer); 640 break; 641 642 case B_REF_TYPE: 643 { 644 size = *(uint32 *)pointer; 645 pointer += sizeof(uint32); 646 entry_ref ref; 647 BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size); 648 649 printf("entry_ref(device=%ld, directory=%lld, " 650 "name=\"%s\", ", ref.device, ref.directory, ref.name); 651 652 BPath path(&ref); 653 printf("path=\"%s\")\n", path.Path()); 654 break; 655 } 656 657 case B_MESSAGE_TYPE: 658 { 659 char buffer[1024]; 660 sprintf(buffer, "%s ", indent); 661 662 BMessage message; 663 size = *(uint32 *)pointer; 664 pointer += sizeof(uint32); 665 status_t result = message.Unflatten((const char *)pointer); 666 if (result != B_OK) { 667 printf("failed unflatten: %s\n", strerror(result)); 668 break; 669 } 670 671 message._PrintToStream(buffer); 672 printf("%s }\n", indent); 673 break; 674 } 675 676 default: 677 { 678 printf("(type = '%.4s')(size = %ld)\n", (char *)&value, 679 size); 680 break; 681 } 682 } 683 684 pointer += size; 685 } 686 } 687 } 688 689 690 status_t 691 BMessage::Rename(const char *oldEntry, const char *newEntry) 692 { 693 DEBUG_FUNCTION_ENTER; 694 if (oldEntry == NULL || newEntry == NULL) 695 return B_BAD_VALUE; 696 697 if (fHeader->message_area >= 0) 698 _CopyForWrite(); 699 700 uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size; 701 int32 *nextField = &fHeader->hash_table[hash]; 702 703 while (*nextField >= 0) { 704 field_header *field = &fFields[*nextField]; 705 706 if (strncmp((const char *)(fData + field->offset), oldEntry, 707 field->name_length) == 0) { 708 // nextField points to the field for oldEntry, save it and unlink 709 int32 index = *nextField; 710 *nextField = field->next_field; 711 field->next_field = -1; 712 713 hash = _HashName(newEntry) % fHeader->hash_table_size; 714 nextField = &fHeader->hash_table[hash]; 715 while (*nextField >= 0) 716 nextField = &fFields[*nextField].next_field; 717 *nextField = index; 718 719 int32 newLength = strlen(newEntry) + 1; 720 status_t result = _ResizeData(field->offset + 1, 721 newLength - field->name_length); 722 if (result < B_OK) 723 return result; 724 725 memcpy(fData + field->offset, newEntry, newLength); 726 field->name_length = newLength; 727 return B_OK; 728 } 729 730 nextField = &field->next_field; 731 } 732 733 return B_NAME_NOT_FOUND; 734 } 735 736 737 bool 738 BMessage::WasDelivered() const 739 { 740 DEBUG_FUNCTION_ENTER; 741 return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0; 742 } 743 744 745 bool 746 BMessage::IsSourceWaiting() const 747 { 748 DEBUG_FUNCTION_ENTER; 749 return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0 750 && (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0; 751 } 752 753 754 bool 755 BMessage::IsSourceRemote() const 756 { 757 DEBUG_FUNCTION_ENTER; 758 return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0 759 && fHeader->reply_team != BPrivate::current_team(); 760 } 761 762 763 BMessenger 764 BMessage::ReturnAddress() const 765 { 766 DEBUG_FUNCTION_ENTER; 767 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) { 768 BMessenger messenger; 769 BMessenger::Private(messenger).SetTo(fHeader->reply_team, 770 fHeader->reply_port, fHeader->reply_target); 771 return messenger; 772 } 773 774 return BMessenger(); 775 } 776 777 778 const BMessage * 779 BMessage::Previous() const 780 { 781 DEBUG_FUNCTION_ENTER; 782 /* ToDo: test if the "_previous_" field is used in R5 */ 783 if (fOriginal == NULL) { 784 fOriginal = new BMessage(); 785 786 if (FindMessage("_previous_", fOriginal) != B_OK) { 787 delete fOriginal; 788 fOriginal = NULL; 789 } 790 } 791 792 return fOriginal; 793 } 794 795 796 bool 797 BMessage::WasDropped() const 798 { 799 DEBUG_FUNCTION_ENTER; 800 return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0; 801 } 802 803 804 BPoint 805 BMessage::DropPoint(BPoint *offset) const 806 { 807 DEBUG_FUNCTION_ENTER; 808 if (offset) 809 *offset = FindPoint("_drop_offset_"); 810 811 return FindPoint("_drop_point_"); 812 } 813 814 815 status_t 816 BMessage::SendReply(uint32 command, BHandler *replyTo) 817 { 818 DEBUG_FUNCTION_ENTER; 819 BMessage message(command); 820 return SendReply(&message, replyTo); 821 } 822 823 824 status_t 825 BMessage::SendReply(BMessage *reply, BHandler *replyTo, bigtime_t timeout) 826 { 827 DEBUG_FUNCTION_ENTER; 828 BMessenger messenger(replyTo); 829 return SendReply(reply, messenger, timeout); 830 } 831 832 833 status_t 834 BMessage::SendReply(BMessage *reply, BMessenger replyTo, bigtime_t timeout) 835 { 836 DEBUG_FUNCTION_ENTER; 837 BMessenger messenger; 838 BMessenger::Private messengerPrivate(messenger); 839 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port, 840 fHeader->reply_target); 841 842 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) { 843 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0) 844 return B_DUPLICATE_REPLY; 845 846 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 847 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 848 status_t result = messenger.SendMessage(reply, replyTo, timeout); 849 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 850 851 if (result != B_OK) { 852 if (set_port_owner(messengerPrivate.Port(), 853 messengerPrivate.Team()) == B_BAD_TEAM_ID) { 854 delete_port(messengerPrivate.Port()); 855 } 856 } 857 858 return result; 859 } 860 861 // no reply required 862 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 863 return B_BAD_REPLY; 864 865 reply->AddMessage("_previous_", this); 866 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 867 status_t result = messenger.SendMessage(reply, replyTo, timeout); 868 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 869 reply->RemoveName("_previous_"); 870 return result; 871 } 872 873 874 status_t 875 BMessage::SendReply(uint32 command, BMessage *replyToReply) 876 { 877 DEBUG_FUNCTION_ENTER; 878 BMessage message(command); 879 return SendReply(&message, replyToReply); 880 } 881 882 883 status_t 884 BMessage::SendReply(BMessage *reply, BMessage *replyToReply, 885 bigtime_t sendTimeout, bigtime_t replyTimeout) 886 { 887 DEBUG_FUNCTION_ENTER; 888 BMessenger messenger; 889 BMessenger::Private messengerPrivate(messenger); 890 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port, 891 fHeader->reply_target); 892 893 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) { 894 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0) 895 return B_DUPLICATE_REPLY; 896 897 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 898 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 899 status_t result = messenger.SendMessage(reply, replyToReply, 900 sendTimeout, replyTimeout); 901 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 902 903 if (result != B_OK) { 904 if (set_port_owner(messengerPrivate.Port(), 905 messengerPrivate.Team()) == B_BAD_TEAM_ID) { 906 delete_port(messengerPrivate.Port()); 907 } 908 } 909 910 return result; 911 } 912 913 // no reply required 914 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 915 return B_BAD_REPLY; 916 917 reply->AddMessage("_previous_", this); 918 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 919 status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout, 920 replyTimeout); 921 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 922 reply->RemoveName("_previous_"); 923 return result; 924 } 925 926 927 ssize_t 928 BMessage::FlattenedSize() const 929 { 930 DEBUG_FUNCTION_ENTER; 931 return sizeof(message_header) + fHeader->field_count * sizeof(field_header) 932 + fHeader->data_size; 933 } 934 935 936 status_t 937 BMessage::Flatten(char *buffer, ssize_t size) const 938 { 939 DEBUG_FUNCTION_ENTER; 940 if (buffer == NULL || size < 0) 941 return B_BAD_VALUE; 942 943 if (fHeader == NULL) 944 return B_NO_INIT; 945 946 /* we have to sync the what code as it is a public member */ 947 fHeader->what = what; 948 949 memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size)); 950 buffer += sizeof(message_header); 951 size -= sizeof(message_header); 952 953 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 954 memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size)); 955 buffer += fieldsSize; 956 size -= fieldsSize; 957 958 memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size)); 959 if ((size_t)size < fHeader->data_size) 960 return B_BUFFER_OVERFLOW; 961 962 return B_OK; 963 } 964 965 966 status_t 967 BMessage::Flatten(BDataIO *stream, ssize_t *size) const 968 { 969 DEBUG_FUNCTION_ENTER; 970 if (stream == NULL) 971 return B_BAD_VALUE; 972 973 if (fHeader == NULL) 974 return B_NO_INIT; 975 976 /* we have to sync the what code as it is a public member */ 977 fHeader->what = what; 978 979 ssize_t result1 = stream->Write(fHeader, sizeof(message_header)); 980 if (result1 != sizeof(message_header)) 981 return result1 < 0 ? result1 : B_ERROR; 982 983 ssize_t result2 = 0; 984 if (fHeader->field_count > 0) { 985 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 986 result2 = stream->Write(fFields, fieldsSize); 987 if (result2 != fieldsSize) 988 return result2 < 0 ? result2 : B_ERROR; 989 } 990 991 ssize_t result3 = 0; 992 if (fHeader->data_size > 0) { 993 result3 = stream->Write(fData, fHeader->data_size); 994 if (result3 != (ssize_t)fHeader->data_size) 995 return result3 < 0 ? result3 : B_ERROR; 996 } 997 998 if (size) 999 *size = result1 + result2 + result3; 1000 1001 return B_OK; 1002 } 1003 1004 1005 /* The concept of message sending by area: 1006 1007 The traditional way of sending a message is to send it by flattening it to 1008 a buffer, pushing it through a port, reading it into the outputbuffer and 1009 unflattening it from there (copying the data again). While this works ok 1010 for small messages it does not make any sense for larger ones and may even 1011 hit some port capacity limit. 1012 Often in the life of a BMessage, it will be sent to someone. Almost as 1013 often the one receiving the message will not need to change the message 1014 in any way, but uses it "read only" to get information from it. This means 1015 that all that copying is pretty pointless in the first place since we 1016 could simply pass the original buffers on. 1017 It's obviously not exactly as simple as this, since we cannot just use the 1018 memory of one application in another - but we can share areas with 1019 eachother. 1020 Therefore instead of flattening into a buffer, we copy the message data 1021 into an area, put this information into the message header and only push 1022 this through the port. The receiving looper then builds a BMessage from 1023 the header, that only references the data in the area (not copying it), 1024 allowing read only access to it. 1025 Only if write access is necessary the message will be copyed from the area 1026 to its own buffers (like in the unflatten step before). 1027 The double copying is reduced to a single copy in most cases and we safe 1028 the slower route of moving the data through a port. 1029 Additionally we save us the reference counting with the use of areas that 1030 are reference counted internally. So we don't have to worry about leaving 1031 an area behind or deleting one that is still in use. 1032 */ 1033 1034 status_t 1035 BMessage::_FlattenToArea(message_header **_header) const 1036 { 1037 DEBUG_FUNCTION_ENTER; 1038 message_header *header = (message_header *)malloc(sizeof(message_header)); 1039 if (header == NULL) 1040 return B_NO_MEMORY; 1041 1042 memcpy(header, fHeader, sizeof(message_header)); 1043 1044 header->what = what; 1045 header->message_area = -1; 1046 *_header = header; 1047 1048 if (header->field_count == 0 && header->data_size == 0) 1049 return B_OK; 1050 1051 char *address = NULL; 1052 size_t fieldsSize = header->field_count * sizeof(field_header); 1053 size_t size = fieldsSize + header->data_size; 1054 size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1); 1055 area_id area = create_area("BMessage data", (void **)&address, 1056 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 1057 1058 if (area < 0) { 1059 free(header); 1060 *_header = NULL; 1061 return area; 1062 } 1063 1064 memcpy(address, fFields, fieldsSize); 1065 memcpy(address + fieldsSize, fData, fHeader->data_size); 1066 header->flags |= MESSAGE_FLAG_PASS_BY_AREA; 1067 header->message_area = area; 1068 return B_OK; 1069 } 1070 1071 1072 status_t 1073 BMessage::_Reference() 1074 { 1075 DEBUG_FUNCTION_ENTER; 1076 fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA; 1077 1078 /* if there is no data at all we don't need the area */ 1079 if (fHeader->field_count == 0 && fHeader->data_size == 0) 1080 return B_OK; 1081 1082 area_info areaInfo; 1083 status_t result = get_area_info(fHeader->message_area, &areaInfo); 1084 if (result < B_OK) 1085 return result; 1086 1087 uint8 *address = NULL; 1088 thread_info threadInfo; 1089 get_thread_info(find_thread(NULL), &threadInfo); 1090 if (areaInfo.team != threadInfo.team) { 1091 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 1092 // we are accessing a message from a port not owned by us 1093 area_id transfered = _kern_transfer_area(fHeader->message_area, 1094 (void **)&address, B_ANY_ADDRESS, threadInfo.team); 1095 if (transfered < 0) { 1096 debug_printf("BMessage: failed to transfer area into current team\n"); 1097 return transfered; 1098 } 1099 1100 fHeader->message_area = transfered; 1101 #endif 1102 } else 1103 address = (uint8 *)areaInfo.address; 1104 1105 fFields = (field_header *)address; 1106 fData = address + fHeader->field_count * sizeof(field_header); 1107 return B_OK; 1108 } 1109 1110 1111 status_t 1112 BMessage::_Dereference() 1113 { 1114 DEBUG_FUNCTION_ENTER; 1115 delete_area(fHeader->message_area); 1116 fHeader->message_area = -1; 1117 fFields = NULL; 1118 fData = NULL; 1119 return B_OK; 1120 } 1121 1122 1123 status_t 1124 BMessage::_CopyForWrite() 1125 { 1126 DEBUG_FUNCTION_ENTER; 1127 1128 field_header *newFields = NULL; 1129 uint8 *newData = NULL; 1130 1131 if (fHeader->field_count > 0) { 1132 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1133 newFields = (field_header *)malloc(fieldsSize); 1134 if (newFields == NULL) 1135 return B_NO_MEMORY; 1136 1137 memcpy(newFields, fFields, fieldsSize); 1138 } 1139 1140 if (fHeader->data_size > 0) { 1141 newData = (uint8 *)malloc(fHeader->data_size); 1142 if (newData == NULL) { 1143 free(newFields); 1144 return B_NO_MEMORY; 1145 } 1146 1147 memcpy(newData, fData, fHeader->data_size); 1148 } 1149 1150 _Dereference(); 1151 1152 fFieldsAvailable = 0; 1153 fDataAvailable = 0; 1154 1155 fFields = newFields; 1156 fData = newData; 1157 return B_OK; 1158 } 1159 1160 1161 status_t 1162 BMessage::_ValidateMessage() 1163 { 1164 if (fHeader->field_count == 0) 1165 return B_OK; 1166 1167 if (fFields == NULL) 1168 return B_NO_INIT; 1169 1170 for (uint32 i = 0; i < fHeader->field_count; i++) { 1171 field_header *field = &fFields[i]; 1172 if ((field->next_field >= 0 1173 && (uint32)field->next_field > fHeader->field_count) 1174 || (field->offset + field->name_length + field->data_size 1175 > fHeader->data_size)) { 1176 // the message is corrupt 1177 MakeEmpty(); 1178 return B_BAD_VALUE; 1179 } 1180 } 1181 1182 return B_OK; 1183 } 1184 1185 1186 status_t 1187 BMessage::Unflatten(const char *flatBuffer) 1188 { 1189 DEBUG_FUNCTION_ENTER; 1190 if (flatBuffer == NULL) 1191 return B_BAD_VALUE; 1192 1193 uint32 format = *(uint32 *)flatBuffer; 1194 if (format != MESSAGE_FORMAT_HAIKU) 1195 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer); 1196 1197 // native message unflattening 1198 1199 _Clear(); 1200 1201 fHeader = (message_header *)malloc(sizeof(message_header)); 1202 if (fHeader == NULL) 1203 return B_NO_MEMORY; 1204 1205 memcpy(fHeader, flatBuffer, sizeof(message_header)); 1206 flatBuffer += sizeof(message_header); 1207 1208 if (fHeader->format != MESSAGE_FORMAT_HAIKU 1209 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1210 _InitHeader(); 1211 return B_BAD_VALUE; 1212 } 1213 1214 what = fHeader->what; 1215 1216 if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0 1217 && fHeader->message_area >= 0) { 1218 status_t result = _Reference(); 1219 if (result != B_OK) 1220 return result; 1221 } else { 1222 fHeader->message_area = -1; 1223 1224 if (fHeader->field_count > 0) { 1225 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1226 fFields = (field_header *)malloc(fieldsSize); 1227 if (fFields == NULL) { 1228 _InitHeader(); 1229 return B_NO_MEMORY; 1230 } 1231 1232 memcpy(fFields, flatBuffer, fieldsSize); 1233 flatBuffer += fieldsSize; 1234 } 1235 1236 if (fHeader->data_size > 0) { 1237 fData = (uint8 *)malloc(fHeader->data_size); 1238 if (fData == NULL) { 1239 free(fFields); 1240 fFields = NULL; 1241 _InitHeader(); 1242 return B_NO_MEMORY; 1243 } 1244 1245 memcpy(fData, flatBuffer, fHeader->data_size); 1246 } 1247 } 1248 1249 return _ValidateMessage(); 1250 } 1251 1252 1253 status_t 1254 BMessage::Unflatten(BDataIO *stream) 1255 { 1256 DEBUG_FUNCTION_ENTER; 1257 if (stream == NULL) 1258 return B_BAD_VALUE; 1259 1260 uint32 format = 0; 1261 stream->Read(&format, sizeof(uint32)); 1262 if (format != MESSAGE_FORMAT_HAIKU) 1263 return BPrivate::MessageAdapter::Unflatten(format, this, stream); 1264 1265 // native message unflattening 1266 1267 _Clear(); 1268 1269 fHeader = (message_header *)malloc(sizeof(message_header)); 1270 if (fHeader == NULL) 1271 return B_NO_MEMORY; 1272 1273 fHeader->format = format; 1274 uint8 *header = (uint8 *)fHeader; 1275 ssize_t result = stream->Read(header + sizeof(uint32), 1276 sizeof(message_header) - sizeof(uint32)); 1277 if (result != sizeof(message_header) - sizeof(uint32) 1278 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1279 _InitHeader(); 1280 return result < 0 ? result : B_BAD_VALUE; 1281 } 1282 1283 what = fHeader->what; 1284 1285 fHeader->message_area = -1; 1286 1287 if (fHeader->field_count > 0) { 1288 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 1289 fFields = (field_header *)malloc(fieldsSize); 1290 if (fFields == NULL) { 1291 _InitHeader(); 1292 return B_NO_MEMORY; 1293 } 1294 1295 result = stream->Read(fFields, fieldsSize); 1296 if (result != fieldsSize) 1297 return result < 0 ? result : B_BAD_VALUE; 1298 } 1299 1300 if (fHeader->data_size > 0) { 1301 fData = (uint8 *)malloc(fHeader->data_size); 1302 if (fData == NULL) { 1303 free(fFields); 1304 fFields = NULL; 1305 _InitHeader(); 1306 return B_NO_MEMORY; 1307 } 1308 1309 result = stream->Read(fData, fHeader->data_size); 1310 if (result != (ssize_t)fHeader->data_size) 1311 return result < 0 ? result : B_BAD_VALUE; 1312 } 1313 1314 return _ValidateMessage(); 1315 } 1316 1317 1318 status_t 1319 BMessage::AddSpecifier(const char *property) 1320 { 1321 DEBUG_FUNCTION_ENTER; 1322 BMessage message(B_DIRECT_SPECIFIER); 1323 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1324 if (result < B_OK) 1325 return result; 1326 1327 return AddSpecifier(&message); 1328 } 1329 1330 1331 status_t 1332 BMessage::AddSpecifier(const char *property, int32 index) 1333 { 1334 DEBUG_FUNCTION_ENTER; 1335 BMessage message(B_INDEX_SPECIFIER); 1336 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1337 if (result < B_OK) 1338 return result; 1339 1340 result = message.AddInt32("index", index); 1341 if (result < B_OK) 1342 return result; 1343 1344 return AddSpecifier(&message); 1345 } 1346 1347 1348 status_t 1349 BMessage::AddSpecifier(const char *property, int32 index, int32 range) 1350 { 1351 DEBUG_FUNCTION_ENTER; 1352 if (range < 0) 1353 return B_BAD_VALUE; 1354 1355 BMessage message(B_RANGE_SPECIFIER); 1356 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1357 if (result < B_OK) 1358 return result; 1359 1360 result = message.AddInt32("index", index); 1361 if (result < B_OK) 1362 return result; 1363 1364 result = message.AddInt32("range", range); 1365 if (result < B_OK) 1366 return result; 1367 1368 return AddSpecifier(&message); 1369 } 1370 1371 1372 status_t 1373 BMessage::AddSpecifier(const char *property, const char *name) 1374 { 1375 DEBUG_FUNCTION_ENTER; 1376 BMessage message(B_NAME_SPECIFIER); 1377 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1378 if (result < B_OK) 1379 return result; 1380 1381 result = message.AddString(B_PROPERTY_NAME_ENTRY, name); 1382 if (result < B_OK) 1383 return result; 1384 1385 return AddSpecifier(&message); 1386 } 1387 1388 1389 status_t 1390 BMessage::AddSpecifier(const BMessage *specifier) 1391 { 1392 DEBUG_FUNCTION_ENTER; 1393 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier); 1394 if (result < B_OK) 1395 return result; 1396 1397 fHeader->current_specifier++; 1398 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 1399 return B_OK; 1400 } 1401 1402 1403 status_t 1404 BMessage::SetCurrentSpecifier(int32 index) 1405 { 1406 DEBUG_FUNCTION_ENTER; 1407 if (index < 0) 1408 return B_BAD_INDEX; 1409 1410 type_code type; 1411 int32 count; 1412 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count); 1413 if (result < B_OK) 1414 return result; 1415 1416 if (index > count) 1417 return B_BAD_INDEX; 1418 1419 fHeader->current_specifier = index; 1420 return B_OK; 1421 } 1422 1423 1424 status_t 1425 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *_what, 1426 const char **property) const 1427 { 1428 DEBUG_FUNCTION_ENTER; 1429 1430 if (index != NULL) 1431 *index = fHeader->current_specifier; 1432 1433 if (fHeader->current_specifier < 0 1434 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1435 return B_BAD_SCRIPT_SYNTAX; 1436 1437 if (specifier) { 1438 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier, 1439 specifier) < B_OK) 1440 return B_BAD_SCRIPT_SYNTAX; 1441 1442 if (_what != NULL) 1443 *_what = specifier->what; 1444 1445 if (property) { 1446 if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK) 1447 return B_BAD_SCRIPT_SYNTAX; 1448 } 1449 } 1450 1451 return B_OK; 1452 } 1453 1454 1455 bool 1456 BMessage::HasSpecifiers() const 1457 { 1458 DEBUG_FUNCTION_ENTER; 1459 return (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0; 1460 } 1461 1462 1463 status_t 1464 BMessage::PopSpecifier() 1465 { 1466 DEBUG_FUNCTION_ENTER; 1467 if (fHeader->current_specifier < 0 || 1468 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1469 return B_BAD_VALUE; 1470 1471 if (fHeader->current_specifier >= 0) 1472 fHeader->current_specifier--; 1473 1474 return B_OK; 1475 } 1476 1477 1478 status_t 1479 BMessage::_ResizeData(uint32 offset, int32 change) 1480 { 1481 if (change == 0) 1482 return B_OK; 1483 1484 /* optimize for the most usual case: appending data */ 1485 if (offset < fHeader->data_size) { 1486 field_header *field = fFields; 1487 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 1488 if (field->offset >= offset) 1489 field->offset += change; 1490 } 1491 } 1492 1493 if (change > 0) { 1494 if (fDataAvailable >= (uint32)change) { 1495 if (offset < fHeader->data_size) { 1496 memmove(fData + offset + change, fData + offset, 1497 fHeader->data_size - offset); 1498 } 1499 1500 fDataAvailable -= change; 1501 fHeader->data_size += change; 1502 return B_OK; 1503 } 1504 1505 size_t size = fHeader->data_size * 2; 1506 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION); 1507 size = max_c(size, fHeader->data_size + change); 1508 1509 uint8 *newData = (uint8 *)realloc(fData, size); 1510 if (size > 0 && newData == NULL) 1511 return B_NO_MEMORY; 1512 1513 fData = newData; 1514 if (offset < fHeader->data_size) { 1515 memmove(fData + offset + change, fData + offset, 1516 fHeader->data_size - offset); 1517 } 1518 1519 fHeader->data_size += change; 1520 fDataAvailable = size - fHeader->data_size; 1521 } else { 1522 ssize_t length = fHeader->data_size - offset + change; 1523 if (length > 0) 1524 memmove(fData + offset, fData + offset - change, length); 1525 1526 // change is negative 1527 fHeader->data_size += change; 1528 fDataAvailable -= change; 1529 1530 if (fDataAvailable > MAX_DATA_PREALLOCATION) { 1531 ssize_t available = MAX_DATA_PREALLOCATION / 2; 1532 ssize_t size = fHeader->data_size + available; 1533 uint8 *newData = (uint8 *)realloc(fData, size); 1534 if (size > 0 && newData == NULL) { 1535 // this is strange, but not really fatal 1536 return B_OK; 1537 } 1538 1539 fData = newData; 1540 fDataAvailable = available; 1541 } 1542 } 1543 1544 return B_OK; 1545 } 1546 1547 1548 uint32 1549 BMessage::_HashName(const char *name) const 1550 { 1551 char ch; 1552 uint32 result = 0; 1553 1554 while ((ch = *name++) != 0) { 1555 result = (result << 7) ^ (result >> 24); 1556 result ^= ch; 1557 } 1558 1559 result ^= result << 12; 1560 return result; 1561 } 1562 1563 1564 status_t 1565 BMessage::_FindField(const char *name, type_code type, field_header **result) const 1566 { 1567 if (name == NULL) 1568 return B_BAD_VALUE; 1569 1570 if (fHeader == NULL || fFields == NULL || fData == NULL) 1571 return B_NAME_NOT_FOUND; 1572 1573 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1574 int32 nextField = fHeader->hash_table[hash]; 1575 1576 while (nextField >= 0) { 1577 field_header *field = &fFields[nextField]; 1578 if ((field->flags & FIELD_FLAG_VALID) == 0) 1579 break; 1580 1581 if (strncmp((const char *)(fData + field->offset), name, 1582 field->name_length) == 0) { 1583 if (type != B_ANY_TYPE && field->type != type) 1584 return B_BAD_TYPE; 1585 1586 *result = field; 1587 return B_OK; 1588 } 1589 1590 nextField = field->next_field; 1591 } 1592 1593 return B_NAME_NOT_FOUND; 1594 } 1595 1596 1597 status_t 1598 BMessage::_AddField(const char *name, type_code type, bool isFixedSize, 1599 field_header **result) 1600 { 1601 if (fHeader == NULL) 1602 return B_ERROR; 1603 1604 if (fFieldsAvailable <= 0) { 1605 uint32 count = fHeader->field_count * 2 + 1; 1606 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION); 1607 1608 field_header *newFields = (field_header *)realloc(fFields, 1609 count * sizeof(field_header)); 1610 if (count > 0 && newFields == NULL) 1611 return B_NO_MEMORY; 1612 1613 fFields = newFields; 1614 fFieldsAvailable = count - fHeader->field_count; 1615 } 1616 1617 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1618 int32 *nextField = &fHeader->hash_table[hash]; 1619 while (*nextField >= 0) 1620 nextField = &fFields[*nextField].next_field; 1621 *nextField = fHeader->field_count; 1622 1623 field_header *field = &fFields[fHeader->field_count]; 1624 field->type = type; 1625 field->count = 0; 1626 field->data_size = 0; 1627 field->next_field = -1; 1628 field->offset = fHeader->data_size; 1629 field->name_length = strlen(name) + 1; 1630 status_t status = _ResizeData(field->offset, field->name_length); 1631 if (status < B_OK) 1632 return status; 1633 1634 memcpy(fData + field->offset, name, field->name_length); 1635 field->flags = FIELD_FLAG_VALID; 1636 if (isFixedSize) 1637 field->flags |= FIELD_FLAG_FIXED_SIZE; 1638 1639 fFieldsAvailable--; 1640 fHeader->field_count++; 1641 *result = field; 1642 return B_OK; 1643 } 1644 1645 1646 status_t 1647 BMessage::_RemoveField(field_header *field) 1648 { 1649 status_t result = _ResizeData(field->offset, -(field->data_size 1650 + field->name_length)); 1651 if (result < B_OK) 1652 return result; 1653 1654 int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header); 1655 int32 nextField = field->next_field; 1656 if (nextField > index) 1657 nextField--; 1658 1659 int32 *value = fHeader->hash_table; 1660 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) { 1661 if (*value > index) 1662 *value -= 1; 1663 else if (*value == index) 1664 *value = nextField; 1665 } 1666 1667 field_header *other = fFields; 1668 for (uint32 i = 0; i < fHeader->field_count; i++, other++) { 1669 if (other->next_field > index) 1670 other->next_field--; 1671 else if (other->next_field == index) 1672 other->next_field = nextField; 1673 } 1674 1675 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header); 1676 memmove(fFields + index, fFields + index + 1, size); 1677 fHeader->field_count--; 1678 fFieldsAvailable++; 1679 1680 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) { 1681 ssize_t available = MAX_FIELD_PREALLOCATION / 2; 1682 size = (fHeader->field_count + available) * sizeof(field_header); 1683 field_header *newFields = (field_header *)realloc(fFields, size); 1684 if (size > 0 && newFields == NULL) { 1685 // this is strange, but not really fatal 1686 return B_OK; 1687 } 1688 1689 fFields = newFields; 1690 fFieldsAvailable = available; 1691 } 1692 1693 return B_OK; 1694 } 1695 1696 1697 status_t 1698 BMessage::AddData(const char *name, type_code type, const void *data, 1699 ssize_t numBytes, bool isFixedSize, int32 count) 1700 { 1701 // Note that the "count" argument is only a hint at how many items 1702 // the caller expects to add to this field. Since we do no item pre- 1703 // allocation, we ignore this argument. 1704 DEBUG_FUNCTION_ENTER; 1705 if (numBytes <= 0 || data == NULL) 1706 return B_BAD_VALUE; 1707 1708 if (fHeader->message_area >= 0) 1709 _CopyForWrite(); 1710 1711 field_header *field = NULL; 1712 status_t result = _FindField(name, type, &field); 1713 if (result == B_NAME_NOT_FOUND) 1714 result = _AddField(name, type, isFixedSize, &field); 1715 1716 if (result < B_OK) 1717 return result; 1718 1719 if (field == NULL) 1720 return B_ERROR; 1721 1722 uint32 offset = field->offset + field->name_length + field->data_size; 1723 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1724 if (field->count) { 1725 ssize_t size = field->data_size / field->count; 1726 if (size != numBytes) 1727 return B_BAD_VALUE; 1728 } 1729 1730 result = _ResizeData(offset, numBytes); 1731 if (result < B_OK) { 1732 if (field->count == 0) 1733 _RemoveField(field); 1734 return result; 1735 } 1736 1737 memcpy(fData + offset, data, numBytes); 1738 field->data_size += numBytes; 1739 } else { 1740 int32 change = numBytes + sizeof(uint32); 1741 result = _ResizeData(offset, change); 1742 if (result < B_OK) { 1743 if (field->count == 0) 1744 _RemoveField(field); 1745 return result; 1746 } 1747 1748 uint32 size = (uint32)numBytes; 1749 memcpy(fData + offset, &size, sizeof(uint32)); 1750 memcpy(fData + offset + sizeof(uint32), data, size); 1751 field->data_size += change; 1752 } 1753 1754 field->count++; 1755 return B_OK; 1756 } 1757 1758 1759 status_t 1760 BMessage::RemoveData(const char *name, int32 index) 1761 { 1762 DEBUG_FUNCTION_ENTER; 1763 if (index < 0) 1764 return B_BAD_INDEX; 1765 1766 if (fHeader->message_area >= 0) 1767 _CopyForWrite(); 1768 1769 field_header *field = NULL; 1770 status_t result = _FindField(name, B_ANY_TYPE, &field); 1771 1772 if (result < B_OK) 1773 return result; 1774 1775 if (field == NULL) 1776 return B_ERROR; 1777 1778 if ((uint32)index >= field->count) 1779 return B_BAD_INDEX; 1780 1781 if (field->count == 1) 1782 return _RemoveField(field); 1783 1784 uint32 offset = field->offset + field->name_length; 1785 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1786 ssize_t size = field->data_size / field->count; 1787 result = _ResizeData(offset + index * size, -size); 1788 if (result < B_OK) 1789 return result; 1790 1791 field->data_size -= size; 1792 } else { 1793 uint8 *pointer = fData + offset; 1794 for (int32 i = 0; i < index; i++) { 1795 offset += *(uint32 *)pointer + sizeof(uint32); 1796 pointer = fData + offset; 1797 } 1798 1799 size_t currentSize = *(uint32 *)pointer + sizeof(uint32); 1800 result = _ResizeData(offset, -currentSize); 1801 if (result < B_OK) 1802 return result; 1803 1804 field->data_size -= currentSize; 1805 } 1806 1807 field->count--; 1808 return B_OK; 1809 } 1810 1811 1812 status_t 1813 BMessage::RemoveName(const char *name) 1814 { 1815 DEBUG_FUNCTION_ENTER; 1816 if (fHeader->message_area >= 0) 1817 _CopyForWrite(); 1818 1819 field_header *field = NULL; 1820 status_t result = _FindField(name, B_ANY_TYPE, &field); 1821 1822 if (result < B_OK) 1823 return result; 1824 1825 if (field == NULL) 1826 return B_ERROR; 1827 1828 return _RemoveField(field); 1829 } 1830 1831 1832 status_t 1833 BMessage::MakeEmpty() 1834 { 1835 DEBUG_FUNCTION_ENTER; 1836 _Clear(); 1837 _InitHeader(); 1838 return B_OK; 1839 } 1840 1841 1842 status_t 1843 BMessage::FindData(const char *name, type_code type, int32 index, 1844 const void **data, ssize_t *numBytes) const 1845 { 1846 DEBUG_FUNCTION_ENTER; 1847 if (data == NULL) 1848 return B_BAD_VALUE; 1849 1850 *data = NULL; 1851 field_header *field = NULL; 1852 status_t result = _FindField(name, type, &field); 1853 1854 if (result < B_OK) 1855 return result; 1856 1857 if (field == NULL) 1858 return B_ERROR; 1859 1860 if (index < 0 || (uint32)index >= field->count) 1861 return B_BAD_INDEX; 1862 1863 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1864 size_t bytes = field->data_size / field->count; 1865 *data = fData + field->offset + field->name_length + index * bytes; 1866 if (numBytes != NULL) 1867 *numBytes = bytes; 1868 } else { 1869 uint8 *pointer = fData + field->offset + field->name_length; 1870 for (int32 i = 0; i < index; i++) 1871 pointer += *(uint32 *)pointer + sizeof(uint32); 1872 1873 *data = pointer + sizeof(uint32); 1874 if (numBytes != NULL) 1875 *numBytes = *(uint32 *)pointer; 1876 } 1877 1878 return B_OK; 1879 } 1880 1881 1882 status_t 1883 BMessage::ReplaceData(const char *name, type_code type, int32 index, 1884 const void *data, ssize_t numBytes) 1885 { 1886 DEBUG_FUNCTION_ENTER; 1887 if (numBytes <= 0 || data == NULL) 1888 return B_BAD_VALUE; 1889 1890 field_header *field = NULL; 1891 status_t result = _FindField(name, type, &field); 1892 1893 if (result < B_OK) 1894 return result; 1895 1896 if (field == NULL) 1897 return B_ERROR; 1898 1899 if (index < 0 || (uint32)index >= field->count) 1900 return B_BAD_INDEX; 1901 1902 if (fHeader->message_area >= 0) 1903 _CopyForWrite(); 1904 1905 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1906 ssize_t size = field->data_size / field->count; 1907 if (size != numBytes) 1908 return B_BAD_VALUE; 1909 1910 memcpy(fData + field->offset + field->name_length + index * size, data, 1911 size); 1912 } else { 1913 uint32 offset = field->offset + field->name_length; 1914 uint8 *pointer = fData + offset; 1915 1916 for (int32 i = 0; i < index; i++) { 1917 offset += *(uint32 *)pointer + sizeof(uint32); 1918 pointer = fData + offset; 1919 } 1920 1921 size_t currentSize = *(uint32 *)pointer; 1922 int32 change = numBytes - currentSize; 1923 result = _ResizeData(offset, change); 1924 if (result < B_OK) 1925 return result; 1926 1927 uint32 newSize = (uint32)numBytes; 1928 memcpy(fData + offset, &newSize, sizeof(uint32)); 1929 memcpy(fData + offset + sizeof(uint32), data, newSize); 1930 field->data_size += change; 1931 } 1932 1933 return B_OK; 1934 } 1935 1936 1937 bool 1938 BMessage::HasData(const char *name, type_code type, int32 index) const 1939 { 1940 DEBUG_FUNCTION_ENTER; 1941 field_header *field = NULL; 1942 status_t result = _FindField(name, type, &field); 1943 1944 if (result < B_OK) 1945 return false; 1946 1947 if (field == NULL) 1948 return false; 1949 1950 if (index < 0 || (uint32)index >= field->count) 1951 return false; 1952 1953 return true; 1954 } 1955 1956 1957 /* Static functions for cache initialization and cleanup */ 1958 void 1959 BMessage::_StaticInit() 1960 { 1961 DEBUG_FUNCTION_ENTER2; 1962 sReplyPorts[0] = create_port(1, "tmp_rport0"); 1963 sReplyPorts[1] = create_port(1, "tmp_rport1"); 1964 sReplyPorts[2] = create_port(1, "tmp_rport2"); 1965 1966 sReplyPortInUse[0] = 0; 1967 sReplyPortInUse[1] = 0; 1968 sReplyPortInUse[2] = 0; 1969 1970 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE); 1971 } 1972 1973 1974 void 1975 BMessage::_StaticCleanup() 1976 { 1977 DEBUG_FUNCTION_ENTER2; 1978 delete_port(sReplyPorts[0]); 1979 sReplyPorts[0] = -1; 1980 delete_port(sReplyPorts[1]); 1981 sReplyPorts[1] = -1; 1982 delete_port(sReplyPorts[2]); 1983 sReplyPorts[2] = -1; 1984 } 1985 1986 1987 void 1988 BMessage::_StaticCacheCleanup() 1989 { 1990 DEBUG_FUNCTION_ENTER2; 1991 delete sMsgCache; 1992 sMsgCache = NULL; 1993 } 1994 1995 1996 int32 1997 BMessage::_StaticGetCachedReplyPort() 1998 { 1999 DEBUG_FUNCTION_ENTER2; 2000 int index = -1; 2001 for (int32 i = 0; i < sNumReplyPorts; i++) { 2002 int32 old = atomic_add(&(sReplyPortInUse[i]), 1); 2003 if (old == 0) { 2004 // This entry is free 2005 index = i; 2006 break; 2007 } else { 2008 // This entry is being used. 2009 atomic_add(&(sReplyPortInUse[i]), -1); 2010 } 2011 } 2012 2013 return index; 2014 } 2015 2016 2017 status_t 2018 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2019 bigtime_t timeout, bool replyRequired, BMessenger &replyTo) const 2020 { 2021 DEBUG_FUNCTION_ENTER; 2022 ssize_t size = 0; 2023 char *buffer = NULL; 2024 message_header *header = NULL; 2025 status_t result = B_OK; 2026 2027 BPrivate::BDirectMessageTarget* direct = NULL; 2028 BMessage* copy = NULL; 2029 if (portOwner == BPrivate::current_team()) 2030 BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct); 2031 2032 if (direct != NULL) { 2033 // We have a direct local message target - we can just enqueue the message 2034 // in its message queue. This will also prevent possible deadlocks when the 2035 // queue is full. 2036 copy = new BMessage(*this); 2037 if (copy != NULL) { 2038 header = copy->fHeader; 2039 header->flags = fHeader->flags; 2040 } else { 2041 direct->Release(); 2042 return B_NO_MEMORY; 2043 } 2044 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 2045 } else if (fHeader->data_size > B_PAGE_SIZE * 10) { 2046 // ToDo: bind the above size to the max port message size 2047 // use message passing by area for such a large message 2048 result = _FlattenToArea(&header); 2049 if (result != B_OK) 2050 return result; 2051 2052 buffer = (char *)header; 2053 size = sizeof(message_header); 2054 2055 if (header->message_area >= 0) { 2056 team_id target = portOwner; 2057 if (target < 0) { 2058 port_info info; 2059 result = get_port_info(port, &info); 2060 if (result != B_OK) { 2061 free(header); 2062 return result; 2063 } 2064 target = info.team; 2065 } 2066 2067 void *address = NULL; 2068 area_id transfered = _kern_transfer_area(header->message_area, 2069 &address, B_ANY_ADDRESS, target); 2070 if (transfered < 0) { 2071 delete_area(header->message_area); 2072 free(header); 2073 return transfered; 2074 } 2075 2076 header->message_area = transfered; 2077 } 2078 #endif 2079 } else { 2080 size = FlattenedSize(); 2081 buffer = (char *)malloc(size); 2082 if (buffer == NULL) 2083 return B_NO_MEMORY; 2084 2085 result = Flatten(buffer, size); 2086 if (result < B_OK) { 2087 free(buffer); 2088 return result; 2089 } 2090 2091 header = (message_header *)buffer; 2092 } 2093 2094 if (!replyTo.IsValid()) { 2095 BMessenger::Private(replyTo).SetTo(fHeader->reply_team, 2096 fHeader->reply_port, fHeader->reply_target); 2097 2098 if (!replyTo.IsValid()) 2099 replyTo = be_app_messenger; 2100 } 2101 2102 BMessenger::Private replyToPrivate(replyTo); 2103 2104 if (replyRequired) { 2105 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 2106 header->flags &= ~MESSAGE_FLAG_REPLY_DONE; 2107 } 2108 2109 header->target = token; 2110 header->reply_team = replyToPrivate.Team(); 2111 header->reply_port = replyToPrivate.Port(); 2112 header->reply_target = replyToPrivate.Token(); 2113 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2114 2115 if (direct == NULL) { 2116 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, " 2117 "message: '%c%c%c%c'", portOwner, port, token, 2118 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2119 2120 do { 2121 result = write_port_etc(port, kPortMessageCode, (void *)buffer, 2122 size, B_RELATIVE_TIMEOUT, timeout); 2123 } while (result == B_INTERRUPTED); 2124 } 2125 2126 if (result == B_OK && IsSourceWaiting()) { 2127 // the forwarded message will handle the reply - we must not do 2128 // this anymore 2129 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 2130 } 2131 2132 // we need to do this last because it is possible our 2133 // message might be destroyed after it's enqueued in the 2134 // target looper. Thus we don't want to do any ops that depend on 2135 // members of this after the enqueue. 2136 if (direct != NULL) { 2137 KTRACE("BMessage send direct: port: %ld, token: %ld, " 2138 "message: '%c%c%c%c'", port, token, 2139 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2140 2141 // this is a local message transmission 2142 direct->AddMessage(copy); 2143 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) { 2144 // there is currently no message waiting, and we need to wakeup the looper 2145 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0); 2146 } 2147 direct->Release(); 2148 } 2149 2150 free(buffer); 2151 return result; 2152 } 2153 2154 2155 /*! 2156 Sends a message and waits synchronously for a reply. 2157 */ 2158 status_t 2159 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2160 BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const 2161 { 2162 if (IsSourceWaiting()) { 2163 // we can't forward this message synchronously when it's already 2164 // waiting for a reply 2165 return B_ERROR; 2166 } 2167 2168 DEBUG_FUNCTION_ENTER; 2169 const int32 cachedReplyPort = _StaticGetCachedReplyPort(); 2170 port_id replyPort = B_BAD_PORT_ID; 2171 status_t result = B_OK; 2172 2173 if (cachedReplyPort < B_OK) { 2174 // All the cached reply ports are in use; create a new one 2175 replyPort = create_port(1 /* for one message */, "tmp_reply_port"); 2176 if (replyPort < B_OK) 2177 return replyPort; 2178 } else { 2179 assert(cachedReplyPort < sNumReplyPorts); 2180 replyPort = sReplyPorts[cachedReplyPort]; 2181 } 2182 2183 team_id team = B_BAD_TEAM_ID; 2184 if (be_app != NULL) 2185 team = be_app->Team(); 2186 else { 2187 port_info portInfo; 2188 result = get_port_info(replyPort, &portInfo); 2189 if (result < B_OK) 2190 goto error; 2191 2192 team = portInfo.team; 2193 } 2194 2195 result = set_port_owner(replyPort, portOwner); 2196 if (result < B_OK) 2197 goto error; 2198 2199 // tests if the queue of the reply port is really empty 2200 #if 0 2201 port_info portInfo; 2202 if (get_port_info(replyPort, &portInfo) == B_OK 2203 && portInfo.queue_count > 0) { 2204 debugger("reply port not empty!"); 2205 printf(" reply port not empty! %ld message(s) in queue\n", 2206 portInfo.queue_count); 2207 2208 // fetch and print the messages 2209 for (int32 i = 0; i < portInfo.queue_count; i++) { 2210 char buffer[1024]; 2211 int32 code; 2212 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer)); 2213 if (size < 0) { 2214 printf("failed to read message from reply port\n"); 2215 continue; 2216 } 2217 if (size >= (ssize_t)sizeof(buffer)) { 2218 printf("message from reply port too big\n"); 2219 continue; 2220 } 2221 2222 BMemoryIO stream(buffer, size); 2223 BMessage reply; 2224 if (reply.Unflatten(&stream) != B_OK) { 2225 printf("failed to unflatten message from reply port\n"); 2226 continue; 2227 } 2228 2229 printf("message %ld from reply port:\n", i); 2230 reply.PrintToStream(); 2231 } 2232 } 2233 #endif 2234 2235 { 2236 BMessenger replyTarget; 2237 BMessenger::Private(replyTarget).SetTo(team, replyPort, 2238 B_PREFERRED_TOKEN); 2239 // TODO: replying could also use a BDirectMessageTarget like mechanism for local targets 2240 result = _SendMessage(port, -1, token, sendTimeout, true, 2241 replyTarget); 2242 } 2243 2244 if (result < B_OK) 2245 goto error; 2246 2247 int32 code; 2248 result = handle_reply(replyPort, &code, replyTimeout, reply); 2249 if (result < B_OK && cachedReplyPort >= 0) { 2250 delete_port(replyPort); 2251 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport"); 2252 } 2253 2254 error: 2255 if (cachedReplyPort >= 0) { 2256 // Reclaim ownership of cached port 2257 set_port_owner(replyPort, team); 2258 // Flag as available 2259 atomic_add(&sReplyPortInUse[cachedReplyPort], -1); 2260 return result; 2261 } 2262 2263 delete_port(replyPort); 2264 return result; 2265 } 2266 2267 2268 status_t 2269 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port, 2270 int32 token, bigtime_t timeout) 2271 { 2272 DEBUG_FUNCTION_ENTER2; 2273 if (data == NULL) 2274 return B_BAD_VALUE; 2275 2276 uint32 magic = *(uint32 *)data; 2277 2278 if (magic == MESSAGE_FORMAT_HAIKU || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) { 2279 message_header *header = (message_header *)data; 2280 header->target = token; 2281 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2282 } else if (magic == MESSAGE_FORMAT_R5) { 2283 uint8 *header = (uint8 *)data; 2284 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */ 2285 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */ 2286 + sizeof(uint8) /* flags */; 2287 *(int32 *)header = token; 2288 } else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) { 2289 KMessage::Header *header = (KMessage::Header *)data; 2290 header->targetToken = token; 2291 } else { 2292 return B_NOT_A_MESSAGE; 2293 } 2294 2295 // send the message 2296 status_t result; 2297 2298 do { 2299 result = write_port_etc(port, kPortMessageCode, data, size, 2300 B_RELATIVE_TIMEOUT, timeout); 2301 } while (result == B_INTERRUPTED); 2302 2303 return result; 2304 } 2305 2306 2307 void BMessage::_ReservedMessage1(void) {}; 2308 void BMessage::_ReservedMessage2(void) {}; 2309 void BMessage::_ReservedMessage3(void) {}; 2310 2311 2312 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 2313 2314 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 2315 status_t \ 2316 BMessage::Add##typeName(const char *name, type val) \ 2317 { \ 2318 return AddData(name, typeCode, &val, sizeof(type), true); \ 2319 } \ 2320 \ 2321 status_t \ 2322 BMessage::Find##typeName(const char *name, type *p) const \ 2323 { \ 2324 void *ptr = NULL; \ 2325 ssize_t bytes = 0; \ 2326 status_t error = B_OK; \ 2327 \ 2328 *p = type(); \ 2329 error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes); \ 2330 \ 2331 if (error == B_OK) \ 2332 memcpy(p, ptr, sizeof(type)); \ 2333 \ 2334 return error; \ 2335 } \ 2336 \ 2337 status_t \ 2338 BMessage::Find##typeName(const char *name, int32 index, type *p) const \ 2339 { \ 2340 void *ptr = NULL; \ 2341 ssize_t bytes = 0; \ 2342 status_t error = B_OK; \ 2343 \ 2344 *p = type(); \ 2345 error = FindData(name, typeCode, index, (const void **)&ptr, &bytes); \ 2346 \ 2347 if (error == B_OK) \ 2348 memcpy(p, ptr, sizeof(type)); \ 2349 \ 2350 return error; \ 2351 } \ 2352 \ 2353 status_t \ 2354 BMessage::Replace##typeName(const char *name, type val) \ 2355 { \ 2356 return ReplaceData(name, typeCode, 0, &val, sizeof(type)); \ 2357 } \ 2358 \ 2359 status_t \ 2360 BMessage::Replace##typeName(const char *name, int32 index, type val) \ 2361 { \ 2362 return ReplaceData(name, typeCode, index, &val, sizeof(type)); \ 2363 } \ 2364 \ 2365 bool \ 2366 BMessage::Has##typeName(const char *name, int32 index) const \ 2367 { \ 2368 return HasData(name, typeCode, index); \ 2369 } 2370 2371 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2372 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2373 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2374 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2375 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2376 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2377 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2378 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2379 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2380 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2381 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2382 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2383 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2384 2385 #undef DEFINE_FUNCTIONS 2386 2387 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2388 bool \ 2389 BMessage::Has##typeName(const char *name, int32 index) const \ 2390 { \ 2391 return HasData(name, typeCode, index); \ 2392 } 2393 2394 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2395 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2396 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2397 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2398 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2399 2400 #undef DEFINE_HAS_FUNCTION 2401 2402 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2403 type \ 2404 BMessage::Find##typeName(const char *name, int32 index) const \ 2405 { \ 2406 type val = initialize; \ 2407 Find##typeName(name, index, &val); \ 2408 return val; \ 2409 } 2410 2411 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2412 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2413 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL); 2414 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2415 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2416 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2417 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2418 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2419 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2420 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2421 2422 #undef DEFINE_LAZY_FIND_FUNCTION 2423 2424 status_t 2425 BMessage::AddString(const char *name, const char *string) 2426 { 2427 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false); 2428 } 2429 2430 2431 status_t 2432 BMessage::AddString(const char *name, const BString &string) 2433 { 2434 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false); 2435 } 2436 2437 2438 status_t 2439 BMessage::AddPointer(const char *name, const void *pointer) 2440 { 2441 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2442 } 2443 2444 2445 status_t 2446 BMessage::AddMessenger(const char *name, BMessenger messenger) 2447 { 2448 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2449 } 2450 2451 2452 status_t 2453 BMessage::AddRef(const char *name, const entry_ref *ref) 2454 { 2455 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2456 char buffer[size]; 2457 2458 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2459 2460 if (error >= B_OK) 2461 error = AddData(name, B_REF_TYPE, buffer, size, false); 2462 2463 return error; 2464 } 2465 2466 2467 status_t 2468 BMessage::AddMessage(const char *name, const BMessage *message) 2469 { 2470 if (message == NULL) 2471 return B_BAD_VALUE; 2472 2473 // TODO: This and the following functions waste time by allocating and 2474 // copying an extra buffer. Functions can be added that return a direct 2475 // pointer into the message. 2476 2477 char stackBuffer[16384]; 2478 ssize_t size = message->FlattenedSize(); 2479 2480 char* buffer; 2481 if (size > (ssize_t)sizeof(stackBuffer)) { 2482 buffer = (char *)malloc(size); 2483 if (buffer == NULL) 2484 return B_NO_MEMORY; 2485 } else 2486 buffer = stackBuffer; 2487 2488 status_t error = message->Flatten(buffer, size); 2489 2490 if (error >= B_OK) 2491 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false); 2492 2493 if (buffer != stackBuffer) 2494 free(buffer); 2495 2496 return error; 2497 } 2498 2499 2500 status_t 2501 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count) 2502 { 2503 if (object == NULL) 2504 return B_BAD_VALUE; 2505 2506 char stackBuffer[16384]; 2507 ssize_t size = object->FlattenedSize(); 2508 2509 char* buffer; 2510 if (size > (ssize_t)sizeof(stackBuffer)) { 2511 buffer = (char *)malloc(size); 2512 if (buffer == NULL) 2513 return B_NO_MEMORY; 2514 } else 2515 buffer = stackBuffer; 2516 2517 status_t error = object->Flatten(buffer, size); 2518 2519 if (error >= B_OK) 2520 error = AddData(name, object->TypeCode(), buffer, size, false); 2521 2522 if (buffer != stackBuffer) 2523 free(buffer); 2524 2525 return error; 2526 } 2527 2528 2529 status_t 2530 BMessage::FindString(const char *name, const char **string) const 2531 { 2532 return FindString(name, 0, string); 2533 } 2534 2535 2536 status_t 2537 BMessage::FindString(const char *name, int32 index, const char **string) const 2538 { 2539 ssize_t bytes; 2540 return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes); 2541 } 2542 2543 2544 status_t 2545 BMessage::FindString(const char *name, BString *string) const 2546 { 2547 return FindString(name, 0, string); 2548 } 2549 2550 2551 status_t 2552 BMessage::FindString(const char *name, int32 index, BString *string) const 2553 { 2554 if (string == NULL) 2555 return B_BAD_VALUE; 2556 2557 const char *cstr; 2558 status_t error = FindString(name, index, &cstr); 2559 if (error < B_OK) 2560 return error; 2561 2562 *string = cstr; 2563 return B_OK; 2564 } 2565 2566 2567 status_t 2568 BMessage::FindPointer(const char *name, void **pointer) const 2569 { 2570 return FindPointer(name, 0, pointer); 2571 } 2572 2573 2574 status_t 2575 BMessage::FindPointer(const char *name, int32 index, void **pointer) const 2576 { 2577 if (pointer == NULL) 2578 return B_BAD_VALUE; 2579 2580 void **data = NULL; 2581 ssize_t size = 0; 2582 status_t error = FindData(name, B_POINTER_TYPE, index, 2583 (const void **)&data, &size); 2584 2585 if (error == B_OK) 2586 *pointer = *data; 2587 else 2588 *pointer = NULL; 2589 2590 return error; 2591 } 2592 2593 2594 status_t 2595 BMessage::FindMessenger(const char *name, BMessenger *messenger) const 2596 { 2597 return FindMessenger(name, 0, messenger); 2598 } 2599 2600 2601 status_t 2602 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger) 2603 const 2604 { 2605 if (messenger == NULL) 2606 return B_BAD_VALUE; 2607 2608 void *data = NULL; 2609 ssize_t size = 0; 2610 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2611 (const void **)&data, &size); 2612 2613 if (error == B_OK) 2614 memcpy(messenger, data, sizeof(BMessenger)); 2615 else 2616 *messenger = BMessenger(); 2617 2618 return error; 2619 } 2620 2621 2622 status_t 2623 BMessage::FindRef(const char *name, entry_ref *ref) const 2624 { 2625 return FindRef(name, 0, ref); 2626 } 2627 2628 2629 status_t 2630 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const 2631 { 2632 if (ref == NULL) 2633 return B_BAD_VALUE; 2634 2635 void *data = NULL; 2636 ssize_t size = 0; 2637 status_t error = FindData(name, B_REF_TYPE, index, 2638 (const void **)&data, &size); 2639 2640 if (error == B_OK) 2641 error = BPrivate::entry_ref_unflatten(ref, (char *)data, size); 2642 else 2643 *ref = entry_ref(); 2644 2645 return error; 2646 } 2647 2648 2649 status_t 2650 BMessage::FindMessage(const char *name, BMessage *message) const 2651 { 2652 return FindMessage(name, 0, message); 2653 } 2654 2655 2656 status_t 2657 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const 2658 { 2659 if (message == NULL) 2660 return B_BAD_VALUE; 2661 2662 void *data = NULL; 2663 ssize_t size = 0; 2664 status_t error = FindData(name, B_MESSAGE_TYPE, index, 2665 (const void **)&data, &size); 2666 2667 if (error == B_OK) 2668 error = message->Unflatten((const char *)data); 2669 else 2670 *message = BMessage(); 2671 2672 return error; 2673 } 2674 2675 2676 status_t 2677 BMessage::FindFlat(const char *name, BFlattenable *object) const 2678 { 2679 return FindFlat(name, 0, object); 2680 } 2681 2682 2683 status_t 2684 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const 2685 { 2686 if (object == NULL) 2687 return B_BAD_VALUE; 2688 2689 void *data = NULL; 2690 ssize_t numBytes = 0; 2691 status_t error = FindData(name, object->TypeCode(), index, 2692 (const void **)&data, &numBytes); 2693 2694 if (error == B_OK) 2695 error = object->Unflatten(object->TypeCode(), data, numBytes); 2696 2697 return error; 2698 } 2699 2700 2701 status_t 2702 BMessage::FindData(const char *name, type_code type, const void **data, 2703 ssize_t *numBytes) const 2704 { 2705 return FindData(name, type, 0, data, numBytes); 2706 } 2707 2708 2709 status_t 2710 BMessage::ReplaceString(const char *name, const char *string) 2711 { 2712 if (string == NULL) 2713 return B_BAD_VALUE; 2714 2715 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 2716 } 2717 2718 2719 status_t 2720 BMessage::ReplaceString(const char *name, int32 index, const char *string) 2721 { 2722 if (string == NULL) 2723 return B_BAD_VALUE; 2724 2725 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 2726 } 2727 2728 2729 status_t 2730 BMessage::ReplaceString(const char *name, const BString &string) 2731 { 2732 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 2733 string.Length() + 1); 2734 } 2735 2736 2737 status_t 2738 BMessage::ReplaceString(const char *name, int32 index, const BString &string) 2739 { 2740 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 2741 string.Length() + 1); 2742 } 2743 2744 2745 status_t 2746 BMessage::ReplacePointer(const char *name, const void *pointer) 2747 { 2748 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 2749 } 2750 2751 2752 status_t 2753 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer) 2754 { 2755 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 2756 } 2757 2758 2759 status_t 2760 BMessage::ReplaceMessenger(const char *name, BMessenger messenger) 2761 { 2762 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 2763 sizeof(BMessenger)); 2764 } 2765 2766 2767 status_t 2768 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger) 2769 { 2770 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 2771 sizeof(BMessenger)); 2772 } 2773 2774 2775 status_t 2776 BMessage::ReplaceRef(const char *name, const entry_ref *ref) 2777 { 2778 return ReplaceRef(name, 0, ref); 2779 } 2780 2781 2782 status_t 2783 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref) 2784 { 2785 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2786 char buffer[size]; 2787 2788 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2789 2790 if (error >= B_OK) 2791 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size); 2792 2793 return error; 2794 } 2795 2796 2797 status_t 2798 BMessage::ReplaceMessage(const char *name, const BMessage *message) 2799 { 2800 return ReplaceMessage(name, 0, message); 2801 } 2802 2803 2804 status_t 2805 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message) 2806 { 2807 if (message == NULL) 2808 return B_BAD_VALUE; 2809 2810 ssize_t size = message->FlattenedSize(); 2811 char buffer[size]; 2812 2813 status_t error = message->Flatten(buffer, size); 2814 2815 if (error >= B_OK) 2816 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 2817 2818 return error; 2819 } 2820 2821 2822 status_t 2823 BMessage::ReplaceFlat(const char *name, BFlattenable *object) 2824 { 2825 return ReplaceFlat(name, 0, object); 2826 } 2827 2828 2829 status_t 2830 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object) 2831 { 2832 if (object == NULL) 2833 return B_BAD_VALUE; 2834 2835 ssize_t size = object->FlattenedSize(); 2836 char buffer[size]; 2837 2838 status_t error = object->Flatten(buffer, size); 2839 2840 if (error >= B_OK) 2841 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 2842 2843 return error; 2844 } 2845 2846 2847 status_t 2848 BMessage::ReplaceData(const char *name, type_code type, const void *data, 2849 ssize_t numBytes) 2850 { 2851 return ReplaceData(name, type, 0, data, numBytes); 2852 } 2853 2854 2855 bool 2856 BMessage::HasFlat(const char *name, const BFlattenable *object) const 2857 { 2858 return HasFlat(name, 0, object); 2859 } 2860 2861 2862 bool 2863 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object) 2864 const 2865 { 2866 return HasData(name, object->TypeCode(), index); 2867 } 2868