func GetPriv(ctx uintptr, privatedata interface{}) int { /* Retrieve the private data stored by the milter Retrieving the data will release the memory allocated for it Don't try to retrieve it again unless you call SetPriv first */ // Call libmilter smfi_getpriv to get a pointer to our data CArray := (*byte)(C.smfi_getpriv(int2ctx(ctx))) // Make sure data has been set with a previous call to SetPriv if CArray == nil { return -1 } // Read uint32 size bytes from the start of the pointer var length uint32 lengthsize := unsafe.Sizeof(length) lengthbytes := make([]byte, lengthsize) lenStart := uintptr(unsafe.Pointer(CArray)) seqStart := lenStart + uintptr(lengthsize) for i := uintptr(0); i < uintptr(lengthsize); i++ { CArray = (*byte)(unsafe.Pointer(lenStart + i)) lengthbytes[i] = *CArray } // Binary decode the length bytes buf := bytes.NewBuffer(lengthbytes) err := binary.Read(buf, binary.BigEndian, &length) if err != nil { return -1 } // Read byte sequence of data databytes := make([]byte, length) for i := uintptr(0); i < uintptr(length); i++ { CArray = (*byte)(unsafe.Pointer(seqStart + i)) databytes[i] = *CArray } // Free the data malloc'ed by C C.free(unsafe.Pointer(lenStart)) C.smfi_setpriv(int2ctx(ctx), nil) // Unserialize the data bytes back into a data structure err = GobDecode(databytes, privatedata) if err != nil { return -1 } return 0 }
// See also: http://bit.ly/1HVWA9I func SetPriv(ctx uintptr, privatedata interface{}) int { // privatedata seems to work for any data type // Structs must have exported fields // Serialize Go privatedata into a byte slice bytedata, _ := GobEncode(privatedata) // length and size // length is a uint32 (usually 4 bytes) // the length will be stored in front of the byte sequence length := uint32(len(bytedata)) lengthsize := C.size_t(unsafe.Sizeof(length)) buf := new(bytes.Buffer) err := binary.Write(buf, binary.BigEndian, length) if err != nil { return -1 } lengthbytes := buf.Bytes() // Allocate memory for the length and byte sequence CArray := (*C.uchar)(C.malloc(lengthsize + C.size_t(length))) var lenStart, seqStart uintptr lenStart = uintptr(unsafe.Pointer(CArray)) seqStart = lenStart + uintptr(lengthsize) CArray = (*C.uchar)(unsafe.Pointer(lenStart)) for i := uintptr(0); i < uintptr(lengthsize); i++ { CArray = (*C.uchar)(unsafe.Pointer(lenStart + i)) *CArray = C.uchar(lengthbytes[i]) } // Now copy the data bytes to the position after the length for i := uintptr(0); i < uintptr(length); i++ { CArray = (*C.uchar)(unsafe.Pointer(seqStart + i)) *CArray = C.uchar(bytedata[i]) } // Call libmilter smfi_setpriv type CtxPtr *C.struct_smfi_str return int(C.smfi_setpriv(int2ctx(ctx), unsafe.Pointer(lenStart))) }