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