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