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