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