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