1 /* 2 * Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <util/KMessage.h> 8 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <ByteOrder.h> 13 #include <Debug.h> 14 #include <KernelExport.h> 15 #include <TypeConstants.h> 16 17 18 #if defined(_BOOT_MODE) || defined(_LOADER_MODE) 19 # include <util/kernel_cpp.h> 20 #else 21 # include <new> 22 #endif 23 24 25 // TODO: Add a field index using a hash map, so that lookup improves to O(1) 26 // (is now O(n)). 27 28 29 // define the PANIC macro 30 #ifndef PANIC 31 # ifdef _KERNEL_MODE 32 # define PANIC(str) panic(str) 33 # else 34 # define PANIC(str) debugger(str) 35 # endif 36 #endif 37 38 39 static const int32 kMessageReallocChunkSize = 64; 40 41 const uint32 KMessage::kMessageHeaderMagic = 'kMsG'; 42 43 44 // #pragma mark - Helper Functions 45 46 static inline int32 47 _Align(int32 offset) 48 { 49 return (offset + 3) & ~0x3; 50 } 51 52 53 static inline void* 54 _Align(void* address, int32 offset = 0) 55 { 56 return (void*)(((uint32)address + offset + 3) & ~0x3); 57 } 58 59 60 // #pragma mark - FieldValueHeader 61 62 63 struct KMessage::FieldValueHeader { 64 int32 size; 65 66 void* Data() 67 { 68 return _Align(this, sizeof(FieldValueHeader)); 69 } 70 71 FieldValueHeader* NextFieldValueHeader() 72 { 73 return (FieldValueHeader*)_Align(Data(), size); 74 } 75 }; 76 77 78 // #pragma mark - FieldHeader 79 80 81 struct KMessage::FieldHeader { 82 type_code type; 83 int32 elementSize; // if < 0: non-fixed size 84 int32 elementCount; 85 int32 fieldSize; 86 int16 headerSize; 87 char name[1]; 88 89 void* Data() 90 { 91 return (uint8*)this + headerSize; 92 } 93 94 bool HasFixedElementSize() 95 { 96 return elementSize >= 0; 97 } 98 99 void* ElementAt(int32 index, int32* size) 100 { 101 if (index < 0 || index >= elementCount) 102 return NULL; 103 uint8* data = (uint8*)this + headerSize; 104 if (HasFixedElementSize()) { 105 *size = elementSize; 106 return data + elementSize * index; 107 } 108 // non-fixed element size: we need to iterate 109 FieldValueHeader* valueHeader = (FieldValueHeader*)data; 110 for (int i = 0; i < index; i++) 111 valueHeader = valueHeader->NextFieldValueHeader(); 112 *size = valueHeader->size; 113 return valueHeader->Data(); 114 } 115 116 FieldHeader* NextFieldHeader() 117 { 118 return (FieldHeader*)_Align(this, fieldSize); 119 } 120 }; 121 122 123 // #pragma mark - KMessage 124 125 126 KMessage::KMessage() 127 : 128 fBuffer(NULL), 129 fBufferCapacity(0), 130 fFlags(0), 131 fLastFieldOffset(0) 132 { 133 Unset(); 134 } 135 136 137 KMessage::KMessage(uint32 what) 138 : 139 fBuffer(NULL), 140 fBufferCapacity(0), 141 fFlags(0), 142 fLastFieldOffset(0) 143 { 144 Unset(); 145 SetWhat(what); 146 } 147 148 149 KMessage::~KMessage() 150 { 151 Unset(); 152 } 153 154 155 status_t 156 KMessage::SetTo(uint32 what, uint32 flags) 157 { 158 // There are no flags interesting in this case at the moment. 159 Unset(); 160 SetWhat(what); 161 return B_OK; 162 } 163 164 165 status_t 166 KMessage::SetTo(void* buffer, int32 bufferSize, uint32 what, uint32 flags) 167 { 168 Unset(); 169 170 if (!buffer) 171 return B_BAD_VALUE; 172 173 if (bufferSize < 0) { 174 if (!(flags & KMESSAGE_INIT_FROM_BUFFER)) 175 return B_BAD_VALUE; 176 } else if (bufferSize < (int)sizeof(Header)) 177 return B_BAD_VALUE; 178 179 // if read-only, we need to init from the buffer, too 180 if ((flags & KMESSAGE_READ_ONLY) != 0 181 && (flags & KMESSAGE_INIT_FROM_BUFFER) == 0) { 182 return B_BAD_VALUE; 183 } 184 185 // if not initializing from the given buffer, cloning it doesn't make sense 186 if ((flags & KMESSAGE_INIT_FROM_BUFFER) == 0 187 && (flags & KMESSAGE_CLONE_BUFFER) != 0) { 188 return B_BAD_VALUE; 189 } 190 191 fBuffer = buffer; 192 fBufferCapacity = bufferSize; 193 fFlags = flags; 194 195 status_t error = B_OK; 196 if (flags & KMESSAGE_INIT_FROM_BUFFER) 197 error = _InitFromBuffer(bufferSize < 0); 198 else 199 _InitBuffer(what); 200 201 if (error != B_OK) 202 Unset(); 203 204 return error; 205 } 206 207 208 status_t 209 KMessage::SetTo(const void* buffer, int32 bufferSize, uint32 flags) 210 { 211 return SetTo(const_cast<void*>(buffer), bufferSize, 0, 212 KMESSAGE_INIT_FROM_BUFFER | KMESSAGE_READ_ONLY | flags); 213 } 214 215 216 void 217 KMessage::Unset() 218 { 219 // free buffer 220 if (fBuffer && fBuffer != &fHeader && (fFlags & KMESSAGE_OWNS_BUFFER)) 221 free(fBuffer); 222 fBuffer = &fHeader; 223 fBufferCapacity = sizeof(Header); 224 _InitBuffer(0); 225 } 226 227 228 void 229 KMessage::SetWhat(uint32 what) 230 { 231 _Header()->what = what; 232 } 233 234 235 uint32 236 KMessage::What() const 237 { 238 return _Header()->what; 239 } 240 241 242 const void* 243 KMessage::Buffer() const 244 { 245 return fBuffer; 246 } 247 248 249 int32 250 KMessage::BufferCapacity() const 251 { 252 return fBufferCapacity; 253 } 254 255 256 int32 257 KMessage::ContentSize() const 258 { 259 return _Header()->size; 260 } 261 262 263 status_t 264 KMessage::AddField(const char* name, type_code type, int32 elementSize, 265 KMessageField* field) 266 { 267 if (!name || type == B_ANY_TYPE) 268 return B_BAD_VALUE; 269 KMessageField existingField; 270 if (FindField(name, &existingField) == B_OK) 271 return B_NAME_IN_USE; 272 return _AddField(name, type, elementSize, field); 273 } 274 275 276 status_t 277 KMessage::FindField(const char* name, KMessageField* field) const 278 { 279 return FindField(name, B_ANY_TYPE, field); 280 } 281 282 283 status_t 284 KMessage::FindField(const char* name, type_code type, 285 KMessageField* field) const 286 { 287 if (!name) 288 return B_BAD_VALUE; 289 KMessageField stackField; 290 if (field) 291 field->Unset(); 292 else 293 field = &stackField; 294 while (GetNextField(field) == B_OK) { 295 if ((type == B_ANY_TYPE || field->TypeCode() == type) 296 && strcmp(name, field->Name()) == 0) { 297 return B_OK; 298 } 299 } 300 return B_NAME_NOT_FOUND; 301 } 302 303 304 status_t 305 KMessage::GetNextField(KMessageField* field) const 306 { 307 if (!field || (field->Message() != NULL && field->Message() != this)) 308 return B_BAD_VALUE; 309 FieldHeader* fieldHeader = field->_Header(); 310 FieldHeader* lastField = _LastFieldHeader(); 311 if (!lastField) 312 return B_NAME_NOT_FOUND; 313 if (fieldHeader == NULL) { 314 fieldHeader = _FirstFieldHeader(); 315 } else { 316 if ((uint8*)fieldHeader < (uint8*)_FirstFieldHeader() 317 || (uint8*)fieldHeader > (uint8*)lastField) { 318 return B_BAD_VALUE; 319 } 320 if (fieldHeader == lastField) 321 return B_NAME_NOT_FOUND; 322 fieldHeader = fieldHeader->NextFieldHeader(); 323 } 324 field->SetTo(const_cast<KMessage*>(this), _BufferOffsetFor(fieldHeader)); 325 return B_OK; 326 } 327 328 329 bool 330 KMessage::IsEmpty() const 331 { 332 return _LastFieldHeader() == NULL; 333 } 334 335 336 status_t 337 KMessage::AddData(const char* name, type_code type, const void* data, 338 int32 numBytes, bool isFixedSize) 339 { 340 if (!name || type == B_ANY_TYPE || !data || numBytes < 0) 341 return B_BAD_VALUE; 342 KMessageField field; 343 if (FindField(name, &field) == B_OK) { 344 // field with that name already exists: check its type 345 if (field.TypeCode() != type) 346 return B_BAD_TYPE; 347 } else { 348 // no such field yet: add it 349 status_t error = _AddField(name, type, (isFixedSize ? numBytes : -1), 350 &field); 351 if (error != B_OK) 352 return error; 353 } 354 return _AddFieldData(&field, data, numBytes, 1); 355 } 356 357 358 status_t 359 KMessage::AddArray(const char* name, type_code type, const void* data, 360 int32 elementSize, int32 elementCount) 361 { 362 if (!name || type == B_ANY_TYPE || !data || elementSize < 0 363 || elementCount < 0) { 364 return B_BAD_VALUE; 365 } 366 KMessageField field; 367 if (FindField(name, &field) == B_OK) { 368 // field with that name already exists: check its type 369 if (field.TypeCode() != type) 370 return B_BAD_TYPE; 371 } else { 372 // no such field yet: add it 373 status_t error = _AddField(name, type, elementSize, &field); 374 if (error != B_OK) 375 return error; 376 } 377 return _AddFieldData(&field, data, elementSize, elementCount); 378 } 379 380 381 status_t 382 KMessage::SetData(const char* name, type_code type, const void* data, 383 int32 numBytes) 384 { 385 if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY)) 386 return B_NOT_ALLOWED; 387 388 KMessageField field; 389 390 if (FindField(name, &field) == B_OK) { 391 // field already known 392 if (field.TypeCode() != type || !field.HasFixedElementSize() 393 || field.ElementSize() != numBytes) { 394 return B_BAD_VALUE; 395 } 396 397 // if it has an element, just replace its value 398 if (field.CountElements() > 0) { 399 const void* element = field.ElementAt(0); 400 memcpy(const_cast<void*>(element), data, numBytes); 401 return B_OK; 402 } 403 } else { 404 // no such field yet -- add it 405 status_t error = _AddField(name, type, numBytes, &field); 406 if (error != B_OK) 407 return error; 408 } 409 410 // we've got an empty field -- add the element 411 return _AddFieldData(&field, data, numBytes, 1); 412 } 413 414 415 status_t 416 KMessage::FindData(const char* name, type_code type, const void** data, 417 int32* numBytes) const 418 { 419 return FindData(name, type, 0, data, numBytes); 420 } 421 422 423 status_t 424 KMessage::FindData(const char* name, type_code type, int32 index, 425 const void** data, int32* numBytes) const 426 { 427 if (!name || !data || !numBytes) 428 return B_BAD_VALUE; 429 KMessageField field; 430 status_t error = FindField(name, type, &field); 431 if (error != B_OK) 432 return error; 433 const void* foundData = field.ElementAt(index, numBytes); 434 if (!foundData) 435 return B_BAD_INDEX; 436 if (data) 437 *data = foundData; 438 return B_OK; 439 } 440 441 442 team_id 443 KMessage::Sender() const 444 { 445 return _Header()->sender; 446 } 447 448 449 int32 450 KMessage::TargetToken() const 451 { 452 return _Header()->targetToken; 453 } 454 455 456 port_id 457 KMessage::ReplyPort() const 458 { 459 return _Header()->replyPort; 460 } 461 462 463 int32 464 KMessage::ReplyToken() const 465 { 466 return _Header()->replyToken; 467 } 468 469 470 void 471 KMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort, 472 int32 replyToken, team_id senderTeam) 473 { 474 Header* header = _Header(); 475 header->sender = senderTeam; 476 header->targetToken = targetToken; 477 header->replyPort = replyPort; 478 header->replyToken = replyToken; 479 header->sender = senderTeam; 480 } 481 482 483 #ifndef KMESSAGE_CONTAINER_ONLY 484 485 486 status_t 487 KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort, 488 int32 replyToken, bigtime_t timeout, team_id senderTeam) 489 { 490 // get the sender team 491 if (senderTeam < 0) { 492 thread_info info; 493 status_t error = get_thread_info(find_thread(NULL), &info); 494 if (error != B_OK) 495 return error; 496 497 senderTeam = info.team; 498 } 499 500 SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam); 501 502 // send the message 503 if (timeout < 0) 504 return write_port(targetPort, 'KMSG', fBuffer, ContentSize()); 505 506 return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(), 507 B_RELATIVE_TIMEOUT, timeout); 508 } 509 510 511 status_t 512 KMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply, 513 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam) 514 { 515 // get the team the target port belongs to 516 port_info portInfo; 517 status_t error = get_port_info(targetPort, &portInfo); 518 if (error != B_OK) 519 return error; 520 team_id targetTeam = portInfo.team; 521 // allocate a reply port, if a reply is desired 522 port_id replyPort = -1; 523 if (reply) { 524 // get our team 525 team_id ourTeam = B_SYSTEM_TEAM; 526 #ifndef _KERNEL_MODE 527 if (targetTeam != B_SYSTEM_TEAM) { 528 thread_info threadInfo; 529 error = get_thread_info(find_thread(NULL), &threadInfo); 530 if (error != B_OK) 531 return error; 532 ourTeam = threadInfo.team; 533 } 534 #endif 535 // create the port 536 replyPort = create_port(1, "KMessage reply port"); 537 if (replyPort < 0) 538 return replyPort; 539 // If the target team is not our team and not the kernel team either, 540 // we transfer the ownership of the port to it, so we will not block 541 if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM) 542 set_port_owner(replyPort, targetTeam); 543 } 544 struct PortDeleter { 545 PortDeleter(port_id port) : port(port) {} 546 ~PortDeleter() 547 { 548 if (port >= 0) 549 delete_port(port); 550 } 551 552 port_id port; 553 } replyPortDeleter(replyPort); 554 // send the message 555 error = SendTo(targetPort, targetToken, replyPort, 0, 556 deliveryTimeout, senderTeam); 557 if (error != B_OK) 558 return error; 559 // get the reply 560 if (reply) 561 return reply->ReceiveFrom(replyPort, replyTimeout); 562 return B_OK; 563 } 564 565 566 status_t 567 KMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken, 568 bigtime_t timeout, team_id senderTeam) 569 { 570 if (!message) 571 return B_BAD_VALUE; 572 return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken, 573 timeout, senderTeam); 574 } 575 576 577 status_t 578 KMessage::SendReply(KMessage* message, KMessage* reply, 579 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam) 580 { 581 if (!message) 582 return B_BAD_VALUE; 583 return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout, 584 replyTimeout, senderTeam); 585 } 586 587 588 status_t 589 KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout, 590 port_message_info* messageInfo) 591 { 592 port_message_info _messageInfo; 593 if (messageInfo == NULL) 594 messageInfo = &_messageInfo; 595 596 // get the port buffer size 597 status_t error; 598 if (timeout < 0) { 599 error = get_port_message_info_etc(fromPort, messageInfo, 0, 0); 600 } else { 601 error = get_port_message_info_etc(fromPort, messageInfo, 602 B_RELATIVE_TIMEOUT, timeout); 603 } 604 if (error != B_OK) 605 return error; 606 607 // allocate a buffer 608 uint8* buffer = (uint8*)malloc(messageInfo->size); 609 if (!buffer) 610 return B_NO_MEMORY; 611 612 // read the message 613 int32 what; 614 ssize_t realSize = read_port_etc(fromPort, &what, buffer, messageInfo->size, 615 B_RELATIVE_TIMEOUT, 0); 616 if (realSize < 0) { 617 free(buffer); 618 return realSize; 619 } 620 if (messageInfo->size != (size_t)realSize) { 621 free(buffer); 622 return B_ERROR; 623 } 624 625 // init the message 626 return SetTo(buffer, messageInfo->size, 0, 627 KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER); 628 } 629 630 631 #endif // !KMESSAGE_CONTAINER_ONLY 632 633 634 void 635 KMessage::Dump(void (*printFunc)(const char*, ...)) const 636 { 637 Header* header = _Header(); 638 printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: %#" 639 B_PRIx32 "\n", fBuffer, header->size, fBufferCapacity, fFlags); 640 641 KMessageField field; 642 while (GetNextField(&field) == B_OK) { 643 type_code type = field.TypeCode(); 644 uint32 bigEndianType = B_HOST_TO_BENDIAN_INT32(type); 645 int nameSpacing = 17 - strlen(field.Name()); 646 if (nameSpacing < 0) 647 nameSpacing = 0; 648 649 printFunc(" field: \"%s\"%*s (%.4s): ", field.Name(), nameSpacing, "", 650 (char*)&bigEndianType); 651 652 if (field.CountElements() != 1) 653 printFunc("\n"); 654 655 int32 size; 656 for (int i = 0; const void* data = field.ElementAt(i, &size); i++) { 657 if (field.CountElements() != 1) 658 printFunc(" [%2d] ", i); 659 660 bool isIntType = false; 661 int64 intData = 0; 662 switch (type) { 663 case B_BOOL_TYPE: 664 printFunc("%s\n", (*(bool*)data ? "true" : "false")); 665 break; 666 case B_INT8_TYPE: 667 isIntType = true; 668 intData = *(int8*)data; 669 break; 670 case B_INT16_TYPE: 671 isIntType = true; 672 intData = *(int16*)data; 673 break; 674 case B_INT32_TYPE: 675 isIntType = true; 676 intData = *(int32*)data; 677 break; 678 case B_INT64_TYPE: 679 isIntType = true; 680 intData = *(int64*)data; 681 break; 682 case B_STRING_TYPE: 683 printFunc("\"%s\"\n", (char*)data); 684 break; 685 default: 686 printFunc("data at %p, %ld bytes\n", (char*)data, size); 687 break; 688 } 689 if (isIntType) 690 printFunc("%lld (0x%llx)\n", intData, intData); 691 } 692 } 693 } 694 695 696 KMessage::Header* 697 KMessage::_Header() const 698 { 699 return (Header*)fBuffer; 700 } 701 702 703 int32 704 KMessage::_BufferOffsetFor(const void* data) const 705 { 706 if (!data) 707 return -1; 708 return (uint8*)data - (uint8*)fBuffer; 709 } 710 711 712 KMessage::FieldHeader* 713 KMessage::_FirstFieldHeader() const 714 { 715 return (FieldHeader*)_Align(fBuffer, sizeof(Header)); 716 } 717 718 719 KMessage::FieldHeader* 720 KMessage::_LastFieldHeader() const 721 { 722 return _FieldHeaderForOffset(fLastFieldOffset); 723 } 724 725 726 KMessage::FieldHeader* 727 KMessage::_FieldHeaderForOffset(int32 offset) const 728 { 729 if (offset <= 0 || offset >= _Header()->size) 730 return NULL; 731 return (FieldHeader*)((uint8*)fBuffer + offset); 732 } 733 734 735 status_t 736 KMessage::_AddField(const char* name, type_code type, int32 elementSize, 737 KMessageField* field) 738 { 739 FieldHeader* fieldHeader; 740 int32 alignedSize; 741 status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true, 742 true, (void**)&fieldHeader, &alignedSize); 743 if (error != B_OK) 744 return error; 745 fieldHeader->type = type; 746 fieldHeader->elementSize = elementSize; 747 fieldHeader->elementCount = 0; 748 fieldHeader->fieldSize = alignedSize; 749 fieldHeader->headerSize = alignedSize; 750 strcpy(fieldHeader->name, name); 751 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 752 if (field) 753 field->SetTo(this, _BufferOffsetFor(fieldHeader)); 754 return B_OK; 755 } 756 757 758 status_t 759 KMessage::_AddFieldData(KMessageField* field, const void* data, 760 int32 elementSize, int32 elementCount) 761 { 762 if (!field) 763 return B_BAD_VALUE; 764 FieldHeader* fieldHeader = field->_Header(); 765 FieldHeader* lastField = _LastFieldHeader(); 766 if (!fieldHeader || fieldHeader != lastField || !data 767 || elementSize < 0 || elementCount < 0) { 768 return B_BAD_VALUE; 769 } 770 if (elementCount == 0) 771 return B_OK; 772 // fixed size values 773 if (fieldHeader->HasFixedElementSize()) { 774 if (elementSize != fieldHeader->elementSize) 775 return B_BAD_VALUE; 776 void* address; 777 int32 alignedSize; 778 status_t error = _AllocateSpace(elementSize * elementCount, 779 (fieldHeader->elementCount == 0), false, &address, &alignedSize); 780 if (error != B_OK) 781 return error; 782 fieldHeader = field->_Header(); // might have been relocated 783 memcpy(address, data, elementSize * elementCount); 784 fieldHeader->elementCount += elementCount; 785 fieldHeader->fieldSize = (uint8*)address + alignedSize 786 - (uint8*)fieldHeader; 787 return B_OK; 788 } 789 // non-fixed size values 790 // add the elements individually (TODO: Optimize!) 791 int32 valueHeaderSize = _Align(sizeof(FieldValueHeader)); 792 int32 entrySize = valueHeaderSize + elementSize; 793 for (int32 i = 0; i < elementCount; i++) { 794 void* address; 795 int32 alignedSize; 796 status_t error = _AllocateSpace(entrySize, true, false, &address, 797 &alignedSize); 798 if (error != B_OK) 799 return error; 800 fieldHeader = field->_Header(); // might have been relocated 801 FieldValueHeader* valueHeader = (FieldValueHeader*)address; 802 valueHeader->size = elementSize; 803 memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize, 804 elementSize); 805 fieldHeader->elementCount++; 806 fieldHeader->fieldSize = (uint8*)address + alignedSize 807 - (uint8*)fieldHeader; 808 } 809 return B_OK; 810 } 811 812 813 status_t 814 KMessage::_InitFromBuffer(bool sizeFromBuffer) 815 { 816 if (fBuffer == NULL) 817 return B_BAD_DATA; 818 819 // clone the buffer, if requested 820 if ((fFlags & KMESSAGE_CLONE_BUFFER) != 0) { 821 if (sizeFromBuffer) { 822 int32 size = fBufferCapacity; 823 memcpy(&size, &_Header()->size, 4); 824 fBufferCapacity = size; 825 } 826 827 void* buffer = malloc(fBufferCapacity); 828 if (buffer == NULL) 829 return B_NO_MEMORY; 830 831 memcpy(buffer, fBuffer, fBufferCapacity); 832 fBuffer = buffer; 833 fFlags &= ~(uint32)(KMESSAGE_READ_ONLY | KMESSAGE_CLONE_BUFFER); 834 } 835 836 if (_Align(fBuffer) != fBuffer) 837 return B_BAD_DATA; 838 Header* header = _Header(); 839 840 if (sizeFromBuffer) 841 fBufferCapacity = header->size; 842 843 if (fBufferCapacity < (int)sizeof(Header)) 844 return B_BAD_DATA; 845 846 // check header 847 if (header->magic != kMessageHeaderMagic) 848 return B_BAD_DATA; 849 if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity) 850 return B_BAD_DATA; 851 852 // check the fields 853 FieldHeader* fieldHeader = NULL; 854 uint8* data = (uint8*)_FirstFieldHeader(); 855 int32 remainingBytes = (uint8*)fBuffer + header->size - data; 856 while (remainingBytes > 0) { 857 if (remainingBytes < (int)sizeof(FieldHeader)) 858 return B_BAD_DATA; 859 fieldHeader = (FieldHeader*)data; 860 // check field header 861 if (fieldHeader->type == B_ANY_TYPE) 862 return B_BAD_DATA; 863 if (fieldHeader->elementCount < 0) 864 return B_BAD_DATA; 865 if (fieldHeader->fieldSize < (int)sizeof(FieldHeader) 866 || fieldHeader->fieldSize > remainingBytes) { 867 return B_BAD_DATA; 868 } 869 if (fieldHeader->headerSize < (int)sizeof(FieldHeader) 870 || fieldHeader->headerSize > fieldHeader->fieldSize) { 871 return B_BAD_DATA; 872 } 873 int32 maxNameLen = data + fieldHeader->headerSize 874 - (uint8*)fieldHeader->name; 875 int32 nameLen = strnlen(fieldHeader->name, maxNameLen); 876 if (nameLen == maxNameLen || nameLen == 0) 877 return B_BAD_DATA; 878 int32 fieldSize = fieldHeader->headerSize; 879 if (fieldHeader->HasFixedElementSize()) { 880 // fixed element size 881 int32 dataSize = fieldHeader->elementSize 882 * fieldHeader->elementCount; 883 fieldSize = (uint8*)fieldHeader->Data() + dataSize - data; 884 } else { 885 // non-fixed element size 886 FieldValueHeader* valueHeader 887 = (FieldValueHeader*)fieldHeader->Data(); 888 for (int32 i = 0; i < fieldHeader->elementCount; i++) { 889 remainingBytes = (uint8*)fBuffer + header->size 890 - (uint8*)valueHeader; 891 if (remainingBytes < (int)sizeof(FieldValueHeader)) 892 return B_BAD_DATA; 893 uint8* value = (uint8*)valueHeader->Data(); 894 remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value; 895 if (remainingBytes < valueHeader->size) 896 return B_BAD_DATA; 897 fieldSize = value + valueHeader->size - data; 898 valueHeader = valueHeader->NextFieldValueHeader(); 899 } 900 if (fieldSize > fieldHeader->fieldSize) 901 return B_BAD_DATA; 902 } 903 data = (uint8*)fieldHeader->NextFieldHeader(); 904 remainingBytes = (uint8*)fBuffer + header->size - data; 905 } 906 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 907 return B_OK; 908 } 909 910 911 void 912 KMessage::_InitBuffer(uint32 what) 913 { 914 Header* header = _Header(); 915 header->magic = kMessageHeaderMagic; 916 header->size = sizeof(Header); 917 header->what = what; 918 header->sender = -1; 919 header->targetToken = -1; 920 header->replyPort = -1; 921 header->replyToken = -1; 922 fLastFieldOffset = 0; 923 } 924 925 926 void 927 KMessage::_CheckBuffer() 928 { 929 int32 lastFieldOffset = fLastFieldOffset; 930 if (_InitFromBuffer(false) != B_OK) { 931 PANIC("internal data mangled"); 932 } 933 if (fLastFieldOffset != lastFieldOffset) { 934 PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()"); 935 } 936 } 937 938 939 status_t 940 KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize, 941 void** address, int32* alignedSize) 942 { 943 if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY)) 944 return B_NOT_ALLOWED; 945 946 int32 offset = ContentSize(); 947 if (alignAddress) 948 offset = _Align(offset); 949 int32 newSize = offset + size; 950 if (alignSize) 951 newSize = _Align(newSize); 952 // reallocate if necessary 953 if (fBuffer == &fHeader) { 954 int32 newCapacity = _CapacityFor(newSize); 955 void* newBuffer = malloc(newCapacity); 956 if (!newBuffer) 957 return B_NO_MEMORY; 958 fBuffer = newBuffer; 959 fBufferCapacity = newCapacity; 960 fFlags |= KMESSAGE_OWNS_BUFFER; 961 memcpy(fBuffer, &fHeader, sizeof(fHeader)); 962 } else { 963 if (newSize > fBufferCapacity) { 964 // if we don't own the buffer, we can't resize it 965 if (!(fFlags & KMESSAGE_OWNS_BUFFER)) 966 return B_BUFFER_OVERFLOW; 967 int32 newCapacity = _CapacityFor(newSize); 968 void* newBuffer = realloc(fBuffer, newCapacity); 969 if (!newBuffer) 970 return B_NO_MEMORY; 971 fBuffer = newBuffer; 972 fBufferCapacity = newCapacity; 973 } 974 } 975 _Header()->size = newSize; 976 *address = (char*)fBuffer + offset; 977 *alignedSize = newSize - offset; 978 return B_OK; 979 } 980 981 982 int32 983 KMessage::_CapacityFor(int32 size) 984 { 985 return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize 986 * kMessageReallocChunkSize; 987 } 988 989 990 // #pragma mark - KMessageField 991 992 993 KMessageField::KMessageField() 994 : 995 fMessage(NULL), 996 fHeaderOffset(0) 997 { 998 } 999 1000 1001 void 1002 KMessageField::Unset() 1003 { 1004 fMessage = NULL; 1005 fHeaderOffset = 0; 1006 } 1007 1008 1009 KMessage* 1010 KMessageField::Message() const 1011 { 1012 return fMessage; 1013 } 1014 1015 1016 const char* 1017 KMessageField::Name() const 1018 { 1019 KMessage::FieldHeader* header = _Header(); 1020 return header ? header->name : NULL; 1021 } 1022 1023 1024 type_code 1025 KMessageField::TypeCode() const 1026 { 1027 KMessage::FieldHeader* header = _Header(); 1028 return header ? header->type : 0; 1029 } 1030 1031 1032 bool 1033 KMessageField::HasFixedElementSize() const 1034 { 1035 KMessage::FieldHeader* header = _Header(); 1036 return header ? header->HasFixedElementSize() : false; 1037 } 1038 1039 1040 int32 1041 KMessageField::ElementSize() const 1042 { 1043 KMessage::FieldHeader* header = _Header(); 1044 return header ? header->elementSize : -1; 1045 } 1046 1047 1048 status_t 1049 KMessageField::AddElement(const void* data, int32 size) 1050 { 1051 KMessage::FieldHeader* header = _Header(); 1052 if (!header || !data) 1053 return B_BAD_VALUE; 1054 if (size < 0) { 1055 size = ElementSize(); 1056 if (size < 0) 1057 return B_BAD_VALUE; 1058 } 1059 return fMessage->_AddFieldData(this, data, size, 1); 1060 } 1061 1062 1063 status_t 1064 KMessageField::AddElements(const void* data, int32 count, int32 elementSize) 1065 { 1066 KMessage::FieldHeader* header = _Header(); 1067 if (!header || !data || count < 0) 1068 return B_BAD_VALUE; 1069 if (elementSize < 0) { 1070 elementSize = ElementSize(); 1071 if (elementSize < 0) 1072 return B_BAD_VALUE; 1073 } 1074 return fMessage->_AddFieldData(this, data, elementSize, count); 1075 } 1076 1077 1078 const void* 1079 KMessageField::ElementAt(int32 index, int32* size) const 1080 { 1081 KMessage::FieldHeader* header = _Header(); 1082 return header ? header->ElementAt(index, size) : NULL; 1083 } 1084 1085 1086 int32 1087 KMessageField::CountElements() const 1088 { 1089 KMessage::FieldHeader* header = _Header(); 1090 return header ? header->elementCount : 0; 1091 } 1092 1093 1094 void 1095 KMessageField::SetTo(KMessage* message, int32 headerOffset) 1096 { 1097 fMessage = message; 1098 fHeaderOffset = headerOffset; 1099 } 1100 1101 1102 KMessage::FieldHeader* 1103 KMessageField::_Header() const 1104 { 1105 return fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL; 1106 } 1107