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