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_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%" B_PRIx32, 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[%" B_PRIu32 "] = ", 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 (long)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=%d, directory=%" B_PRIdINO 650 ", name=\"%s\", ", (int)ref.device, ref.directory, 651 ref.name); 652 653 BPath path(&ref); 654 printf("path=\"%s\")\n", path.Path()); 655 break; 656 } 657 658 case B_MESSAGE_TYPE: 659 { 660 char buffer[1024]; 661 sprintf(buffer, "%s ", indent); 662 663 BMessage message; 664 size = *(uint32 *)pointer; 665 pointer += sizeof(uint32); 666 status_t result = message.Unflatten((const char *)pointer); 667 if (result != B_OK) { 668 printf("failed unflatten: %s\n", strerror(result)); 669 break; 670 } 671 672 message._PrintToStream(buffer); 673 printf("%s }\n", indent); 674 break; 675 } 676 677 default: 678 { 679 printf("(type = '%.4s')(size = %ld)\n", (char *)&value, 680 (long)size); 681 break; 682 } 683 } 684 685 pointer += size; 686 } 687 } 688 } 689 690 691 status_t 692 BMessage::Rename(const char *oldEntry, const char *newEntry) 693 { 694 DEBUG_FUNCTION_ENTER; 695 if (oldEntry == NULL || newEntry == NULL) 696 return B_BAD_VALUE; 697 698 if (fHeader->message_area >= 0) 699 _CopyForWrite(); 700 701 uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size; 702 int32 *nextField = &fHeader->hash_table[hash]; 703 704 while (*nextField >= 0) { 705 field_header *field = &fFields[*nextField]; 706 707 if (strncmp((const char *)(fData + field->offset), oldEntry, 708 field->name_length) == 0) { 709 // nextField points to the field for oldEntry, save it and unlink 710 int32 index = *nextField; 711 *nextField = field->next_field; 712 field->next_field = -1; 713 714 hash = _HashName(newEntry) % fHeader->hash_table_size; 715 nextField = &fHeader->hash_table[hash]; 716 while (*nextField >= 0) 717 nextField = &fFields[*nextField].next_field; 718 *nextField = index; 719 720 int32 newLength = strlen(newEntry) + 1; 721 status_t result = _ResizeData(field->offset + 1, 722 newLength - field->name_length); 723 if (result < B_OK) 724 return result; 725 726 memcpy(fData + field->offset, newEntry, newLength); 727 field->name_length = newLength; 728 return B_OK; 729 } 730 731 nextField = &field->next_field; 732 } 733 734 return B_NAME_NOT_FOUND; 735 } 736 737 738 bool 739 BMessage::WasDelivered() const 740 { 741 DEBUG_FUNCTION_ENTER; 742 return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0; 743 } 744 745 746 bool 747 BMessage::IsSourceWaiting() const 748 { 749 DEBUG_FUNCTION_ENTER; 750 return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0 751 && (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0; 752 } 753 754 755 bool 756 BMessage::IsSourceRemote() const 757 { 758 DEBUG_FUNCTION_ENTER; 759 return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0 760 && fHeader->reply_team != BPrivate::current_team(); 761 } 762 763 764 BMessenger 765 BMessage::ReturnAddress() const 766 { 767 DEBUG_FUNCTION_ENTER; 768 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) { 769 BMessenger messenger; 770 BMessenger::Private(messenger).SetTo(fHeader->reply_team, 771 fHeader->reply_port, fHeader->reply_target); 772 return messenger; 773 } 774 775 return BMessenger(); 776 } 777 778 779 const BMessage * 780 BMessage::Previous() const 781 { 782 DEBUG_FUNCTION_ENTER; 783 /* ToDo: test if the "_previous_" field is used in R5 */ 784 if (fOriginal == NULL) { 785 fOriginal = new BMessage(); 786 787 if (FindMessage("_previous_", fOriginal) != B_OK) { 788 delete fOriginal; 789 fOriginal = NULL; 790 } 791 } 792 793 return fOriginal; 794 } 795 796 797 bool 798 BMessage::WasDropped() const 799 { 800 DEBUG_FUNCTION_ENTER; 801 return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0; 802 } 803 804 805 BPoint 806 BMessage::DropPoint(BPoint *offset) const 807 { 808 DEBUG_FUNCTION_ENTER; 809 if (offset) 810 *offset = FindPoint("_drop_offset_"); 811 812 return FindPoint("_drop_point_"); 813 } 814 815 816 status_t 817 BMessage::SendReply(uint32 command, BHandler *replyTo) 818 { 819 DEBUG_FUNCTION_ENTER; 820 BMessage message(command); 821 return SendReply(&message, replyTo); 822 } 823 824 825 status_t 826 BMessage::SendReply(BMessage *reply, BHandler *replyTo, bigtime_t timeout) 827 { 828 DEBUG_FUNCTION_ENTER; 829 BMessenger messenger(replyTo); 830 return SendReply(reply, messenger, timeout); 831 } 832 833 834 status_t 835 BMessage::SendReply(BMessage *reply, BMessenger replyTo, bigtime_t timeout) 836 { 837 DEBUG_FUNCTION_ENTER; 838 BMessenger messenger; 839 BMessenger::Private messengerPrivate(messenger); 840 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port, 841 fHeader->reply_target); 842 843 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) { 844 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0) 845 return B_DUPLICATE_REPLY; 846 847 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 848 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 849 status_t result = messenger.SendMessage(reply, replyTo, timeout); 850 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 851 852 if (result != B_OK) { 853 if (set_port_owner(messengerPrivate.Port(), 854 messengerPrivate.Team()) == B_BAD_TEAM_ID) { 855 delete_port(messengerPrivate.Port()); 856 } 857 } 858 859 return result; 860 } 861 862 // no reply required 863 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 864 return B_BAD_REPLY; 865 866 reply->AddMessage("_previous_", this); 867 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 868 status_t result = messenger.SendMessage(reply, replyTo, timeout); 869 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 870 reply->RemoveName("_previous_"); 871 return result; 872 } 873 874 875 status_t 876 BMessage::SendReply(uint32 command, BMessage *replyToReply) 877 { 878 DEBUG_FUNCTION_ENTER; 879 BMessage message(command); 880 return SendReply(&message, replyToReply); 881 } 882 883 884 status_t 885 BMessage::SendReply(BMessage *reply, BMessage *replyToReply, 886 bigtime_t sendTimeout, bigtime_t replyTimeout) 887 { 888 DEBUG_FUNCTION_ENTER; 889 BMessenger messenger; 890 BMessenger::Private messengerPrivate(messenger); 891 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port, 892 fHeader->reply_target); 893 894 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) { 895 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0) 896 return B_DUPLICATE_REPLY; 897 898 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 899 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 900 status_t result = messenger.SendMessage(reply, replyToReply, 901 sendTimeout, replyTimeout); 902 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 903 904 if (result != B_OK) { 905 if (set_port_owner(messengerPrivate.Port(), 906 messengerPrivate.Team()) == B_BAD_TEAM_ID) { 907 delete_port(messengerPrivate.Port()); 908 } 909 } 910 911 return result; 912 } 913 914 // no reply required 915 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 916 return B_BAD_REPLY; 917 918 reply->AddMessage("_previous_", this); 919 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY; 920 status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout, 921 replyTimeout); 922 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY; 923 reply->RemoveName("_previous_"); 924 return result; 925 } 926 927 928 ssize_t 929 BMessage::FlattenedSize() const 930 { 931 DEBUG_FUNCTION_ENTER; 932 return sizeof(message_header) + fHeader->field_count * sizeof(field_header) 933 + fHeader->data_size; 934 } 935 936 937 status_t 938 BMessage::Flatten(char *buffer, ssize_t size) const 939 { 940 DEBUG_FUNCTION_ENTER; 941 if (buffer == NULL || size < 0) 942 return B_BAD_VALUE; 943 944 if (fHeader == NULL) 945 return B_NO_INIT; 946 947 /* we have to sync the what code as it is a public member */ 948 fHeader->what = what; 949 950 memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size)); 951 buffer += sizeof(message_header); 952 size -= sizeof(message_header); 953 954 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 955 memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size)); 956 buffer += fieldsSize; 957 size -= fieldsSize; 958 959 memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size)); 960 if ((size_t)size < fHeader->data_size) 961 return B_BUFFER_OVERFLOW; 962 963 return B_OK; 964 } 965 966 967 status_t 968 BMessage::Flatten(BDataIO *stream, ssize_t *size) const 969 { 970 DEBUG_FUNCTION_ENTER; 971 if (stream == NULL) 972 return B_BAD_VALUE; 973 974 if (fHeader == NULL) 975 return B_NO_INIT; 976 977 /* we have to sync the what code as it is a public member */ 978 fHeader->what = what; 979 980 ssize_t result1 = stream->Write(fHeader, sizeof(message_header)); 981 if (result1 != sizeof(message_header)) 982 return result1 < 0 ? result1 : B_ERROR; 983 984 ssize_t result2 = 0; 985 if (fHeader->field_count > 0) { 986 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 987 result2 = stream->Write(fFields, fieldsSize); 988 if (result2 != fieldsSize) 989 return result2 < 0 ? result2 : B_ERROR; 990 } 991 992 ssize_t result3 = 0; 993 if (fHeader->data_size > 0) { 994 result3 = stream->Write(fData, fHeader->data_size); 995 if (result3 != (ssize_t)fHeader->data_size) 996 return result3 < 0 ? result3 : B_ERROR; 997 } 998 999 if (size) 1000 *size = result1 + result2 + result3; 1001 1002 return B_OK; 1003 } 1004 1005 1006 /* The concept of message sending by area: 1007 1008 The traditional way of sending a message is to send it by flattening it to 1009 a buffer, pushing it through a port, reading it into the outputbuffer and 1010 unflattening it from there (copying the data again). While this works ok 1011 for small messages it does not make any sense for larger ones and may even 1012 hit some port capacity limit. 1013 Often in the life of a BMessage, it will be sent to someone. Almost as 1014 often the one receiving the message will not need to change the message 1015 in any way, but uses it "read only" to get information from it. This means 1016 that all that copying is pretty pointless in the first place since we 1017 could simply pass the original buffers on. 1018 It's obviously not exactly as simple as this, since we cannot just use the 1019 memory of one application in another - but we can share areas with 1020 eachother. 1021 Therefore instead of flattening into a buffer, we copy the message data 1022 into an area, put this information into the message header and only push 1023 this through the port. The receiving looper then builds a BMessage from 1024 the header, that only references the data in the area (not copying it), 1025 allowing read only access to it. 1026 Only if write access is necessary the message will be copyed from the area 1027 to its own buffers (like in the unflatten step before). 1028 The double copying is reduced to a single copy in most cases and we safe 1029 the slower route of moving the data through a port. 1030 Additionally we save us the reference counting with the use of areas that 1031 are reference counted internally. So we don't have to worry about leaving 1032 an area behind or deleting one that is still in use. 1033 */ 1034 1035 status_t 1036 BMessage::_FlattenToArea(message_header **_header) const 1037 { 1038 DEBUG_FUNCTION_ENTER; 1039 message_header *header = (message_header *)malloc(sizeof(message_header)); 1040 if (header == NULL) 1041 return B_NO_MEMORY; 1042 1043 memcpy(header, fHeader, sizeof(message_header)); 1044 1045 header->what = what; 1046 header->message_area = -1; 1047 *_header = header; 1048 1049 if (header->field_count == 0 && header->data_size == 0) 1050 return B_OK; 1051 1052 char *address = NULL; 1053 size_t fieldsSize = header->field_count * sizeof(field_header); 1054 size_t size = fieldsSize + header->data_size; 1055 size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1); 1056 area_id area = create_area("BMessage data", (void **)&address, 1057 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 1058 1059 if (area < 0) { 1060 free(header); 1061 *_header = NULL; 1062 return area; 1063 } 1064 1065 memcpy(address, fFields, fieldsSize); 1066 memcpy(address + fieldsSize, fData, fHeader->data_size); 1067 header->flags |= MESSAGE_FLAG_PASS_BY_AREA; 1068 header->message_area = area; 1069 return B_OK; 1070 } 1071 1072 1073 status_t 1074 BMessage::_Reference() 1075 { 1076 DEBUG_FUNCTION_ENTER; 1077 fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA; 1078 1079 /* if there is no data at all we don't need the area */ 1080 if (fHeader->field_count == 0 && fHeader->data_size == 0) 1081 return B_OK; 1082 1083 area_info areaInfo; 1084 status_t result = get_area_info(fHeader->message_area, &areaInfo); 1085 if (result < B_OK) 1086 return result; 1087 1088 uint8 *address = NULL; 1089 thread_info threadInfo; 1090 get_thread_info(find_thread(NULL), &threadInfo); 1091 if (areaInfo.team != threadInfo.team) { 1092 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 1093 // we are accessing a message from a port not owned by us 1094 area_id transfered = _kern_transfer_area(fHeader->message_area, 1095 (void **)&address, B_ANY_ADDRESS, threadInfo.team); 1096 if (transfered < 0) { 1097 debug_printf("BMessage: failed to transfer area into current team\n"); 1098 return transfered; 1099 } 1100 1101 fHeader->message_area = transfered; 1102 #endif 1103 } else 1104 address = (uint8 *)areaInfo.address; 1105 1106 fFields = (field_header *)address; 1107 fData = address + fHeader->field_count * sizeof(field_header); 1108 return B_OK; 1109 } 1110 1111 1112 status_t 1113 BMessage::_Dereference() 1114 { 1115 DEBUG_FUNCTION_ENTER; 1116 delete_area(fHeader->message_area); 1117 fHeader->message_area = -1; 1118 fFields = NULL; 1119 fData = NULL; 1120 return B_OK; 1121 } 1122 1123 1124 status_t 1125 BMessage::_CopyForWrite() 1126 { 1127 DEBUG_FUNCTION_ENTER; 1128 1129 field_header *newFields = NULL; 1130 uint8 *newData = NULL; 1131 1132 if (fHeader->field_count > 0) { 1133 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1134 newFields = (field_header *)malloc(fieldsSize); 1135 if (newFields == NULL) 1136 return B_NO_MEMORY; 1137 1138 memcpy(newFields, fFields, fieldsSize); 1139 } 1140 1141 if (fHeader->data_size > 0) { 1142 newData = (uint8 *)malloc(fHeader->data_size); 1143 if (newData == NULL) { 1144 free(newFields); 1145 return B_NO_MEMORY; 1146 } 1147 1148 memcpy(newData, fData, fHeader->data_size); 1149 } 1150 1151 _Dereference(); 1152 1153 fFieldsAvailable = 0; 1154 fDataAvailable = 0; 1155 1156 fFields = newFields; 1157 fData = newData; 1158 return B_OK; 1159 } 1160 1161 1162 status_t 1163 BMessage::_ValidateMessage() 1164 { 1165 if (fHeader->field_count == 0) 1166 return B_OK; 1167 1168 if (fFields == NULL) 1169 return B_NO_INIT; 1170 1171 for (uint32 i = 0; i < fHeader->field_count; i++) { 1172 field_header *field = &fFields[i]; 1173 if ((field->next_field >= 0 1174 && (uint32)field->next_field > fHeader->field_count) 1175 || (field->offset + field->name_length + field->data_size 1176 > fHeader->data_size)) { 1177 // the message is corrupt 1178 MakeEmpty(); 1179 return B_BAD_VALUE; 1180 } 1181 } 1182 1183 return B_OK; 1184 } 1185 1186 1187 status_t 1188 BMessage::Unflatten(const char *flatBuffer) 1189 { 1190 DEBUG_FUNCTION_ENTER; 1191 if (flatBuffer == NULL) 1192 return B_BAD_VALUE; 1193 1194 uint32 format = *(uint32 *)flatBuffer; 1195 if (format != MESSAGE_FORMAT_HAIKU) 1196 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer); 1197 1198 // native message unflattening 1199 1200 _Clear(); 1201 1202 fHeader = (message_header *)malloc(sizeof(message_header)); 1203 if (fHeader == NULL) 1204 return B_NO_MEMORY; 1205 1206 memcpy(fHeader, flatBuffer, sizeof(message_header)); 1207 flatBuffer += sizeof(message_header); 1208 1209 if (fHeader->format != MESSAGE_FORMAT_HAIKU 1210 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1211 _InitHeader(); 1212 return B_BAD_VALUE; 1213 } 1214 1215 what = fHeader->what; 1216 1217 if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0 1218 && fHeader->message_area >= 0) { 1219 status_t result = _Reference(); 1220 if (result != B_OK) 1221 return result; 1222 } else { 1223 fHeader->message_area = -1; 1224 1225 if (fHeader->field_count > 0) { 1226 size_t fieldsSize = fHeader->field_count * sizeof(field_header); 1227 fFields = (field_header *)malloc(fieldsSize); 1228 if (fFields == NULL) { 1229 _InitHeader(); 1230 return B_NO_MEMORY; 1231 } 1232 1233 memcpy(fFields, flatBuffer, fieldsSize); 1234 flatBuffer += fieldsSize; 1235 } 1236 1237 if (fHeader->data_size > 0) { 1238 fData = (uint8 *)malloc(fHeader->data_size); 1239 if (fData == NULL) { 1240 free(fFields); 1241 fFields = NULL; 1242 _InitHeader(); 1243 return B_NO_MEMORY; 1244 } 1245 1246 memcpy(fData, flatBuffer, fHeader->data_size); 1247 } 1248 } 1249 1250 return _ValidateMessage(); 1251 } 1252 1253 1254 status_t 1255 BMessage::Unflatten(BDataIO *stream) 1256 { 1257 DEBUG_FUNCTION_ENTER; 1258 if (stream == NULL) 1259 return B_BAD_VALUE; 1260 1261 uint32 format = 0; 1262 stream->Read(&format, sizeof(uint32)); 1263 if (format != MESSAGE_FORMAT_HAIKU) 1264 return BPrivate::MessageAdapter::Unflatten(format, this, stream); 1265 1266 // native message unflattening 1267 1268 _Clear(); 1269 1270 fHeader = (message_header *)malloc(sizeof(message_header)); 1271 if (fHeader == NULL) 1272 return B_NO_MEMORY; 1273 1274 fHeader->format = format; 1275 uint8 *header = (uint8 *)fHeader; 1276 ssize_t result = stream->Read(header + sizeof(uint32), 1277 sizeof(message_header) - sizeof(uint32)); 1278 if (result != sizeof(message_header) - sizeof(uint32) 1279 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) { 1280 _InitHeader(); 1281 return result < 0 ? result : B_BAD_VALUE; 1282 } 1283 1284 what = fHeader->what; 1285 1286 fHeader->message_area = -1; 1287 1288 if (fHeader->field_count > 0) { 1289 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header); 1290 fFields = (field_header *)malloc(fieldsSize); 1291 if (fFields == NULL) { 1292 _InitHeader(); 1293 return B_NO_MEMORY; 1294 } 1295 1296 result = stream->Read(fFields, fieldsSize); 1297 if (result != fieldsSize) 1298 return result < 0 ? result : B_BAD_VALUE; 1299 } 1300 1301 if (fHeader->data_size > 0) { 1302 fData = (uint8 *)malloc(fHeader->data_size); 1303 if (fData == NULL) { 1304 free(fFields); 1305 fFields = NULL; 1306 _InitHeader(); 1307 return B_NO_MEMORY; 1308 } 1309 1310 result = stream->Read(fData, fHeader->data_size); 1311 if (result != (ssize_t)fHeader->data_size) 1312 return result < 0 ? result : B_BAD_VALUE; 1313 } 1314 1315 return _ValidateMessage(); 1316 } 1317 1318 1319 status_t 1320 BMessage::AddSpecifier(const char *property) 1321 { 1322 DEBUG_FUNCTION_ENTER; 1323 BMessage message(B_DIRECT_SPECIFIER); 1324 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1325 if (result < B_OK) 1326 return result; 1327 1328 return AddSpecifier(&message); 1329 } 1330 1331 1332 status_t 1333 BMessage::AddSpecifier(const char *property, int32 index) 1334 { 1335 DEBUG_FUNCTION_ENTER; 1336 BMessage message(B_INDEX_SPECIFIER); 1337 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1338 if (result < B_OK) 1339 return result; 1340 1341 result = message.AddInt32("index", index); 1342 if (result < B_OK) 1343 return result; 1344 1345 return AddSpecifier(&message); 1346 } 1347 1348 1349 status_t 1350 BMessage::AddSpecifier(const char *property, int32 index, int32 range) 1351 { 1352 DEBUG_FUNCTION_ENTER; 1353 if (range < 0) 1354 return B_BAD_VALUE; 1355 1356 BMessage message(B_RANGE_SPECIFIER); 1357 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1358 if (result < B_OK) 1359 return result; 1360 1361 result = message.AddInt32("index", index); 1362 if (result < B_OK) 1363 return result; 1364 1365 result = message.AddInt32("range", range); 1366 if (result < B_OK) 1367 return result; 1368 1369 return AddSpecifier(&message); 1370 } 1371 1372 1373 status_t 1374 BMessage::AddSpecifier(const char *property, const char *name) 1375 { 1376 DEBUG_FUNCTION_ENTER; 1377 BMessage message(B_NAME_SPECIFIER); 1378 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1379 if (result < B_OK) 1380 return result; 1381 1382 result = message.AddString(B_PROPERTY_NAME_ENTRY, name); 1383 if (result < B_OK) 1384 return result; 1385 1386 return AddSpecifier(&message); 1387 } 1388 1389 1390 status_t 1391 BMessage::AddSpecifier(const BMessage *specifier) 1392 { 1393 DEBUG_FUNCTION_ENTER; 1394 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier); 1395 if (result < B_OK) 1396 return result; 1397 1398 fHeader->current_specifier++; 1399 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 1400 return B_OK; 1401 } 1402 1403 1404 status_t 1405 BMessage::SetCurrentSpecifier(int32 index) 1406 { 1407 DEBUG_FUNCTION_ENTER; 1408 if (index < 0) 1409 return B_BAD_INDEX; 1410 1411 type_code type; 1412 int32 count; 1413 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count); 1414 if (result < B_OK) 1415 return result; 1416 1417 if (index > count) 1418 return B_BAD_INDEX; 1419 1420 fHeader->current_specifier = index; 1421 return B_OK; 1422 } 1423 1424 1425 status_t 1426 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *_what, 1427 const char **property) const 1428 { 1429 DEBUG_FUNCTION_ENTER; 1430 1431 if (index != NULL) 1432 *index = fHeader->current_specifier; 1433 1434 if (fHeader->current_specifier < 0 1435 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1436 return B_BAD_SCRIPT_SYNTAX; 1437 1438 if (specifier) { 1439 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier, 1440 specifier) < B_OK) 1441 return B_BAD_SCRIPT_SYNTAX; 1442 1443 if (_what != NULL) 1444 *_what = specifier->what; 1445 1446 if (property) { 1447 if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK) 1448 return B_BAD_SCRIPT_SYNTAX; 1449 } 1450 } 1451 1452 return B_OK; 1453 } 1454 1455 1456 bool 1457 BMessage::HasSpecifiers() const 1458 { 1459 DEBUG_FUNCTION_ENTER; 1460 return (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0; 1461 } 1462 1463 1464 status_t 1465 BMessage::PopSpecifier() 1466 { 1467 DEBUG_FUNCTION_ENTER; 1468 if (fHeader->current_specifier < 0 || 1469 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0) 1470 return B_BAD_VALUE; 1471 1472 if (fHeader->current_specifier >= 0) 1473 fHeader->current_specifier--; 1474 1475 return B_OK; 1476 } 1477 1478 1479 status_t 1480 BMessage::_ResizeData(uint32 offset, int32 change) 1481 { 1482 if (change == 0) 1483 return B_OK; 1484 1485 /* optimize for the most usual case: appending data */ 1486 if (offset < fHeader->data_size) { 1487 field_header *field = fFields; 1488 for (uint32 i = 0; i < fHeader->field_count; i++, field++) { 1489 if (field->offset >= offset) 1490 field->offset += change; 1491 } 1492 } 1493 1494 if (change > 0) { 1495 if (fDataAvailable >= (uint32)change) { 1496 if (offset < fHeader->data_size) { 1497 memmove(fData + offset + change, fData + offset, 1498 fHeader->data_size - offset); 1499 } 1500 1501 fDataAvailable -= change; 1502 fHeader->data_size += change; 1503 return B_OK; 1504 } 1505 1506 size_t size = fHeader->data_size * 2; 1507 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION); 1508 size = max_c(size, fHeader->data_size + change); 1509 1510 uint8 *newData = (uint8 *)realloc(fData, size); 1511 if (size > 0 && newData == NULL) 1512 return B_NO_MEMORY; 1513 1514 fData = newData; 1515 if (offset < fHeader->data_size) { 1516 memmove(fData + offset + change, fData + offset, 1517 fHeader->data_size - offset); 1518 } 1519 1520 fHeader->data_size += change; 1521 fDataAvailable = size - fHeader->data_size; 1522 } else { 1523 ssize_t length = fHeader->data_size - offset + change; 1524 if (length > 0) 1525 memmove(fData + offset, fData + offset - change, length); 1526 1527 // change is negative 1528 fHeader->data_size += change; 1529 fDataAvailable -= change; 1530 1531 if (fDataAvailable > MAX_DATA_PREALLOCATION) { 1532 ssize_t available = MAX_DATA_PREALLOCATION / 2; 1533 ssize_t size = fHeader->data_size + available; 1534 uint8 *newData = (uint8 *)realloc(fData, size); 1535 if (size > 0 && newData == NULL) { 1536 // this is strange, but not really fatal 1537 return B_OK; 1538 } 1539 1540 fData = newData; 1541 fDataAvailable = available; 1542 } 1543 } 1544 1545 return B_OK; 1546 } 1547 1548 1549 uint32 1550 BMessage::_HashName(const char *name) const 1551 { 1552 char ch; 1553 uint32 result = 0; 1554 1555 while ((ch = *name++) != 0) { 1556 result = (result << 7) ^ (result >> 24); 1557 result ^= ch; 1558 } 1559 1560 result ^= result << 12; 1561 return result; 1562 } 1563 1564 1565 status_t 1566 BMessage::_FindField(const char *name, type_code type, field_header **result) const 1567 { 1568 if (name == NULL) 1569 return B_BAD_VALUE; 1570 1571 if (fHeader == NULL || fFields == NULL || fData == NULL) 1572 return B_NAME_NOT_FOUND; 1573 1574 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1575 int32 nextField = fHeader->hash_table[hash]; 1576 1577 while (nextField >= 0) { 1578 field_header *field = &fFields[nextField]; 1579 if ((field->flags & FIELD_FLAG_VALID) == 0) 1580 break; 1581 1582 if (strncmp((const char *)(fData + field->offset), name, 1583 field->name_length) == 0) { 1584 if (type != B_ANY_TYPE && field->type != type) 1585 return B_BAD_TYPE; 1586 1587 *result = field; 1588 return B_OK; 1589 } 1590 1591 nextField = field->next_field; 1592 } 1593 1594 return B_NAME_NOT_FOUND; 1595 } 1596 1597 1598 status_t 1599 BMessage::_AddField(const char *name, type_code type, bool isFixedSize, 1600 field_header **result) 1601 { 1602 if (fHeader == NULL) 1603 return B_ERROR; 1604 1605 if (fFieldsAvailable <= 0) { 1606 uint32 count = fHeader->field_count * 2 + 1; 1607 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION); 1608 1609 field_header *newFields = (field_header *)realloc(fFields, 1610 count * sizeof(field_header)); 1611 if (count > 0 && newFields == NULL) 1612 return B_NO_MEMORY; 1613 1614 fFields = newFields; 1615 fFieldsAvailable = count - fHeader->field_count; 1616 } 1617 1618 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1619 int32 *nextField = &fHeader->hash_table[hash]; 1620 while (*nextField >= 0) 1621 nextField = &fFields[*nextField].next_field; 1622 *nextField = fHeader->field_count; 1623 1624 field_header *field = &fFields[fHeader->field_count]; 1625 field->type = type; 1626 field->count = 0; 1627 field->data_size = 0; 1628 field->next_field = -1; 1629 field->offset = fHeader->data_size; 1630 field->name_length = strlen(name) + 1; 1631 status_t status = _ResizeData(field->offset, field->name_length); 1632 if (status < B_OK) 1633 return status; 1634 1635 memcpy(fData + field->offset, name, field->name_length); 1636 field->flags = FIELD_FLAG_VALID; 1637 if (isFixedSize) 1638 field->flags |= FIELD_FLAG_FIXED_SIZE; 1639 1640 fFieldsAvailable--; 1641 fHeader->field_count++; 1642 *result = field; 1643 return B_OK; 1644 } 1645 1646 1647 status_t 1648 BMessage::_RemoveField(field_header *field) 1649 { 1650 status_t result = _ResizeData(field->offset, -(field->data_size 1651 + field->name_length)); 1652 if (result < B_OK) 1653 return result; 1654 1655 int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header); 1656 int32 nextField = field->next_field; 1657 if (nextField > index) 1658 nextField--; 1659 1660 int32 *value = fHeader->hash_table; 1661 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) { 1662 if (*value > index) 1663 *value -= 1; 1664 else if (*value == index) 1665 *value = nextField; 1666 } 1667 1668 field_header *other = fFields; 1669 for (uint32 i = 0; i < fHeader->field_count; i++, other++) { 1670 if (other->next_field > index) 1671 other->next_field--; 1672 else if (other->next_field == index) 1673 other->next_field = nextField; 1674 } 1675 1676 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header); 1677 memmove(fFields + index, fFields + index + 1, size); 1678 fHeader->field_count--; 1679 fFieldsAvailable++; 1680 1681 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) { 1682 ssize_t available = MAX_FIELD_PREALLOCATION / 2; 1683 size = (fHeader->field_count + available) * sizeof(field_header); 1684 field_header *newFields = (field_header *)realloc(fFields, size); 1685 if (size > 0 && newFields == NULL) { 1686 // this is strange, but not really fatal 1687 return B_OK; 1688 } 1689 1690 fFields = newFields; 1691 fFieldsAvailable = available; 1692 } 1693 1694 return B_OK; 1695 } 1696 1697 1698 status_t 1699 BMessage::AddData(const char *name, type_code type, const void *data, 1700 ssize_t numBytes, bool isFixedSize, int32 count) 1701 { 1702 // Note that the "count" argument is only a hint at how many items 1703 // the caller expects to add to this field. Since we do no item pre- 1704 // allocation, we ignore this argument. 1705 DEBUG_FUNCTION_ENTER; 1706 if (numBytes <= 0 || data == NULL) 1707 return B_BAD_VALUE; 1708 1709 if (fHeader->message_area >= 0) 1710 _CopyForWrite(); 1711 1712 field_header *field = NULL; 1713 status_t result = _FindField(name, type, &field); 1714 if (result == B_NAME_NOT_FOUND) 1715 result = _AddField(name, type, isFixedSize, &field); 1716 1717 if (result < B_OK) 1718 return result; 1719 1720 if (field == NULL) 1721 return B_ERROR; 1722 1723 uint32 offset = field->offset + field->name_length + field->data_size; 1724 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1725 if (field->count) { 1726 ssize_t size = field->data_size / field->count; 1727 if (size != numBytes) 1728 return B_BAD_VALUE; 1729 } 1730 1731 result = _ResizeData(offset, numBytes); 1732 if (result < B_OK) { 1733 if (field->count == 0) 1734 _RemoveField(field); 1735 return result; 1736 } 1737 1738 memcpy(fData + offset, data, numBytes); 1739 field->data_size += numBytes; 1740 } else { 1741 int32 change = numBytes + sizeof(uint32); 1742 result = _ResizeData(offset, change); 1743 if (result < B_OK) { 1744 if (field->count == 0) 1745 _RemoveField(field); 1746 return result; 1747 } 1748 1749 uint32 size = (uint32)numBytes; 1750 memcpy(fData + offset, &size, sizeof(uint32)); 1751 memcpy(fData + offset + sizeof(uint32), data, size); 1752 field->data_size += change; 1753 } 1754 1755 field->count++; 1756 return B_OK; 1757 } 1758 1759 1760 status_t 1761 BMessage::RemoveData(const char *name, int32 index) 1762 { 1763 DEBUG_FUNCTION_ENTER; 1764 if (index < 0) 1765 return B_BAD_INDEX; 1766 1767 if (fHeader->message_area >= 0) 1768 _CopyForWrite(); 1769 1770 field_header *field = NULL; 1771 status_t result = _FindField(name, B_ANY_TYPE, &field); 1772 1773 if (result < B_OK) 1774 return result; 1775 1776 if (field == NULL) 1777 return B_ERROR; 1778 1779 if ((uint32)index >= field->count) 1780 return B_BAD_INDEX; 1781 1782 if (field->count == 1) 1783 return _RemoveField(field); 1784 1785 uint32 offset = field->offset + field->name_length; 1786 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1787 ssize_t size = field->data_size / field->count; 1788 result = _ResizeData(offset + index * size, -size); 1789 if (result < B_OK) 1790 return result; 1791 1792 field->data_size -= size; 1793 } else { 1794 uint8 *pointer = fData + offset; 1795 for (int32 i = 0; i < index; i++) { 1796 offset += *(uint32 *)pointer + sizeof(uint32); 1797 pointer = fData + offset; 1798 } 1799 1800 size_t currentSize = *(uint32 *)pointer + sizeof(uint32); 1801 result = _ResizeData(offset, -currentSize); 1802 if (result < B_OK) 1803 return result; 1804 1805 field->data_size -= currentSize; 1806 } 1807 1808 field->count--; 1809 return B_OK; 1810 } 1811 1812 1813 status_t 1814 BMessage::RemoveName(const char *name) 1815 { 1816 DEBUG_FUNCTION_ENTER; 1817 if (fHeader->message_area >= 0) 1818 _CopyForWrite(); 1819 1820 field_header *field = NULL; 1821 status_t result = _FindField(name, B_ANY_TYPE, &field); 1822 1823 if (result < B_OK) 1824 return result; 1825 1826 if (field == NULL) 1827 return B_ERROR; 1828 1829 return _RemoveField(field); 1830 } 1831 1832 1833 status_t 1834 BMessage::MakeEmpty() 1835 { 1836 DEBUG_FUNCTION_ENTER; 1837 _Clear(); 1838 _InitHeader(); 1839 return B_OK; 1840 } 1841 1842 1843 status_t 1844 BMessage::FindData(const char *name, type_code type, int32 index, 1845 const void **data, ssize_t *numBytes) const 1846 { 1847 DEBUG_FUNCTION_ENTER; 1848 if (data == NULL) 1849 return B_BAD_VALUE; 1850 1851 *data = NULL; 1852 field_header *field = NULL; 1853 status_t result = _FindField(name, type, &field); 1854 1855 if (result < B_OK) 1856 return result; 1857 1858 if (field == NULL) 1859 return B_ERROR; 1860 1861 if (index < 0 || (uint32)index >= field->count) 1862 return B_BAD_INDEX; 1863 1864 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1865 size_t bytes = field->data_size / field->count; 1866 *data = fData + field->offset + field->name_length + index * bytes; 1867 if (numBytes != NULL) 1868 *numBytes = bytes; 1869 } else { 1870 uint8 *pointer = fData + field->offset + field->name_length; 1871 for (int32 i = 0; i < index; i++) 1872 pointer += *(uint32 *)pointer + sizeof(uint32); 1873 1874 *data = pointer + sizeof(uint32); 1875 if (numBytes != NULL) 1876 *numBytes = *(uint32 *)pointer; 1877 } 1878 1879 return B_OK; 1880 } 1881 1882 1883 status_t 1884 BMessage::ReplaceData(const char *name, type_code type, int32 index, 1885 const void *data, ssize_t numBytes) 1886 { 1887 DEBUG_FUNCTION_ENTER; 1888 if (numBytes <= 0 || data == NULL) 1889 return B_BAD_VALUE; 1890 1891 field_header *field = NULL; 1892 status_t result = _FindField(name, type, &field); 1893 1894 if (result < B_OK) 1895 return result; 1896 1897 if (field == NULL) 1898 return B_ERROR; 1899 1900 if (index < 0 || (uint32)index >= field->count) 1901 return B_BAD_INDEX; 1902 1903 if (fHeader->message_area >= 0) 1904 _CopyForWrite(); 1905 1906 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) { 1907 ssize_t size = field->data_size / field->count; 1908 if (size != numBytes) 1909 return B_BAD_VALUE; 1910 1911 memcpy(fData + field->offset + field->name_length + index * size, data, 1912 size); 1913 } else { 1914 uint32 offset = field->offset + field->name_length; 1915 uint8 *pointer = fData + offset; 1916 1917 for (int32 i = 0; i < index; i++) { 1918 offset += *(uint32 *)pointer + sizeof(uint32); 1919 pointer = fData + offset; 1920 } 1921 1922 size_t currentSize = *(uint32 *)pointer; 1923 int32 change = numBytes - currentSize; 1924 result = _ResizeData(offset, change); 1925 if (result < B_OK) 1926 return result; 1927 1928 uint32 newSize = (uint32)numBytes; 1929 memcpy(fData + offset, &newSize, sizeof(uint32)); 1930 memcpy(fData + offset + sizeof(uint32), data, newSize); 1931 field->data_size += change; 1932 } 1933 1934 return B_OK; 1935 } 1936 1937 1938 bool 1939 BMessage::HasData(const char *name, type_code type, int32 index) const 1940 { 1941 DEBUG_FUNCTION_ENTER; 1942 field_header *field = NULL; 1943 status_t result = _FindField(name, type, &field); 1944 1945 if (result < B_OK) 1946 return false; 1947 1948 if (field == NULL) 1949 return false; 1950 1951 if (index < 0 || (uint32)index >= field->count) 1952 return false; 1953 1954 return true; 1955 } 1956 1957 1958 /* Static functions for cache initialization and cleanup */ 1959 void 1960 BMessage::_StaticInit() 1961 { 1962 DEBUG_FUNCTION_ENTER2; 1963 sReplyPorts[0] = create_port(1, "tmp_rport0"); 1964 sReplyPorts[1] = create_port(1, "tmp_rport1"); 1965 sReplyPorts[2] = create_port(1, "tmp_rport2"); 1966 1967 sReplyPortInUse[0] = 0; 1968 sReplyPortInUse[1] = 0; 1969 sReplyPortInUse[2] = 0; 1970 1971 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE); 1972 } 1973 1974 1975 void 1976 BMessage::_StaticReInitForkedChild() 1977 { 1978 DEBUG_FUNCTION_ENTER2; 1979 1980 // overwrite the inherited ports with a set of our own 1981 sReplyPorts[0] = create_port(1, "tmp_rport0"); 1982 sReplyPorts[1] = create_port(1, "tmp_rport1"); 1983 sReplyPorts[2] = create_port(1, "tmp_rport2"); 1984 1985 sReplyPortInUse[0] = 0; 1986 sReplyPortInUse[1] = 0; 1987 sReplyPortInUse[2] = 0; 1988 } 1989 1990 1991 void 1992 BMessage::_StaticCleanup() 1993 { 1994 DEBUG_FUNCTION_ENTER2; 1995 delete_port(sReplyPorts[0]); 1996 sReplyPorts[0] = -1; 1997 delete_port(sReplyPorts[1]); 1998 sReplyPorts[1] = -1; 1999 delete_port(sReplyPorts[2]); 2000 sReplyPorts[2] = -1; 2001 } 2002 2003 2004 void 2005 BMessage::_StaticCacheCleanup() 2006 { 2007 DEBUG_FUNCTION_ENTER2; 2008 delete sMsgCache; 2009 sMsgCache = NULL; 2010 } 2011 2012 2013 int32 2014 BMessage::_StaticGetCachedReplyPort() 2015 { 2016 DEBUG_FUNCTION_ENTER2; 2017 int index = -1; 2018 for (int32 i = 0; i < sNumReplyPorts; i++) { 2019 int32 old = atomic_add(&(sReplyPortInUse[i]), 1); 2020 if (old == 0) { 2021 // This entry is free 2022 index = i; 2023 break; 2024 } else { 2025 // This entry is being used. 2026 atomic_add(&(sReplyPortInUse[i]), -1); 2027 } 2028 } 2029 2030 return index; 2031 } 2032 2033 2034 status_t 2035 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2036 bigtime_t timeout, bool replyRequired, BMessenger &replyTo) const 2037 { 2038 DEBUG_FUNCTION_ENTER; 2039 ssize_t size = 0; 2040 char *buffer = NULL; 2041 message_header *header = NULL; 2042 status_t result = B_OK; 2043 2044 BPrivate::BDirectMessageTarget* direct = NULL; 2045 BMessage* copy = NULL; 2046 if (portOwner == BPrivate::current_team()) 2047 BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct); 2048 2049 if (direct != NULL) { 2050 // We have a direct local message target - we can just enqueue the message 2051 // in its message queue. This will also prevent possible deadlocks when the 2052 // queue is full. 2053 copy = new BMessage(*this); 2054 if (copy != NULL) { 2055 header = copy->fHeader; 2056 header->flags = fHeader->flags; 2057 } else { 2058 direct->Release(); 2059 return B_NO_MEMORY; 2060 } 2061 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 2062 } else if (fHeader->data_size > B_PAGE_SIZE * 10) { 2063 // ToDo: bind the above size to the max port message size 2064 // use message passing by area for such a large message 2065 result = _FlattenToArea(&header); 2066 if (result != B_OK) 2067 return result; 2068 2069 buffer = (char *)header; 2070 size = sizeof(message_header); 2071 2072 if (header->message_area >= 0) { 2073 team_id target = portOwner; 2074 if (target < 0) { 2075 port_info info; 2076 result = get_port_info(port, &info); 2077 if (result != B_OK) { 2078 free(header); 2079 return result; 2080 } 2081 target = info.team; 2082 } 2083 2084 void *address = NULL; 2085 area_id transfered = _kern_transfer_area(header->message_area, 2086 &address, B_ANY_ADDRESS, target); 2087 if (transfered < 0) { 2088 delete_area(header->message_area); 2089 free(header); 2090 return transfered; 2091 } 2092 2093 header->message_area = transfered; 2094 } 2095 #endif 2096 } else { 2097 size = FlattenedSize(); 2098 buffer = (char *)malloc(size); 2099 if (buffer == NULL) 2100 return B_NO_MEMORY; 2101 2102 result = Flatten(buffer, size); 2103 if (result < B_OK) { 2104 free(buffer); 2105 return result; 2106 } 2107 2108 header = (message_header *)buffer; 2109 } 2110 2111 if (!replyTo.IsValid()) { 2112 BMessenger::Private(replyTo).SetTo(fHeader->reply_team, 2113 fHeader->reply_port, fHeader->reply_target); 2114 2115 if (!replyTo.IsValid()) 2116 replyTo = be_app_messenger; 2117 } 2118 2119 BMessenger::Private replyToPrivate(replyTo); 2120 2121 if (replyRequired) { 2122 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 2123 header->flags &= ~MESSAGE_FLAG_REPLY_DONE; 2124 } 2125 2126 header->target = token; 2127 header->reply_team = replyToPrivate.Team(); 2128 header->reply_port = replyToPrivate.Port(); 2129 header->reply_target = replyToPrivate.Token(); 2130 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2131 2132 if (direct == NULL) { 2133 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, " 2134 "message: '%c%c%c%c'", portOwner, port, token, 2135 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2136 2137 do { 2138 result = write_port_etc(port, kPortMessageCode, (void *)buffer, 2139 size, B_RELATIVE_TIMEOUT, timeout); 2140 } while (result == B_INTERRUPTED); 2141 } 2142 2143 if (result == B_OK && IsSourceWaiting()) { 2144 // the forwarded message will handle the reply - we must not do 2145 // this anymore 2146 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 2147 } 2148 2149 // we need to do this last because it is possible our 2150 // message might be destroyed after it's enqueued in the 2151 // target looper. Thus we don't want to do any ops that depend on 2152 // members of this after the enqueue. 2153 if (direct != NULL) { 2154 KTRACE("BMessage send direct: port: %ld, token: %ld, " 2155 "message: '%c%c%c%c'", port, token, 2156 char(what >> 24), char(what >> 16), char(what >> 8), (char)what); 2157 2158 // this is a local message transmission 2159 direct->AddMessage(copy); 2160 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) { 2161 // there is currently no message waiting, and we need to wakeup the looper 2162 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0); 2163 } 2164 direct->Release(); 2165 } 2166 2167 free(buffer); 2168 return result; 2169 } 2170 2171 2172 /*! 2173 Sends a message and waits synchronously for a reply. 2174 */ 2175 status_t 2176 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 2177 BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const 2178 { 2179 if (IsSourceWaiting()) { 2180 // we can't forward this message synchronously when it's already 2181 // waiting for a reply 2182 return B_ERROR; 2183 } 2184 2185 DEBUG_FUNCTION_ENTER; 2186 const int32 cachedReplyPort = _StaticGetCachedReplyPort(); 2187 port_id replyPort = B_BAD_PORT_ID; 2188 status_t result = B_OK; 2189 2190 if (cachedReplyPort < B_OK) { 2191 // All the cached reply ports are in use; create a new one 2192 replyPort = create_port(1 /* for one message */, "tmp_reply_port"); 2193 if (replyPort < B_OK) 2194 return replyPort; 2195 } else { 2196 assert(cachedReplyPort < sNumReplyPorts); 2197 replyPort = sReplyPorts[cachedReplyPort]; 2198 } 2199 2200 team_id team = B_BAD_TEAM_ID; 2201 if (be_app != NULL) 2202 team = be_app->Team(); 2203 else { 2204 port_info portInfo; 2205 result = get_port_info(replyPort, &portInfo); 2206 if (result < B_OK) 2207 goto error; 2208 2209 team = portInfo.team; 2210 } 2211 2212 result = set_port_owner(replyPort, portOwner); 2213 if (result < B_OK) 2214 goto error; 2215 2216 // tests if the queue of the reply port is really empty 2217 #if 0 2218 port_info portInfo; 2219 if (get_port_info(replyPort, &portInfo) == B_OK 2220 && portInfo.queue_count > 0) { 2221 debugger("reply port not empty!"); 2222 printf(" reply port not empty! %ld message(s) in queue\n", 2223 portInfo.queue_count); 2224 2225 // fetch and print the messages 2226 for (int32 i = 0; i < portInfo.queue_count; i++) { 2227 char buffer[1024]; 2228 int32 code; 2229 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer)); 2230 if (size < 0) { 2231 printf("failed to read message from reply port\n"); 2232 continue; 2233 } 2234 if (size >= (ssize_t)sizeof(buffer)) { 2235 printf("message from reply port too big\n"); 2236 continue; 2237 } 2238 2239 BMemoryIO stream(buffer, size); 2240 BMessage reply; 2241 if (reply.Unflatten(&stream) != B_OK) { 2242 printf("failed to unflatten message from reply port\n"); 2243 continue; 2244 } 2245 2246 printf("message %ld from reply port:\n", i); 2247 reply.PrintToStream(); 2248 } 2249 } 2250 #endif 2251 2252 { 2253 BMessenger replyTarget; 2254 BMessenger::Private(replyTarget).SetTo(team, replyPort, 2255 B_PREFERRED_TOKEN); 2256 // TODO: replying could also use a BDirectMessageTarget like mechanism for local targets 2257 result = _SendMessage(port, -1, token, sendTimeout, true, 2258 replyTarget); 2259 } 2260 2261 if (result < B_OK) 2262 goto error; 2263 2264 int32 code; 2265 result = handle_reply(replyPort, &code, replyTimeout, reply); 2266 if (result < B_OK && cachedReplyPort >= 0) { 2267 delete_port(replyPort); 2268 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport"); 2269 } 2270 2271 error: 2272 if (cachedReplyPort >= 0) { 2273 // Reclaim ownership of cached port 2274 set_port_owner(replyPort, team); 2275 // Flag as available 2276 atomic_add(&sReplyPortInUse[cachedReplyPort], -1); 2277 return result; 2278 } 2279 2280 delete_port(replyPort); 2281 return result; 2282 } 2283 2284 2285 status_t 2286 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port, 2287 int32 token, bigtime_t timeout) 2288 { 2289 DEBUG_FUNCTION_ENTER2; 2290 if (data == NULL) 2291 return B_BAD_VALUE; 2292 2293 uint32 magic = *(uint32 *)data; 2294 2295 if (magic == MESSAGE_FORMAT_HAIKU || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) { 2296 message_header *header = (message_header *)data; 2297 header->target = token; 2298 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2299 } else if (magic == MESSAGE_FORMAT_R5) { 2300 uint8 *header = (uint8 *)data; 2301 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */ 2302 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */ 2303 + sizeof(uint8) /* flags */; 2304 *(int32 *)header = token; 2305 } else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) { 2306 KMessage::Header *header = (KMessage::Header *)data; 2307 header->targetToken = token; 2308 } else { 2309 return B_NOT_A_MESSAGE; 2310 } 2311 2312 // send the message 2313 status_t result; 2314 2315 do { 2316 result = write_port_etc(port, kPortMessageCode, data, size, 2317 B_RELATIVE_TIMEOUT, timeout); 2318 } while (result == B_INTERRUPTED); 2319 2320 return result; 2321 } 2322 2323 2324 void BMessage::_ReservedMessage1(void) {}; 2325 void BMessage::_ReservedMessage2(void) {}; 2326 void BMessage::_ReservedMessage3(void) {}; 2327 2328 2329 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 2330 2331 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 2332 status_t \ 2333 BMessage::Add##typeName(const char *name, type val) \ 2334 { \ 2335 return AddData(name, typeCode, &val, sizeof(type), true); \ 2336 } \ 2337 \ 2338 status_t \ 2339 BMessage::Find##typeName(const char *name, type *p) const \ 2340 { \ 2341 void *ptr = NULL; \ 2342 ssize_t bytes = 0; \ 2343 status_t error = B_OK; \ 2344 \ 2345 *p = type(); \ 2346 error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes); \ 2347 \ 2348 if (error == B_OK) \ 2349 memcpy(p, ptr, sizeof(type)); \ 2350 \ 2351 return error; \ 2352 } \ 2353 \ 2354 status_t \ 2355 BMessage::Find##typeName(const char *name, int32 index, type *p) const \ 2356 { \ 2357 void *ptr = NULL; \ 2358 ssize_t bytes = 0; \ 2359 status_t error = B_OK; \ 2360 \ 2361 *p = type(); \ 2362 error = FindData(name, typeCode, index, (const void **)&ptr, &bytes); \ 2363 \ 2364 if (error == B_OK) \ 2365 memcpy(p, ptr, sizeof(type)); \ 2366 \ 2367 return error; \ 2368 } \ 2369 \ 2370 status_t \ 2371 BMessage::Replace##typeName(const char *name, type val) \ 2372 { \ 2373 return ReplaceData(name, typeCode, 0, &val, sizeof(type)); \ 2374 } \ 2375 \ 2376 status_t \ 2377 BMessage::Replace##typeName(const char *name, int32 index, type val) \ 2378 { \ 2379 return ReplaceData(name, typeCode, index, &val, sizeof(type)); \ 2380 } \ 2381 \ 2382 bool \ 2383 BMessage::Has##typeName(const char *name, int32 index) const \ 2384 { \ 2385 return HasData(name, typeCode, index); \ 2386 } 2387 2388 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2389 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2390 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2391 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE); 2392 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2393 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE); 2394 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2395 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE); 2396 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2397 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE); 2398 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2399 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2400 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2401 2402 #undef DEFINE_FUNCTIONS 2403 2404 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2405 bool \ 2406 BMessage::Has##typeName(const char *name, int32 index) const \ 2407 { \ 2408 return HasData(name, typeCode, index); \ 2409 } 2410 2411 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2412 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2413 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2414 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2415 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2416 2417 #undef DEFINE_HAS_FUNCTION 2418 2419 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2420 type \ 2421 BMessage::Find##typeName(const char *name, int32 index) const \ 2422 { \ 2423 type val = initialize; \ 2424 Find##typeName(name, index, &val); \ 2425 return val; \ 2426 } 2427 2428 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2429 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2430 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL); 2431 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2432 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2433 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2434 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2435 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2436 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2437 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2438 2439 #undef DEFINE_LAZY_FIND_FUNCTION 2440 2441 status_t 2442 BMessage::AddString(const char *name, const char *string) 2443 { 2444 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false); 2445 } 2446 2447 2448 status_t 2449 BMessage::AddString(const char *name, const BString &string) 2450 { 2451 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false); 2452 } 2453 2454 2455 status_t 2456 BMessage::AddPointer(const char *name, const void *pointer) 2457 { 2458 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2459 } 2460 2461 2462 status_t 2463 BMessage::AddMessenger(const char *name, BMessenger messenger) 2464 { 2465 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2466 } 2467 2468 2469 status_t 2470 BMessage::AddRef(const char *name, const entry_ref *ref) 2471 { 2472 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2473 char buffer[size]; 2474 2475 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2476 2477 if (error >= B_OK) 2478 error = AddData(name, B_REF_TYPE, buffer, size, false); 2479 2480 return error; 2481 } 2482 2483 2484 status_t 2485 BMessage::AddMessage(const char *name, const BMessage *message) 2486 { 2487 if (message == NULL) 2488 return B_BAD_VALUE; 2489 2490 // TODO: This and the following functions waste time by allocating and 2491 // copying an extra buffer. Functions can be added that return a direct 2492 // pointer into the message. 2493 2494 char stackBuffer[16384]; 2495 ssize_t size = message->FlattenedSize(); 2496 2497 char* buffer; 2498 if (size > (ssize_t)sizeof(stackBuffer)) { 2499 buffer = (char *)malloc(size); 2500 if (buffer == NULL) 2501 return B_NO_MEMORY; 2502 } else 2503 buffer = stackBuffer; 2504 2505 status_t error = message->Flatten(buffer, size); 2506 2507 if (error >= B_OK) 2508 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false); 2509 2510 if (buffer != stackBuffer) 2511 free(buffer); 2512 2513 return error; 2514 } 2515 2516 2517 status_t 2518 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count) 2519 { 2520 if (object == NULL) 2521 return B_BAD_VALUE; 2522 2523 char stackBuffer[16384]; 2524 ssize_t size = object->FlattenedSize(); 2525 2526 char* buffer; 2527 if (size > (ssize_t)sizeof(stackBuffer)) { 2528 buffer = (char *)malloc(size); 2529 if (buffer == NULL) 2530 return B_NO_MEMORY; 2531 } else 2532 buffer = stackBuffer; 2533 2534 status_t error = object->Flatten(buffer, size); 2535 2536 if (error >= B_OK) 2537 error = AddData(name, object->TypeCode(), buffer, size, false); 2538 2539 if (buffer != stackBuffer) 2540 free(buffer); 2541 2542 return error; 2543 } 2544 2545 2546 status_t 2547 BMessage::FindString(const char *name, const char **string) const 2548 { 2549 return FindString(name, 0, string); 2550 } 2551 2552 2553 status_t 2554 BMessage::FindString(const char *name, int32 index, const char **string) const 2555 { 2556 ssize_t bytes; 2557 return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes); 2558 } 2559 2560 2561 status_t 2562 BMessage::FindString(const char *name, BString *string) const 2563 { 2564 return FindString(name, 0, string); 2565 } 2566 2567 2568 status_t 2569 BMessage::FindString(const char *name, int32 index, BString *string) const 2570 { 2571 if (string == NULL) 2572 return B_BAD_VALUE; 2573 2574 const char *cstr; 2575 status_t error = FindString(name, index, &cstr); 2576 if (error < B_OK) 2577 return error; 2578 2579 *string = cstr; 2580 return B_OK; 2581 } 2582 2583 2584 status_t 2585 BMessage::FindPointer(const char *name, void **pointer) const 2586 { 2587 return FindPointer(name, 0, pointer); 2588 } 2589 2590 2591 status_t 2592 BMessage::FindPointer(const char *name, int32 index, void **pointer) const 2593 { 2594 if (pointer == NULL) 2595 return B_BAD_VALUE; 2596 2597 void **data = NULL; 2598 ssize_t size = 0; 2599 status_t error = FindData(name, B_POINTER_TYPE, index, 2600 (const void **)&data, &size); 2601 2602 if (error == B_OK) 2603 *pointer = *data; 2604 else 2605 *pointer = NULL; 2606 2607 return error; 2608 } 2609 2610 2611 status_t 2612 BMessage::FindMessenger(const char *name, BMessenger *messenger) const 2613 { 2614 return FindMessenger(name, 0, messenger); 2615 } 2616 2617 2618 status_t 2619 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger) 2620 const 2621 { 2622 if (messenger == NULL) 2623 return B_BAD_VALUE; 2624 2625 void *data = NULL; 2626 ssize_t size = 0; 2627 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2628 (const void **)&data, &size); 2629 2630 if (error == B_OK) 2631 memcpy(messenger, data, sizeof(BMessenger)); 2632 else 2633 *messenger = BMessenger(); 2634 2635 return error; 2636 } 2637 2638 2639 status_t 2640 BMessage::FindRef(const char *name, entry_ref *ref) const 2641 { 2642 return FindRef(name, 0, ref); 2643 } 2644 2645 2646 status_t 2647 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const 2648 { 2649 if (ref == NULL) 2650 return B_BAD_VALUE; 2651 2652 void *data = NULL; 2653 ssize_t size = 0; 2654 status_t error = FindData(name, B_REF_TYPE, index, 2655 (const void **)&data, &size); 2656 2657 if (error == B_OK) 2658 error = BPrivate::entry_ref_unflatten(ref, (char *)data, size); 2659 else 2660 *ref = entry_ref(); 2661 2662 return error; 2663 } 2664 2665 2666 status_t 2667 BMessage::FindMessage(const char *name, BMessage *message) const 2668 { 2669 return FindMessage(name, 0, message); 2670 } 2671 2672 2673 status_t 2674 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const 2675 { 2676 if (message == NULL) 2677 return B_BAD_VALUE; 2678 2679 void *data = NULL; 2680 ssize_t size = 0; 2681 status_t error = FindData(name, B_MESSAGE_TYPE, index, 2682 (const void **)&data, &size); 2683 2684 if (error == B_OK) 2685 error = message->Unflatten((const char *)data); 2686 else 2687 *message = BMessage(); 2688 2689 return error; 2690 } 2691 2692 2693 status_t 2694 BMessage::FindFlat(const char *name, BFlattenable *object) const 2695 { 2696 return FindFlat(name, 0, object); 2697 } 2698 2699 2700 status_t 2701 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const 2702 { 2703 if (object == NULL) 2704 return B_BAD_VALUE; 2705 2706 void *data = NULL; 2707 ssize_t numBytes = 0; 2708 status_t error = FindData(name, object->TypeCode(), index, 2709 (const void **)&data, &numBytes); 2710 2711 if (error == B_OK) 2712 error = object->Unflatten(object->TypeCode(), data, numBytes); 2713 2714 return error; 2715 } 2716 2717 2718 status_t 2719 BMessage::FindData(const char *name, type_code type, const void **data, 2720 ssize_t *numBytes) const 2721 { 2722 return FindData(name, type, 0, data, numBytes); 2723 } 2724 2725 2726 status_t 2727 BMessage::ReplaceString(const char *name, const char *string) 2728 { 2729 if (string == NULL) 2730 return B_BAD_VALUE; 2731 2732 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 2733 } 2734 2735 2736 status_t 2737 BMessage::ReplaceString(const char *name, int32 index, const char *string) 2738 { 2739 if (string == NULL) 2740 return B_BAD_VALUE; 2741 2742 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 2743 } 2744 2745 2746 status_t 2747 BMessage::ReplaceString(const char *name, const BString &string) 2748 { 2749 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 2750 string.Length() + 1); 2751 } 2752 2753 2754 status_t 2755 BMessage::ReplaceString(const char *name, int32 index, const BString &string) 2756 { 2757 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 2758 string.Length() + 1); 2759 } 2760 2761 2762 status_t 2763 BMessage::ReplacePointer(const char *name, const void *pointer) 2764 { 2765 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 2766 } 2767 2768 2769 status_t 2770 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer) 2771 { 2772 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 2773 } 2774 2775 2776 status_t 2777 BMessage::ReplaceMessenger(const char *name, BMessenger messenger) 2778 { 2779 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 2780 sizeof(BMessenger)); 2781 } 2782 2783 2784 status_t 2785 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger) 2786 { 2787 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 2788 sizeof(BMessenger)); 2789 } 2790 2791 2792 status_t 2793 BMessage::ReplaceRef(const char *name, const entry_ref *ref) 2794 { 2795 return ReplaceRef(name, 0, ref); 2796 } 2797 2798 2799 status_t 2800 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref) 2801 { 2802 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2803 char buffer[size]; 2804 2805 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2806 2807 if (error >= B_OK) 2808 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size); 2809 2810 return error; 2811 } 2812 2813 2814 status_t 2815 BMessage::ReplaceMessage(const char *name, const BMessage *message) 2816 { 2817 return ReplaceMessage(name, 0, message); 2818 } 2819 2820 2821 status_t 2822 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message) 2823 { 2824 if (message == NULL) 2825 return B_BAD_VALUE; 2826 2827 ssize_t size = message->FlattenedSize(); 2828 char buffer[size]; 2829 2830 status_t error = message->Flatten(buffer, size); 2831 2832 if (error >= B_OK) 2833 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 2834 2835 return error; 2836 } 2837 2838 2839 status_t 2840 BMessage::ReplaceFlat(const char *name, BFlattenable *object) 2841 { 2842 return ReplaceFlat(name, 0, object); 2843 } 2844 2845 2846 status_t 2847 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object) 2848 { 2849 if (object == NULL) 2850 return B_BAD_VALUE; 2851 2852 ssize_t size = object->FlattenedSize(); 2853 char buffer[size]; 2854 2855 status_t error = object->Flatten(buffer, size); 2856 2857 if (error >= B_OK) 2858 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 2859 2860 return error; 2861 } 2862 2863 2864 status_t 2865 BMessage::ReplaceData(const char *name, type_code type, const void *data, 2866 ssize_t numBytes) 2867 { 2868 return ReplaceData(name, type, 0, data, numBytes); 2869 } 2870 2871 2872 bool 2873 BMessage::HasFlat(const char *name, const BFlattenable *object) const 2874 { 2875 return HasFlat(name, 0, object); 2876 } 2877 2878 2879 bool 2880 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object) 2881 const 2882 { 2883 return HasData(name, object->TypeCode(), index); 2884 } 2885