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