1 Reply
      Latest reply on Nov 4, 2016 3:37 AM by eskimo
      ankitthakur_fico Level 1 Level 1 (0 points)

        I am having a struct object. And a method, whose input is payload. Now I am creating a mutableData named packet, and it's mutable bytes are referring to ICMPHeader struct.



        struct ICMPHeader {
            var type:UInt8
            var code:UInt8
            var checksum:UInt16
            var identifier:UInt16
            var sequenceNumber:UInt16


        func createPacket(payload:NSData) -> NSData(){
            var packet:NSMutableData?
            var icmpPtr:ICMPHeader = ICMPHeader(type: 0, code: 0, checksum: 0, identifier: 0, sequenceNumber: 0)
            packet = NSMutableData(length: Int(MemoryLayout<ICMPHeader>.size + payload.length))
            if packet != nil {
               icmpPtr = packet!.mutableBytes.assumingMemoryBound(to: ICMPHeader.self).pointee
               icmpPtr.type = type
               icmpPtr.code = 0
               icmpPtr.checksum = 0
               icmpPtr.identifier = CFSwapInt16BigToHost(identifier)
               icmpPtr.sequenceNumber = CFSwapInt16HostToBig(identifier)
               memcpy(&icmpPtr + 1, payload.bytes, payload.length)
               if (requiresChecksum) {
                   icmpPtr.checksum = in_cksum(packet!.bytes, bufferLen: packet!.length);
           return packet


        Mutable bytes are successfully getting binded to struct, and values are also getting updated in struct ICMPHeader.


        The issue is changing the values in struct is not changing the value of mutable data packet.


        And if, I am trying to recreate the packet after creating struct, then it is crashing.

        package = NSMutableData(bytes: unsafeBitCast(icmpPtr, to: UnsafeMutableRawPointer.self), length: Int(MemoryLayout<ICMPHeader>.size + payload.length))
        • Re: NSMutableData's bytes to UnsafeMutableRawPointer not updating the value of mutableData
          eskimo Apple Staff Apple Staff (13,935 points)

          The immediate cause of your problem is this:

          icmpPtr = packet!.mutableBytes.assumingMemoryBound(to: ICMPHeader.self).pointee

          icmpPtr is not a pointer, its a ICMPHeader value, and, as with all value types, changes to it do not get reflected elsewhere.

          However, there’s a bunch of other things I’d change in your code:

          • From what you posted it seems like you’re defining ICMPHeader in Swift.  That’s not good.  Swift makes no guarantees about how such a structure would be laid out.  You’ll have to define it in C (as shown below) and then import that into Swift.  Note my use of __Check_Compile_Time to check, at compile time, that the compiler has laid out the structure correctly.

          • Swift has had native endian swizzling for a while now.

          • In my experience Foundation value types are much easier to use than NSData.

          Here’s how I’d write this code:

          import Foundation
          func in_cksum(buffer: UnsafeBufferPointer<UInt8>) -> UInt16 {
              return 12345
          func createPacket(payload: Data) -> Data {
              let type: UInt8 = 42
              let identifier: UInt16 = 666
              var result = Data(count: MemoryLayout<ICMPHeader>.size)
              result.withUnsafeMutableBytes { (icmpPtr: UnsafeMutablePointer<ICMPHeader>) in
                icmpPtr.pointee.type = type 
                icmpPtr.pointee.code = 0
                icmpPtr.pointee.checksum = 0 
                icmpPtr.pointee.identifier = identifier.bigEndian
                icmpPtr.pointee.sequenceNumber = identifier.bigEndian 
              let checksum = result.withUnsafeBytes { (base: UnsafePointer<UInt8>) in
                  return in_cksum(buffer: UnsafeBufferPointer(start: base, count: result.count))
              result.withUnsafeMutableBytes { (icmpPtr: UnsafeMutablePointer<ICMPHeader>) in
                  icmpPtr.pointee.checksum = checksum
              return result

          Note I’m not byte swapping checksum because the traditional IP checksum implementation returns the value big endian anyway.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

          @import Darwin;
          #include <AssertMacros.h>
          struct ICMPHeader { 
              uint8_t type; 
              uint8_t code; 
              uint16_t checksum;
              uint16_t identifier;
              uint16_t sequenceNumber;
          typedef struct ICMPHeader ICMPHeader;
          __Check_Compile_Time(sizeof(ICMPHeader) == 8);
          __Check_Compile_Time(offsetof(ICMPHeader, type) == 0);
          __Check_Compile_Time(offsetof(ICMPHeader, code) == 1);
          __Check_Compile_Time(offsetof(ICMPHeader, checksum) == 2);
          __Check_Compile_Time(offsetof(ICMPHeader, identifier) == 4);
          __Check_Compile_Time(offsetof(ICMPHeader, sequenceNumber) == 6);