@@ -26,9 +26,10 @@ import kotlinx.coroutines.CompletableJob
2626import kotlinx.rpc.grpc.GrpcMetadata
2727import kotlinx.rpc.grpc.Status
2828import kotlinx.rpc.grpc.StatusCode
29+ import kotlinx.rpc.grpc.descriptor.MethodDescriptor
2930import kotlinx.rpc.grpc.internal.BatchResult
3031import kotlinx.rpc.grpc.internal.CompletionQueue
31- import kotlinx.rpc.grpc.descriptor.MethodDescriptor
32+ import kotlinx.rpc.grpc.internal.destroyEntries
3233import kotlinx.rpc.grpc.internal.internalError
3334import kotlinx.rpc.grpc.internal.toByteArray
3435import kotlinx.rpc.grpc.internal.toGrpcByteBuffer
@@ -182,7 +183,7 @@ internal class NativeClientCall<Request, Response>(
182183 if (! success) return
183184
184185 // send and receive initial headers to/from the server
185- sendAndReceiveInitialMetadata()
186+ sendAndReceiveInitialMetadata(headers )
186187 }
187188
188189 /* *
@@ -251,13 +252,16 @@ internal class NativeClientCall<Request, Response>(
251252 val statusCode = arena.alloc< grpc_status_code.Var > ()
252253 val statusDetails = arena.alloc< grpc_slice> ()
253254 val errorStr = arena.alloc<CPointerVar <ByteVar >>()
255+
256+ val trailingMetadata = arena.alloc< grpc_metadata_array> ()
257+ grpc_metadata_array_init(trailingMetadata.ptr)
258+
254259 val op = arena.alloc< grpc_op> {
255260 op = GRPC_OP_RECV_STATUS_ON_CLIENT
256261 data.recv_status_on_client.status = statusCode.ptr
257262 data.recv_status_on_client.status_details = statusDetails.ptr
258263 data.recv_status_on_client.error_string = errorStr.ptr
259- // TODO: trailing metadata
260- data.recv_status_on_client.trailing_metadata = null
264+ data.recv_status_on_client.trailing_metadata = trailingMetadata.ptr
261265 }
262266
263267 when (val callResult = cq.runBatch(this @NativeClientCall.raw, op.ptr, 1u )) {
@@ -266,11 +270,13 @@ internal class NativeClientCall<Request, Response>(
266270 val details = statusDetails.toByteArray().toKString()
267271 val kStatusCode = statusCode.value.toKotlin()
268272 val status = Status (kStatusCode, details, null )
269- val trailers = GrpcMetadata ()
273+ val trailers = GrpcMetadata (trailingMetadata )
270274
271275 // cleanup
272276 grpc_slice_unref(statusDetails.readValue())
273277 if (errorStr.value != null ) gpr_free(errorStr.value)
278+ // the entries are owned by the call object, so we must only destroy the array
279+ grpc_metadata_array_destroy(trailingMetadata.readValue())
274280 arena.clear()
275281
276282 // set close info and try to close the call.
@@ -296,29 +302,37 @@ internal class NativeClientCall<Request, Response>(
296302 }
297303 }
298304
299- private fun sendAndReceiveInitialMetadata () {
305+ private fun sendAndReceiveInitialMetadata (headers : GrpcMetadata ) {
300306 // sending and receiving initial metadata
301307 val arena = Arena ()
302308 val opsNum = 2uL
303309 val ops = arena.allocArray< grpc_op> (opsNum.convert())
304310
311+ // turn given headers into a grpc_metadata_array.
312+ val sendInitialMetadata: grpc_metadata_array = with (headers) {
313+ arena.allocRawGrpcMetadata()
314+ }
315+
305316 // send initial meta data to server
306- // TODO: initial metadata
307317 ops[0 ].op = GRPC_OP_SEND_INITIAL_METADATA
308- ops[0 ].data.send_initial_metadata.count = 0u
318+ ops[0 ].data.send_initial_metadata.count = sendInitialMetadata.count
319+ ops[0 ].data.send_initial_metadata.metadata = sendInitialMetadata.metadata
309320
310- val meta = arena.alloc< grpc_metadata_array> ()
311- // TODO: make metadata array an object (for lifecycle management)
312- grpc_metadata_array_init(meta.ptr)
321+ val recvInitialMetadata = arena.alloc< grpc_metadata_array> ()
322+ grpc_metadata_array_init(recvInitialMetadata.ptr)
313323 ops[1 ].op = GRPC_OP_RECV_INITIAL_METADATA
314- ops[1 ].data.recv_initial_metadata.recv_initial_metadata = meta .ptr
324+ ops[1 ].data.recv_initial_metadata.recv_initial_metadata = recvInitialMetadata .ptr
315325
316326 runBatch(ops, opsNum, cleanup = {
317- grpc_metadata_array_destroy(meta.ptr)
327+ // we must not destroy the array itself, as it is cleared when clearing the arena.
328+ sendInitialMetadata.destroyEntries()
329+ // the entries are owned by the call object, so we must only destroy the array
330+ grpc_metadata_array_destroy(recvInitialMetadata.readValue())
318331 arena.clear()
319332 }) {
333+ val headers = GrpcMetadata (recvInitialMetadata)
320334 safeUserCode(" Failed to call onHeaders." ) {
321- listener?.onHeaders(GrpcMetadata () )
335+ listener?.onHeaders(headers )
322336 }
323337 }
324338 }
@@ -447,4 +461,3 @@ internal class NativeClientCall<Request, Response>(
447461 }
448462}
449463
450-
0 commit comments