4
4
#[ cfg( target_os = "linux" ) ]
5
5
use datadog_library_config:: tracer_metadata:: AnonymousFileHandle ;
6
6
use datadog_library_config:: tracer_metadata:: { self , TracerMetadata } ;
7
- use ddcommon_ffi:: { CharSlice , Result } ;
8
- use std:: os:: raw:: c_int;
7
+ use ddcommon_ffi:: Result ;
8
+ use std:: ffi:: CStr ;
9
+ use std:: os:: raw:: { c_char, c_int} ;
9
10
10
11
/// C-compatible representation of an anonymous file handle
11
12
#[ repr( C ) ]
@@ -14,53 +15,118 @@ pub struct TracerMemfdHandle {
14
15
pub fd : c_int ,
15
16
}
16
17
17
- /// Store tracer metadata to a file handle
18
+ /// Represents the types of metadata that can be set on a `TracerMetadata` object.
19
+ #[ repr( C ) ]
20
+ pub enum MetadataKind {
21
+ RuntimeId = 0 ,
22
+ TracerLanguage = 1 ,
23
+ TracerVersion = 2 ,
24
+ Hostname = 3 ,
25
+ ServiceName = 4 ,
26
+ ServiceVersion = 5 ,
27
+ ProcessTags = 6 ,
28
+ ContainerId = 7 ,
29
+ }
30
+
31
+ /// Allocates and returns a pointer to a new `TracerMetadata` object on the heap.
18
32
///
19
33
/// # Safety
34
+ /// This function returns a raw pointer. The caller is responsible for calling
35
+ /// `ddog_tracer_metadata_free` to deallocate the memory.
36
+ ///
37
+ /// # Returns
38
+ /// A non-null pointer to a newly allocated `TracerMetadata` instance.
39
+ #[ no_mangle]
40
+ pub unsafe extern "C" fn ddog_tracer_metadata_new ( ) -> * mut TracerMetadata {
41
+ Box :: into_raw ( Box :: new ( TracerMetadata :: default ( ) ) )
42
+ }
43
+
44
+ /// Frees a `TracerMetadata` instance previously allocated with `ddog_tracer_metadata_new`.
45
+ ///
46
+ /// # Safety
47
+ /// - `ptr` must be a pointer previously returned by `ddog_tracer_metadata_new`.
48
+ /// - Double-freeing or passing an invalid pointer results in undefined behavior.
49
+ /// - Passing a null pointer is safe and does nothing.
50
+ #[ no_mangle]
51
+ pub unsafe extern "C" fn ddog_tracer_metadata_free ( ptr : * mut TracerMetadata ) {
52
+ if ptr. is_null ( ) {
53
+ return ;
54
+ }
55
+ unsafe {
56
+ drop ( Box :: from_raw ( ptr) ) ;
57
+ }
58
+ }
59
+
60
+ /// Sets a field of the `TracerMetadata` object pointed to by `ptr`.
61
+ ///
62
+ /// # Arguments
63
+ /// - `ptr`: Pointer to a `TracerMetadata` instance.
64
+ /// - `kind`: The metadata field to set (as defined in `MetadataKind`).
65
+ /// - `value`: A null-terminated C string representing the value to set.
66
+ ///
67
+ /// # Safety
68
+ /// - Both `ptr` and `value` must be non-null.
69
+ /// - `value` must point to a valid UTF-8 null-terminated string.
70
+ /// - If the string is not valid UTF-8, the function does nothing.
71
+ #[ no_mangle]
72
+ pub unsafe extern "C" fn ddog_tracer_metadata_set (
73
+ ptr : * mut TracerMetadata ,
74
+ kind : MetadataKind ,
75
+ value : * const c_char ,
76
+ ) {
77
+ if ptr. is_null ( ) || value. is_null ( ) {
78
+ return ;
79
+ }
80
+
81
+ unsafe {
82
+ let c_str = CStr :: from_ptr ( value) ;
83
+ let str_value = match c_str. to_str ( ) {
84
+ Ok ( v) => v. to_string ( ) ,
85
+ Err ( _) => return ,
86
+ } ;
87
+
88
+ let metadata = & mut * ptr;
89
+
90
+ match kind {
91
+ MetadataKind :: RuntimeId => metadata. runtime_id = Some ( str_value) ,
92
+ MetadataKind :: TracerLanguage => metadata. tracer_language = str_value,
93
+ MetadataKind :: TracerVersion => metadata. tracer_version = str_value,
94
+ MetadataKind :: Hostname => metadata. hostname = str_value,
95
+ MetadataKind :: ServiceName => metadata. service_name = Some ( str_value) ,
96
+ MetadataKind :: ServiceVersion => metadata. service_version = Some ( str_value) ,
97
+ MetadataKind :: ProcessTags => metadata. process_tags = Some ( str_value) ,
98
+ MetadataKind :: ContainerId => metadata. container_id = Some ( str_value) ,
99
+ }
100
+ }
101
+ }
102
+
103
+ /// Serializes the `TracerMetadata` into a platform-specific memory handle (e.g., memfd on Linux).
104
+ ///
105
+ /// # Safety
106
+ /// - `ptr` must be a valid, non-null pointer to a `TracerMetadata`.
107
+ ///
108
+ /// # Returns
109
+ /// - On Linux: a `TracerMemfdHandle` containing a raw file descriptor to a memory file.
110
+ /// - On unsupported platforms: an error.
111
+ /// - On failure: propagates any internal errors from the metadata storage process.
20
112
///
21
- /// Accepts raw C-compatible strings
113
+ /// # Platform Support
114
+ /// This function currently only supports Linux via `memfd`. On other platforms,
115
+ /// it will return an error.
22
116
#[ no_mangle]
23
- pub unsafe extern "C" fn ddog_store_tracer_metadata (
24
- schema_version : u8 ,
25
- runtime_id : CharSlice ,
26
- tracer_language : CharSlice ,
27
- tracer_version : CharSlice ,
28
- hostname : CharSlice ,
29
- service_name : CharSlice ,
30
- service_env : CharSlice ,
31
- service_version : CharSlice ,
117
+ pub unsafe extern "C" fn ddog_tracer_metadata_store (
118
+ ptr : * mut TracerMetadata ,
32
119
) -> Result < TracerMemfdHandle > {
33
- // Convert C strings to Rust types
34
- let metadata = TracerMetadata {
35
- schema_version,
36
- runtime_id : if runtime_id. is_empty ( ) {
37
- None
38
- } else {
39
- Some ( runtime_id. to_string ( ) )
40
- } ,
41
- tracer_language : tracer_language. to_string ( ) ,
42
- tracer_version : tracer_version. to_string ( ) ,
43
- hostname : hostname. to_string ( ) ,
44
- service_name : if service_name. is_empty ( ) {
45
- None
46
- } else {
47
- Some ( service_name. to_string ( ) )
48
- } ,
49
- service_env : if service_env. is_empty ( ) {
50
- None
51
- } else {
52
- Some ( service_env. to_string ( ) )
53
- } ,
54
- service_version : if service_version. is_empty ( ) {
55
- None
56
- } else {
57
- Some ( service_version. to_string ( ) )
58
- } ,
59
- } ;
120
+ if ptr. is_null ( ) {
121
+ return Err :: < TracerMemfdHandle , _ > ( anyhow:: anyhow!(
122
+ "Failed to store tracer metadata: received a null pointer"
123
+ ) )
124
+ . into ( ) ;
125
+ }
60
126
61
- // Call the actual implementation
127
+ let metadata = & mut * ptr ;
62
128
let result: anyhow:: Result < TracerMemfdHandle > =
63
- match tracer_metadata:: store_tracer_metadata ( & metadata) {
129
+ match tracer_metadata:: store_tracer_metadata ( metadata) {
64
130
#[ cfg( target_os = "linux" ) ]
65
131
Ok ( handle) => {
66
132
use std:: os:: fd:: { IntoRawFd , OwnedFd } ;
0 commit comments