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 // ReceiveFrom 557 status_t 558 KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout) 559 { 560 // get the port buffer size 561 ssize_t size; 562 if (timeout < 0) 563 size = port_buffer_size(fromPort); 564 else 565 size = port_buffer_size_etc(fromPort, B_RELATIVE_TIMEOUT, timeout); 566 if (size < 0) 567 return size; 568 // allocate a buffer 569 uint8* buffer = (uint8*)malloc(size); 570 if (!buffer) 571 return B_NO_MEMORY; 572 // read the message 573 int32 what; 574 ssize_t realSize = read_port_etc(fromPort, &what, buffer, size, 575 B_RELATIVE_TIMEOUT, 0); 576 if (realSize < 0) 577 return realSize; 578 if (size != realSize) 579 return B_ERROR; 580 // init the message 581 return SetTo(buffer, size, 0, 582 KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER); 583 } 584 585 #endif // !KMESSAGE_CONTAINER_ONLY 586 587 588 // _Header 589 KMessage::Header * 590 KMessage::_Header() const 591 { 592 return (Header*)fBuffer; 593 } 594 595 // _BufferOffsetFor 596 int32 597 KMessage::_BufferOffsetFor(const void* data) const 598 { 599 if (!data) 600 return -1; 601 return ((uint8*)data - (uint8*)fBuffer); 602 } 603 604 // _FirstFieldHeader 605 KMessage::FieldHeader * 606 KMessage::_FirstFieldHeader() const 607 { 608 return (FieldHeader*)_Align(fBuffer, sizeof(Header)); 609 } 610 611 // _LastFieldHeader 612 KMessage::FieldHeader * 613 KMessage::_LastFieldHeader() const 614 { 615 return _FieldHeaderForOffset(fLastFieldOffset); 616 } 617 618 // _FieldHeaderForOffset 619 KMessage::FieldHeader * 620 KMessage::_FieldHeaderForOffset(int32 offset) const 621 { 622 if (offset <= 0 || offset >= _Header()->size) 623 return NULL; 624 return (FieldHeader*)((uint8*)fBuffer + offset); 625 } 626 627 // _AddField 628 status_t 629 KMessage::_AddField(const char *name, type_code type, int32 elementSize, 630 KMessageField *field) 631 { 632 FieldHeader *fieldHeader; 633 int32 alignedSize; 634 status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true, 635 true, (void**)&fieldHeader, &alignedSize); 636 if (error != B_OK) 637 return error; 638 fieldHeader->type = type; 639 fieldHeader->elementSize = elementSize; 640 fieldHeader->elementCount = 0; 641 fieldHeader->fieldSize = alignedSize; 642 fieldHeader->headerSize = alignedSize; 643 strcpy(fieldHeader->name, name); 644 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 645 if (field) 646 field->SetTo(this, _BufferOffsetFor(fieldHeader)); 647 return B_OK; 648 } 649 650 // _AddFieldData 651 status_t 652 KMessage::_AddFieldData(KMessageField *field, const void *data, 653 int32 elementSize, int32 elementCount) 654 { 655 if (!field) 656 return B_BAD_VALUE; 657 FieldHeader *fieldHeader = field->_Header(); 658 FieldHeader* lastField = _LastFieldHeader(); 659 if (!fieldHeader || fieldHeader != lastField || !data 660 || elementSize < 0 || elementCount < 0) { 661 return B_BAD_VALUE; 662 } 663 if (elementCount == 0) 664 return B_OK; 665 // fixed size values 666 if (fieldHeader->HasFixedElementSize()) { 667 if (elementSize != fieldHeader->elementSize) 668 return B_BAD_VALUE; 669 void *address; 670 int32 alignedSize; 671 status_t error = _AllocateSpace(elementSize * elementCount, 672 (fieldHeader->elementCount == 0), false, &address, &alignedSize); 673 if (error != B_OK) 674 return error; 675 fieldHeader = field->_Header(); // might have been relocated 676 memcpy(address, data, elementSize * elementCount); 677 fieldHeader->elementCount += elementCount; 678 fieldHeader->fieldSize = (uint8*)address + alignedSize 679 - (uint8*)fieldHeader; 680 return B_OK; 681 } 682 // non-fixed size values 683 // add the elements individually (TODO: Optimize!) 684 int32 valueHeaderSize = _Align(sizeof(FieldValueHeader)); 685 int32 entrySize = valueHeaderSize + elementSize; 686 for (int32 i = 0; i < elementCount; i++) { 687 void *address; 688 int32 alignedSize; 689 status_t error = _AllocateSpace(entrySize, true, false, &address, 690 &alignedSize); 691 if (error != B_OK) 692 return error; 693 fieldHeader = field->_Header(); // might have been relocated 694 FieldValueHeader *valueHeader = (FieldValueHeader*)address; 695 valueHeader->size = elementSize; 696 memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize, 697 elementSize); 698 fieldHeader->elementCount++; 699 fieldHeader->fieldSize = (uint8*)address + alignedSize 700 - (uint8*)fieldHeader; 701 } 702 return B_OK; 703 } 704 705 // _InitFromBuffer 706 status_t 707 KMessage::_InitFromBuffer(bool sizeFromBuffer) 708 { 709 if (!fBuffer || _Align(fBuffer) != fBuffer) 710 return B_BAD_DATA; 711 Header *header = _Header(); 712 713 if (sizeFromBuffer) 714 fBufferCapacity = header->size; 715 716 if (fBufferCapacity < (int)sizeof(Header)) 717 return B_BAD_DATA; 718 719 // check header 720 if (header->magic != kMessageHeaderMagic) 721 return B_BAD_DATA; 722 if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity) 723 return B_BAD_DATA; 724 725 // check the fields 726 FieldHeader *fieldHeader = NULL; 727 uint8 *data = (uint8*)_FirstFieldHeader(); 728 int32 remainingBytes = (uint8*)fBuffer + header->size - data; 729 while (remainingBytes > 0) { 730 if (remainingBytes < (int)sizeof(FieldHeader)) 731 return B_BAD_DATA; 732 fieldHeader = (FieldHeader*)data; 733 // check field header 734 if (fieldHeader->type == B_ANY_TYPE) 735 return B_BAD_DATA; 736 if (fieldHeader->elementCount < 0) 737 return B_BAD_DATA; 738 if (fieldHeader->fieldSize < (int)sizeof(FieldHeader) 739 || fieldHeader->fieldSize > remainingBytes) { 740 return B_BAD_DATA; 741 } 742 if (fieldHeader->headerSize < (int)sizeof(FieldHeader) 743 || fieldHeader->headerSize > fieldHeader->fieldSize) { 744 return B_BAD_DATA; 745 } 746 int32 maxNameLen = data + fieldHeader->headerSize 747 - (uint8*)fieldHeader->name; 748 int32 nameLen = strnlen(fieldHeader->name, maxNameLen); 749 if (nameLen == maxNameLen || nameLen == 0) 750 return B_BAD_DATA; 751 int32 fieldSize = fieldHeader->headerSize; 752 if (fieldHeader->HasFixedElementSize()) { 753 // fixed element size 754 int32 dataSize = fieldHeader->elementSize 755 * fieldHeader->elementCount; 756 fieldSize = (uint8*)fieldHeader->Data() + dataSize - data; 757 } else { 758 // non-fixed element size 759 FieldValueHeader *valueHeader 760 = (FieldValueHeader *)fieldHeader->Data(); 761 for (int32 i = 0; i < fieldHeader->elementCount; i++) { 762 remainingBytes = (uint8*)fBuffer + header->size 763 - (uint8*)valueHeader; 764 if (remainingBytes < (int)sizeof(FieldValueHeader)) 765 return B_BAD_DATA; 766 uint8 *value = (uint8*)valueHeader->Data(); 767 remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value; 768 if (remainingBytes < valueHeader->size) 769 return B_BAD_DATA; 770 fieldSize = value + valueHeader->size - data; 771 valueHeader = valueHeader->NextFieldValueHeader(); 772 } 773 if (fieldSize > fieldHeader->fieldSize) 774 return B_BAD_DATA; 775 } 776 data = (uint8*)fieldHeader->NextFieldHeader(); 777 remainingBytes = (uint8*)fBuffer + header->size - data; 778 } 779 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 780 return B_OK; 781 } 782 783 // _InitBuffer 784 void 785 KMessage::_InitBuffer(uint32 what) 786 { 787 Header *header = _Header(); 788 header->magic = kMessageHeaderMagic; 789 header->size = sizeof(Header); 790 header->what = what; 791 header->sender = -1; 792 header->targetToken = -1; 793 header->replyPort = -1; 794 header->replyToken = -1; 795 fLastFieldOffset = 0; 796 } 797 798 // _CheckBuffer 799 void 800 KMessage::_CheckBuffer() 801 { 802 int32 lastFieldOffset = fLastFieldOffset; 803 if (_InitFromBuffer(false) != B_OK) { 804 PANIC("internal data mangled"); 805 } 806 if (fLastFieldOffset != lastFieldOffset) { 807 PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()"); 808 } 809 } 810 811 // _AllocateSpace 812 status_t 813 KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize, 814 void **address, int32 *alignedSize) 815 { 816 if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY)) 817 return B_NOT_ALLOWED; 818 819 int32 offset = ContentSize(); 820 if (alignAddress) 821 offset = _Align(offset); 822 int32 newSize = offset + size; 823 if (alignSize) 824 newSize = _Align(newSize); 825 // reallocate if necessary 826 if (fBuffer == &fHeader) { 827 int32 newCapacity = _CapacityFor(newSize); 828 void *newBuffer = malloc(newCapacity); 829 if (!newBuffer) 830 return B_NO_MEMORY; 831 fBuffer = newBuffer; 832 fBufferCapacity = newCapacity; 833 fFlags |= KMESSAGE_OWNS_BUFFER; 834 memcpy(fBuffer, &fHeader, sizeof(fHeader)); 835 } else { 836 if (newSize > fBufferCapacity) { 837 // if we don't own the buffer, we can't resize it 838 if (!(fFlags & KMESSAGE_OWNS_BUFFER)) 839 return B_BUFFER_OVERFLOW; 840 int32 newCapacity = _CapacityFor(newSize); 841 void *newBuffer = realloc(fBuffer, newCapacity); 842 if (!newBuffer) 843 return B_NO_MEMORY; 844 fBuffer = newBuffer; 845 fBufferCapacity = newCapacity; 846 } 847 } 848 _Header()->size = newSize; 849 *address = (char*)fBuffer + offset; 850 *alignedSize = newSize - offset; 851 return B_OK; 852 } 853 854 // _CapacityFor 855 int32 856 KMessage::_CapacityFor(int32 size) 857 { 858 return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize 859 * kMessageReallocChunkSize; 860 } 861 862 863 // #pragma mark - 864 865 // constructor 866 KMessageField::KMessageField() 867 : fMessage(NULL), 868 fHeaderOffset(0) 869 { 870 } 871 872 // Unset 873 void 874 KMessageField::Unset() 875 { 876 fMessage = NULL; 877 fHeaderOffset = 0; 878 } 879 880 // Message 881 KMessage * 882 KMessageField::Message() const 883 { 884 return fMessage; 885 } 886 887 // Name 888 const char * 889 KMessageField::Name() const 890 { 891 KMessage::FieldHeader* header = _Header(); 892 return (header ? header->name : NULL); 893 } 894 895 // TypeCode 896 type_code 897 KMessageField::TypeCode() const 898 { 899 KMessage::FieldHeader* header = _Header(); 900 return (header ? header->type : 0); 901 } 902 903 // HasFixedElementSize 904 bool 905 KMessageField::HasFixedElementSize() const 906 { 907 KMessage::FieldHeader* header = _Header(); 908 return (header ? header->HasFixedElementSize() : false); 909 } 910 911 // ElementSize 912 int32 913 KMessageField::ElementSize() const 914 { 915 KMessage::FieldHeader* header = _Header(); 916 return (header ? header->elementSize : -1); 917 } 918 919 // AddElement 920 status_t 921 KMessageField::AddElement(const void *data, int32 size) 922 { 923 KMessage::FieldHeader* header = _Header(); 924 if (!header || !data) 925 return B_BAD_VALUE; 926 if (size < 0) { 927 size = ElementSize(); 928 if (size < 0) 929 return B_BAD_VALUE; 930 } 931 return fMessage->_AddFieldData(this, data, size, 1); 932 } 933 934 // AddElements 935 status_t 936 KMessageField::AddElements(const void *data, int32 count, int32 elementSize) 937 { 938 KMessage::FieldHeader* header = _Header(); 939 if (!header || !data || count < 0) 940 return B_BAD_VALUE; 941 if (elementSize < 0) { 942 elementSize = ElementSize(); 943 if (elementSize < 0) 944 return B_BAD_VALUE; 945 } 946 return fMessage->_AddFieldData(this, data, elementSize, count); 947 } 948 949 // ElementAt 950 const void * 951 KMessageField::ElementAt(int32 index, int32 *size) const 952 { 953 KMessage::FieldHeader* header = _Header(); 954 return (header ? header->ElementAt(index, size) : NULL); 955 } 956 957 // CountElements 958 int32 959 KMessageField::CountElements() const 960 { 961 KMessage::FieldHeader* header = _Header(); 962 return (header ? header->elementCount : 0); 963 } 964 965 // SetTo 966 void 967 KMessageField::SetTo(KMessage *message, int32 headerOffset) 968 { 969 fMessage = message; 970 fHeaderOffset = headerOffset; 971 } 972 973 // _GetHeader 974 KMessage::FieldHeader* 975 KMessageField::_Header() const 976 { 977 return (fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL); 978 } 979 980