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