github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/services/ipc/ipc.go (about) 1 package ipc 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "github.com/racerxdl/gonx/internal" 7 "github.com/racerxdl/gonx/nx/nxerrors" 8 "github.com/racerxdl/gonx/nx/nxtypes" 9 "github.com/racerxdl/gonx/svc" 10 "unsafe" 11 ) 12 13 // PackMessage is equivalent to libtransistor ipc_pack_message call 14 func PackMessage(msg *PackedMessage, buffer *[0x40]uint32) error { 15 if debug { 16 println("ipc: pack ipc message") 17 } 18 19 aDescriptors := make([]*Buffer, 0, maxIPCDescriptors) 20 bDescriptors := make([]*Buffer, 0, maxIPCDescriptors) 21 cDescriptors := make([]*Buffer, 0, maxIPCDescriptors) 22 xDescriptors := make([]*Buffer, 0, maxIPCDescriptors) 23 24 if debug { 25 println("ipc: pack: prepare") 26 } 27 for _, ipcBuffer := range msg.Buffers { 28 if ipcBuffer.Type&0x20 == 0 { 29 if ipcBuffer.Direction() == DirectionInput { // AX 30 if ipcBuffer.Family() == FamilyA { 31 aDescriptors = append(aDescriptors, ipcBuffer) 32 } else if ipcBuffer.Family() == FamilyX { // X 33 xDescriptors = append(xDescriptors, ipcBuffer) 34 } else { 35 return nxerrors.UnsupportedBufferType 36 } 37 } else if ipcBuffer.Direction() == DirectionOutput { // BC 38 if ipcBuffer.Family() == FamilyB { 39 bDescriptors = append(bDescriptors, ipcBuffer) 40 } else if ipcBuffer.Family() == FamilyC { // C 41 cDescriptors = append(cDescriptors, ipcBuffer) 42 } else { 43 return nxerrors.UnsupportedBufferType 44 } 45 } else { 46 return nxerrors.UnsupportedBufferType 47 } 48 } else { // flag 0x20 set 49 if ipcBuffer.Type == 0x21 { // IN (ax) 50 aDescriptors = append(aDescriptors, ipcBuffer) 51 xDescriptors = append(xDescriptors, &nullBuffer) 52 } else if ipcBuffer.Type == 0x22 { // OUT (bc) 53 bDescriptors = append(bDescriptors, ipcBuffer) 54 cDescriptors = append(cDescriptors, &nullBuffer) 55 } else { 56 return nxerrors.UnsupportedBufferType 57 } 58 } 59 60 // Check for overflow 61 if len(aDescriptors) >= maxIPCDescriptors || 62 len(bDescriptors) >= maxIPCDescriptors || 63 len(cDescriptors) >= maxIPCDescriptors || 64 len(xDescriptors) >= maxIPCDescriptors { 65 return nxerrors.TooManyBuffers 66 } 67 } 68 69 if debug { 70 println("ipc: pack: packing") 71 } 72 h := 0 // H for header count 73 74 buffer[h] = uint32(msg.Type) | 75 (uint32(len(xDescriptors)) << 16) | 76 (uint32(len(aDescriptors)) << 20) | 77 (uint32(len(bDescriptors)) << 24) | 78 (0 << 28) // "w" descriptors 79 h++ 80 81 cDescriptorFlags := 0 82 if len(cDescriptors) == 1 { 83 cDescriptorFlags = 2 84 } else if len(cDescriptors) > 1 { 85 cDescriptorFlags = len(cDescriptors) + 2 86 } 87 handleDescriptorEnabled := len(msg.CopyHandles) > 0 || len(msg.MoveHandles) > 0 || msg.SendPID 88 sizeFieldOffset := h 89 90 handleDescriptorEnabledNum := 0 91 if handleDescriptorEnabled { 92 handleDescriptorEnabledNum = 1 93 } 94 95 // header field 2 96 buffer[h] = 0 | // Size to be filled 97 (uint32(cDescriptorFlags) << 10) | 98 (uint32(handleDescriptorEnabledNum) << 31) 99 h++ 100 101 if handleDescriptorEnabled { 102 if len(msg.CopyHandles) >= maxIPCDescriptors || len(msg.MoveHandles) >= maxIPCDescriptors { 103 return nxerrors.TooManyHandles 104 } 105 106 sendPid := 0 107 if msg.SendPID { 108 sendPid = 1 109 } 110 111 buffer[h] = uint32(sendPid) | 112 (uint32(len(msg.CopyHandles)) << 1) | 113 (uint32(len(msg.MoveHandles)) << 5) 114 h++ 115 116 if msg.SendPID { 117 h += 2 118 } 119 120 for _, v := range msg.CopyHandles { 121 buffer[h] = uint32(v) 122 h++ 123 } 124 for _, v := range msg.MoveHandles { 125 buffer[h] = uint32(v) 126 h++ 127 } 128 } 129 130 // X Descriptors 131 for i, x := range xDescriptors { 132 if x.Addr>>39 > 0 { 133 return nxerrors.InvalidBufferAddress 134 } 135 136 if x.Size>>16 > 0 { 137 return nxerrors.InvalidBufferSize 138 } 139 140 // This mess -> https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22 141 addr64 := uint64(x.Addr) 142 143 buffer[h] = uint32(i) 144 buffer[h] |= uint32(((addr64 >> 36) & 7) << 6) 145 buffer[h] |= uint32(((i >> 9) & 7) << 9) 146 buffer[h] |= uint32(((addr64 >> 32) & 0xF) << 12) 147 buffer[h] |= uint32(x.Size) << 16 148 h++ 149 150 buffer[h] = uint32(addr64 & 0xFFFFFFFF) 151 h++ 152 } 153 154 // A descriptors 155 for _, a := range aDescriptors { 156 if a.Addr>>39 > 0 { 157 return nxerrors.InvalidBufferAddress 158 } 159 160 if a.Size>>35 > 0 { 161 return nxerrors.InvalidBufferSize 162 } 163 164 if a.Type>>8 > 4 { 165 return nxerrors.InvalidBufferFlags 166 } 167 168 buffer[h] = uint32(a.Size & 0xFFFFFFFF) 169 h++ 170 buffer[h] = uint32(a.Addr & 0xFFFFFFFF) 171 h++ 172 173 addr64 := uint64(a.Addr) 174 175 buffer[h] = uint32(a.Type) >> 6 176 buffer[h] |= uint32((addr64>>36)&0x7) << 2 177 buffer[h] |= uint32((a.Size>>32)&0xF) << 24 178 buffer[h] |= uint32((addr64>>32)&0xF) << 28 179 180 h++ 181 } 182 183 // B Descriptors 184 for _, b := range bDescriptors { 185 if b.Addr>>39 > 0 { 186 return nxerrors.InvalidBufferAddress 187 } 188 189 if b.Size>>35 > 0 { 190 return nxerrors.InvalidBufferSize 191 } 192 193 if b.Type>>8 > 4 { 194 return nxerrors.InvalidBufferFlags 195 } 196 197 buffer[h] = uint32(b.Size & 0xFFFFFFFF) 198 h++ 199 buffer[h] = uint32(b.Addr & 0xFFFFFFFF) 200 h++ 201 202 addr64 := uint64(b.Addr) 203 204 buffer[h] = uint32(b.Type) >> 6 205 buffer[h] |= uint32((addr64>>36)&0x7) << 2 206 buffer[h] |= uint32((b.Size>>32)&0xF) << 24 207 buffer[h] |= uint32((addr64>>32)&0xF) << 28 208 209 h++ 210 } 211 212 // "w" descriptors would go here 213 214 rawDataStart := h 215 h = int(uint32(h+3) & ^uint32(3)) 216 217 prePadding := h - rawDataStart 218 219 if len(msg.DataSection) > 0 { 220 internal.Memcpy(unsafe.Pointer(&buffer[h]), unsafe.Pointer(&msg.DataSection[0]), uintptr(len(msg.DataSection))) 221 paddedSize := ipcPadSize(uint64(len(msg.DataSection))) 222 paddedSize /= 4 223 h += int(paddedSize) 224 } 225 226 h += 4 - prePadding 227 228 u16LengthList := make([]uint16, 0) 229 230 // c descriptor u16 length list 231 for _, buf := range cDescriptors { 232 if buf.Type&0x10 == 0 { // u16 length list flag 233 if buf.Size>>16 > 0 { 234 return nxerrors.InvalidBufferSize 235 } 236 u16LengthList = append(u16LengthList, uint16(buf.Size)) 237 } 238 } 239 240 if len(u16LengthList) > 0 { 241 // Copy to IPC Buffer 242 internal.Memcpy(unsafe.Pointer(&buffer[h]), unsafe.Pointer(&u16LengthList[0]), uintptr(len(u16LengthList))*unsafe.Sizeof(uint16(0))) 243 } 244 245 // Move header to point to right position 246 h += (len(u16LengthList) + 1) >> 1 247 248 buffer[sizeFieldOffset] |= uint32(h - rawDataStart) // raw data section size 249 250 // C Descriptors 251 for _, c := range cDescriptors { 252 if c.Addr>>48 > 0 { 253 return nxerrors.InvalidBufferAddress 254 } 255 256 if c.Size>>16 > 0 { 257 return nxerrors.InvalidBufferSize 258 } 259 260 addr64 := uint64(c.Addr) 261 buffer[h] = uint32(addr64 & 0xFFFFFFFF) 262 h++ 263 buffer[h] = uint32(addr64 >> 32) 264 buffer[h] |= uint32(c.Size) << 16 265 h++ 266 } 267 268 return nil 269 } 270 271 // PackIPCRequest is equivalent to libtransistor ipc_pack_request call 272 func PackIPCRequest(rq *Request, object Object, marshalBuffer *[0x40]uint32) error { 273 if debug { 274 println("ipc: pack ipc request") 275 } 276 277 msg := PackedMessage{} 278 279 toDomain := rq.Type == 4 && object.ObjectID >= 0 280 msg.Buffers = rq.Buffers 281 282 if uint32(rq.Type) & ^uint32(0xFFFF) > 0 { 283 return nxerrors.InvalidRequestType 284 } 285 286 msg.Type = rq.Type 287 moveHandles := make([]nxtypes.Handle, 0, maxIPCDescriptors) 288 289 if !toDomain { 290 for _, obj := range rq.Objects { 291 if obj.ObjectID >= 0 { 292 return nxerrors.CantSendDomainObjectToSession 293 } 294 moveHandles = append(moveHandles, nxtypes.Handle(obj.GetSession())) 295 } 296 } 297 298 for _, handle := range rq.MoveHandles { 299 moveHandles = append(moveHandles, handle) 300 } 301 302 if len(moveHandles) > maxIPCDescriptors { 303 return nxerrors.TooManyHandles 304 } 305 306 msg.CopyHandles = rq.CopyHandles 307 msg.SendPID = rq.SendPID 308 309 var buff [0x200 >> 2]uint32 310 311 h := 0 312 dataSectionLen := 0 // In bytes 313 314 if toDomain { 315 if len(rq.Objects) > 8 { 316 return nxerrors.TooManyObjects 317 } 318 v := uint32(1) 319 if rq.CloseObject { 320 v = 2 321 } 322 v |= uint32(len(rq.Objects) << 8) 323 buff[h] = v 324 h++ 325 buff[h] = uint32(object.ObjectID) 326 h++ 327 328 h += 2 // alignment 329 330 dataSectionLen += 0x10 331 } 332 333 payloadSize := 0 334 335 if !rq.CloseObject { 336 buff[h] = sfci 337 h++ 338 339 buff[h] = 0 340 h++ 341 342 buff[h] = rq.RequestID 343 h++ 344 345 buff[h] = 0 346 h++ 347 348 payloadSize += 0x10 349 dataSectionLen += 0x10 350 351 if len(rq.RawData) > 0x200 { 352 return nxerrors.InvalidRawDataSize 353 } 354 if len(rq.RawData) > 0 { 355 internal.Memcpy(unsafe.Pointer(&buff[dataSectionLen/4]), unsafe.Pointer(&rq.RawData[0]), uintptr(len(rq.RawData))) 356 payloadSize += len(rq.RawData) 357 dataSectionLen += len(rq.RawData) 358 } 359 } else { 360 if !toDomain { 361 return nxerrors.CantCloseSessionLikeDomainObjects 362 } 363 364 if rq.Type != 4 || 365 len(rq.Buffers) != 0 || 366 len(rq.RawData) != 0 || 367 rq.SendPID != false || 368 len(rq.CopyHandles) != 0 || 369 len(rq.MoveHandles) != 0 || 370 len(rq.Objects) != 0 { 371 return nxerrors.MalformedCloseRequest 372 } 373 } 374 375 if toDomain { 376 buff[0] |= uint32(payloadSize) << 16 377 for _, obj := range rq.Objects { 378 if obj.GetDomain() != object.GetDomain() { 379 return nxerrors.CantSendObjectAcrossDomains 380 } 381 internal.Memcpy(unsafe.Pointer(&buff[dataSectionLen/4]), unsafe.Pointer(&obj.ObjectID), 4) 382 dataSectionLen += 4 383 } 384 } 385 386 if dataSectionLen > 0 { 387 msg.DataSection = make([]byte, dataSectionLen) 388 internal.Memcpy(unsafe.Pointer(&msg.DataSection[0]), unsafe.Pointer(&buff[0]), uintptr(dataSectionLen)) 389 } 390 391 return PackMessage(&msg, marshalBuffer) 392 } 393 394 // UnpackIPCMessage is equivalent to libtransistor ipc_unpack call 395 func UnpackIPCMessage(msg *Message, buffer *[0x40]uint32) error { 396 if debug { 397 println("ipc: unpack ipc message") 398 } 399 h := 0 // HEAD position 400 401 header0 := buffer[h] 402 h++ 403 header1 := buffer[h] 404 h++ 405 406 msg.MessageType = uint16(header0 & 0xFFFF) 407 408 msg.NumXDescriptors = (header0 >> 16) & 0xF 409 msg.NumADescriptors = (header0 >> 20) & 0xF 410 msg.NumBDescriptors = (header0 >> 24) & 0xF 411 msg.NumWDescriptors = (header0 >> 28) & 0xF 412 413 msg.RawDataSectionSize = header1 & 0xFFFFF // 0b11 1111 1111 414 415 msg.CDescriptorFlags = (header1 >> 10) & 0xF 416 hasHandleDescriptor := (header1 >> 31) > 0 417 418 msg.NumCopyHandles = 0 419 msg.NumMoveHandles = 0 420 msg.CopyHandles = nil 421 msg.MoveHandles = nil 422 msg.HasPID = false 423 msg.PID = 0 424 425 if hasHandleDescriptor { 426 handleDescriptor := buffer[h] 427 h++ 428 429 if handleDescriptor&1 > 0 { 430 msg.HasPID = true 431 msg.PID = *(*uint64)(unsafe.Pointer(&buffer[h])) 432 h += 2 433 } 434 435 msg.NumCopyHandles = (handleDescriptor >> 1) & 0xF 436 msg.NumMoveHandles = (handleDescriptor >> 5) & 0xF 437 438 if msg.NumCopyHandles > 0 { 439 msg.CopyHandles = buffer[h:] 440 h += int(msg.NumCopyHandles) 441 } 442 443 if msg.NumMoveHandles > 0 { 444 msg.MoveHandles = buffer[h:] 445 h += int(msg.NumMoveHandles) 446 } 447 } 448 449 // Descriptors 450 451 if msg.NumXDescriptors > 0 { 452 msg.XDescriptors = buffer[h:] 453 h += int(msg.NumXDescriptors * 2) 454 } 455 456 if msg.NumADescriptors > 0 { 457 msg.ADescriptors = buffer[h:] 458 h += int(msg.NumADescriptors * 3) 459 } 460 if msg.NumBDescriptors > 0 { 461 msg.BDescriptors = buffer[h:] 462 h += int(msg.NumBDescriptors * 3) 463 } 464 465 if msg.NumWDescriptors > 0 { 466 msg.WDescriptors = buffer[h:] 467 h += int(msg.NumWDescriptors * 3) 468 } 469 470 before := h 471 472 // Align head to 4 words 473 h = int(uint32(h+3) & ^uint32(3)) 474 475 msg.PrePadding = h - before 476 msg.PostPadding = 4 - msg.PrePadding 477 if msg.RawDataSectionSize > 0 { 478 msg.DataSection = buffer[h:] 479 } 480 481 h = before + int(msg.RawDataSectionSize) 482 483 msg.CDescriptors = buffer[h:] 484 485 return nil 486 } 487 488 // UnflattenResponse is equivalent to libtransistor ipc_unflatten_response 489 func UnflattenResponse(msg *Message, rs *ResponseFmt, object Object) error { 490 if debug { 491 println("ipc: unflatten ipc response") 492 } 493 fromDomain := object.ObjectID >= 0 494 495 if msg.MessageType != 0 && msg.MessageType != 4 { 496 return nxerrors.InvalidIPCResponseType 497 } 498 499 h := 0 500 501 if fromDomain { 502 h += 4 // skip domain header 503 } 504 505 if msg.DataSection[h] != sfco { 506 return nxerrors.InvalidIPCResponseMagic 507 } 508 h += 2 509 510 responseCode := msg.DataSection[h] 511 h++ 512 513 if responseCode != nxtypes.ResultOK { 514 return nxerrors.IPCError{ 515 Result: uint64(responseCode), 516 Message: "response error", 517 } 518 } 519 h++ 520 521 rawData := msg.DataSection[h:] 522 523 nObjs := int(0) 524 525 if fromDomain { 526 nObjs = 0x10 + len(rs.Objects)*4 527 } 528 529 // RawDataSectionLength - SFCI, Command ID - Padding - nObjs 530 if (int(msg.RawDataSectionSize*4) - 0x10 - 0x10 - nObjs) != int(ipcPadSize(uint64(len(rs.RawData)))) { 531 if debug { 532 v := ipcPadSize(uint64(len(rs.RawData))) 533 println("expected", int(msg.RawDataSectionSize*4)-0x10-0x10-nObjs, "got", v) 534 println("raw data section size", msg.RawDataSectionSize) 535 } 536 return nxerrors.UnexpectedRawDataSize 537 } 538 539 if msg.HasPID != rs.HasPID { 540 return nxerrors.UnexpectedPID 541 } 542 543 if int(msg.NumCopyHandles) != len(rs.CopyHandles) { 544 return nxerrors.UnexpectedCopyHandles 545 } 546 547 numObjs := 0 548 if !fromDomain { 549 numObjs = len(rs.Objects) 550 } 551 552 if int(msg.NumMoveHandles) != len(rs.MoveHandles)+numObjs { 553 return nxerrors.UnexpectedMoveHandles 554 } 555 556 if fromDomain { 557 type responseDomainHeader struct { 558 numObjects uint32 559 unknown1 [2]uint32 560 unknown2 uint32 561 } 562 ptr := unsafe.Pointer(&msg.DataSection[0]) 563 domainHeader := (*responseDomainHeader)(ptr) 564 565 if int(domainHeader.numObjects) != len(rs.Objects) { 566 return nxerrors.UnexpectedObjects 567 } 568 569 // this is a pointer to a uint32_t array, but it is allowed to be unaligned 570 ptru := uintptr(ptr) 571 ptru += unsafe.Sizeof(responseDomainHeader{}) 572 ptru += 0x10 // SFCO, result code 573 ptru += uintptr(len(rs.RawData)) 574 575 domainIds := ptru 576 577 for i := range rs.Objects { 578 rs.Objects[i].Content = object.Content 579 internal.Memcpy(unsafe.Pointer(&rs.Objects[i].ObjectID), unsafe.Pointer(domainIds+uintptr(i*4)), 4) 580 rs.Objects[i].IsBorrowed = false 581 } 582 } 583 584 for i := range rs.CopyHandles { 585 rs.CopyHandles[i] = nxtypes.Handle(msg.CopyHandles[i]) 586 } 587 588 mhi := 0 // move handle index 589 590 if !fromDomain { 591 for i := range rs.Objects { 592 rs.Objects[i].Content = uint64(msg.MoveHandles[mhi]) 593 rs.Objects[i].ObjectID = -1 594 rs.Objects[i].IsBorrowed = false 595 mhi++ 596 } 597 } 598 599 for i := range rs.MoveHandles { 600 rs.MoveHandles[i] = nxtypes.Handle(msg.MoveHandles[mhi]) 601 mhi++ 602 } 603 604 if rs.HasPID { 605 *rs.PID = msg.PID 606 } 607 608 if len(rs.RawData) > 0 { 609 internal.Memcpy(unsafe.Pointer(&rs.RawData[0]), unsafe.Pointer(&rawData[0]), uintptr(len(rs.RawData))) 610 } 611 612 return nil 613 } 614 615 func Send(object Object, rq *Request, rs *ResponseFmt) error { 616 svc.ClearIPCBuffer() 617 ipcBuff := svc.GetIPCBuffer() 618 619 err := PackIPCRequest(rq, object, ipcBuff) 620 if err != nil { 621 if debug { 622 println("ipc: packing error:", err.Error()) 623 } 624 return err 625 } 626 627 if debug { 628 println("ipc: send sync request") 629 } 630 631 if debugDumpBeforeSend { 632 svc.DumpIPCBuffer() 633 } 634 635 r := svc.SendSyncRequest(object.Content) 636 if r > 0 { 637 if debug { 638 fmt.Printf("ipc: bad request with return code %x\n", r) 639 svc.DumpIPCBuffer() 640 } 641 642 return nxerrors.IPCError{ 643 Result: r, 644 Message: "bad request", 645 } 646 } 647 648 if debug { 649 println("ipc: processing response") 650 } 651 652 msg := Message{} 653 654 err = UnpackIPCMessage(&msg, ipcBuff) 655 656 if err != nil { 657 if debug { 658 println("ipc: unpacking error:", err.Error()) 659 svc.DumpIPCBuffer() 660 } 661 return err 662 } 663 664 err = UnflattenResponse(&msg, rs, object) 665 666 if err != nil { 667 if debug { 668 println("ipc: unflatten error:", err.Error()) 669 } 670 return err 671 } 672 673 return nil 674 } 675 676 func CloseSession(session nxtypes.SessionHandle) error { 677 var err error 678 if session == 0 { 679 return nil 680 } 681 682 rq := MakeDefaultRequest(0) 683 rq.Type = TypeIPCClose 684 685 obj := Object{ 686 ObjectID: -1, 687 } 688 689 obj.SetSession(nxtypes.Handle(session)) 690 691 svc.ClearIPCBuffer() 692 ipcBuff := svc.GetIPCBuffer() 693 694 err = PackIPCRequest(&rq, obj, ipcBuff) 695 if err != nil { 696 return err 697 } 698 699 if debug { 700 println("ipc: send sync request") 701 } 702 703 if debugDumpBeforeSend { 704 svc.DumpIPCBuffer() 705 } 706 707 r := svc.SendSyncRequest(uint64(session)) 708 if r != 0xf601 { 709 if debug { 710 fmt.Printf("ipc: expected session closure, got %x\n", r) 711 } 712 err = nxerrors.IPCError{ 713 Message: nxerrors.ExpectedSessionClosure.String(), 714 Result: r, 715 } 716 } 717 718 if debug { 719 println("ipc: svc close handle") 720 } 721 722 svc.CloseHandle(nxtypes.Handle(session)) 723 724 return err 725 } 726 727 func Close(object *Object) error { 728 if object.IsBorrowed { 729 return nil // we're not allowed to close borrowed objects, 730 // and we would also like to handle this transparently 731 } 732 733 if object.Content == 0 { 734 return nil // Already closed 735 } 736 737 if object.ObjectID < 0 { 738 return CloseSession(object.GetSession()) 739 } 740 741 rq := MakeDefaultRequest(0) 742 rq.CloseObject = true 743 744 svc.ClearIPCBuffer() 745 ipcBuff := svc.GetIPCBuffer() 746 747 err := PackIPCRequest(&rq, *object, ipcBuff) 748 if err != nil { 749 return err 750 } 751 752 if debug { 753 println("ipc: send sync request") 754 } 755 756 if debugDumpBeforeSend { 757 svc.DumpIPCBuffer() 758 } 759 760 d := object.GetDomain() 761 762 if d == nil { 763 return nxerrors.InvalidDomain 764 } 765 766 if d.Session == 0 { 767 return nxerrors.InvalidDomain 768 } 769 770 r := svc.SendSyncRequest(uint64(d.Session)) 771 if r > 0 { 772 if debug { 773 println("ipc: error sending request") 774 svc.DumpIPCBuffer() 775 } 776 return nxerrors.IPCError{ 777 Result: r, 778 Message: "error sending request", 779 } 780 } 781 782 object.Recycle() 783 784 return nil 785 } 786 787 func ConvertToDomain(object *Object) (*Domain, error) { 788 if object == nil { 789 return nil, nxerrors.InvalidHandle 790 } 791 if object.IsBorrowed { 792 return nil, nxerrors.RefusalToConvertBorrowedObject 793 } 794 if object.ObjectID != -1 { 795 return nil, nxerrors.AlreadyADomain 796 } 797 798 session := *object 799 domain := &Domain{ 800 Session: session.GetSession(), 801 } 802 803 object.SetDomain(domain) 804 805 rq := MakeDefaultRequest(0) 806 rq.Type = TypeIPCControl 807 808 rs := ResponseFmt{} 809 rs.RawData = make([]byte, unsafe.Sizeof(object.ObjectID)) 810 811 err := Send(session, &rq, &rs) 812 if err != nil { 813 return nil, err 814 } 815 816 object.ObjectID = int32(binary.LittleEndian.Uint32(rs.RawData)) 817 818 return domain, nil 819 }