44#[ cfg( target_os = "linux" ) ]
55use datadog_library_config:: tracer_metadata:: AnonymousFileHandle ;
66use 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} ;
910
1011/// C-compatible representation of an anonymous file handle
1112#[ repr( C ) ]
@@ -14,53 +15,118 @@ pub struct TracerMemfdHandle {
1415 pub fd : c_int ,
1516}
1617
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.
1832///
1933/// # 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.
20112///
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.
22116#[ 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 ,
32119) -> 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+ }
60126
61- // Call the actual implementation
127+ let metadata = & mut * ptr ;
62128 let result: anyhow:: Result < TracerMemfdHandle > =
63- match tracer_metadata:: store_tracer_metadata ( & metadata) {
129+ match tracer_metadata:: store_tracer_metadata ( metadata) {
64130 #[ cfg( target_os = "linux" ) ]
65131 Ok ( handle) => {
66132 use std:: os:: fd:: { IntoRawFd , OwnedFd } ;
0 commit comments