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