Skip to main content

netget/server/gnmi/
runtime.rs

1//! Every HTTP/2 child and subscription future belongs to its TCP connection.
2use super::{
3    actions, codec,
4    proto::gnmi as pb,
5    semantic::{self, Answer, Mode},
6    value,
7};
8use crate::{
9    protocol::{Event, SpawnContext},
10    server::{
11        accept_bounded::{self, ConnectionActivity},
12        connection::ConnectionId,
13        grpc::streaming::{ConnectionTasks, OwnedExecutor},
14    },
15    state::ServerId,
16};
17use bytes::Bytes;
18use futures::Stream;
19use http_body_util::{BodyExt, Full};
20use hyper::{body::Incoming, Request};
21use serde_json::{json, Value};
22use std::{
23    collections::VecDeque,
24    convert::Infallible,
25    pin::Pin,
26    sync::{
27        atomic::{AtomicU32, Ordering},
28        Arc,
29    },
30    time::Duration,
31};
32use tokio::sync::Semaphore;
33use tonic::{codec::CompressionEncoding, Status};
34use tower::Service;
35pub const FIRST_BYTE_READ_TIMEOUT: Duration = Duration::from_secs(30);
36pub const IDLE_BETWEEN_REQUESTS_TIMEOUT: Duration = Duration::from_secs(120);
37pub const MAX_CONNECTIONS: usize = 256;
38pub const MAX_ACTIVE_RPCS: usize = 64;
39const MAX_MESSAGES: usize = 256;
40const MAX_HANDLERS: usize = 258;
41const REFUSAL:&[u8]=b"HTTP/1.1 503 Service Unavailable\r\nContent-Length: 0\r\nRetry-After: 5\r\nConnection: close\r\n\r\n";
42#[derive(Clone)]
43struct Context {
44    llm: crate::llm::OllamaClient,
45    state: Arc<crate::state::AppState>,
46    server: ServerId,
47    connection: ConnectionId,
48    protocol: Arc<actions::GnmiProtocol>,
49    id: u32,
50    deadline: tokio::time::Instant,
51}
52impl Context {
53    async fn decide(
54        &self,
55        event_type: &'static crate::protocol::EventType,
56        request: Value,
57    ) -> Result<Vec<Answer>, Status> {
58        let event = Event::new(event_type, json!({"rpc_id":self.id,"request":request}));
59        let result = crate::llm::action_helper::call_llm(
60            &self.llm,
61            &self.state,
62            self.server,
63            Some(self.connection),
64            &event,
65            self.protocol.as_ref(),
66        )
67        .await
68        .map_err(|error| {
69            if crate::llm::is_overload_error(&error) {
70                Status::unavailable("netget: backend at capacity")
71            } else {
72                Status::internal("netget: handler unavailable")
73            }
74        })?;
75        if result.has_failures() {
76            return Err(Status::internal("netget: invalid handler response"));
77        }
78        let answers = result
79            .protocol_results
80            .iter()
81            .filter_map(|result| {
82                if let crate::llm::ActionResult::Custom { name, data } = result {
83                    if name == "gnmi_answer" {
84                        return Some(data);
85                    }
86                }
87                None
88            })
89            .collect::<Vec<_>>();
90        if answers.is_empty() || answers.len() > 16 {
91            return Err(Status::internal("netget: no bounded gNMI answer"));
92        }
93        answers.into_iter().map(semantic::answer).collect()
94    }
95    async fn unary(
96        &self,
97        event: &'static crate::protocol::EventType,
98        request: Value,
99    ) -> Result<Answer, Status> {
100        let mut answers = self.decide(event, request).await?;
101        if answers.len() != 1 {
102            return Err(Status::internal("netget: unary RPC requires one answer"));
103        }
104        let answer = answers.remove(0);
105        if let Answer::Error(error) = answer {
106            Err(error)
107        } else {
108            Ok(answer)
109        }
110    }
111}
112#[derive(Clone)]
113struct Receiver(Context);
114#[tonic::async_trait]
115impl pb::g_nmi_server::GNmi for Receiver {
116    async fn capabilities(
117        &self,
118        request: tonic::Request<pb::CapabilityRequest>,
119    ) -> Result<tonic::Response<pb::CapabilityResponse>, Status> {
120        if !request.get_ref().extension.is_empty() {
121            return Err(Status::unimplemented("extensions excluded"));
122        }
123        match self.0.unary(&actions::CAPABILITIES, json!({})).await? {
124            Answer::Capabilities(v) => Ok(tonic::Response::new(v)),
125            _ => Err(Status::internal("netget: wrong Capabilities answer")),
126        }
127    }
128    async fn get(
129        &self,
130        request: tonic::Request<pb::GetRequest>,
131    ) -> Result<tonic::Response<pb::GetResponse>, Status> {
132        let request = request.into_inner();
133        let event = semantic::get_request(&request)?;
134        match self.0.unary(&actions::GET, event).await? {
135            Answer::Get(notification) => {
136                for n in &notification {
137                    value::notification_encoding(n, request.encoding)?;
138                }
139                Ok(tonic::Response::new(value::checked(pb::GetResponse {
140                    notification,
141                    error: None,
142                    extension: vec![],
143                })?))
144            }
145            _ => Err(Status::internal("netget: wrong Get answer")),
146        }
147    }
148    async fn set(
149        &self,
150        request: tonic::Request<pb::SetRequest>,
151    ) -> Result<tonic::Response<pb::SetResponse>, Status> {
152        let request = request.into_inner();
153        let event = semantic::set_request(&request)?;
154        match self.0.unary(&actions::SET, event).await? {
155            Answer::Set(timestamp) => Ok(tonic::Response::new(semantic::set_response(
156                &request, &timestamp,
157            )?)),
158            _ => Err(Status::internal("netget: wrong Set answer")),
159        }
160    }
161    type SubscribeStream =
162        Pin<Box<dyn Stream<Item = Result<pb::SubscribeResponse, Status>> + Send>>;
163    async fn subscribe(
164        &self,
165        request: tonic::Request<tonic::Streaming<pb::SubscribeRequest>>,
166    ) -> Result<tonic::Response<Self::SubscribeStream>, Status> {
167        let mut input = request.into_inner();
168        let first = input
169            .message()
170            .await?
171            .ok_or_else(|| Status::invalid_argument("missing SubscriptionList"))?;
172        if !first.extension.is_empty() {
173            return Err(Status::unimplemented("extensions excluded"));
174        }
175        let Some(pb::subscribe_request::Request::Subscribe(list)) = first.request else {
176            return Err(Status::invalid_argument(
177                "first request must contain SubscriptionList",
178            ));
179        };
180        let subscription = semantic::subscription(&list)?;
181        let state = Subscription {
182            ctx: self.0.clone(),
183            subscription,
184            input,
185            pending: VecDeque::new(),
186            input_closed: false,
187            cycle: true,
188            initial: true,
189            synced: false,
190            finished: false,
191            wait: None,
192            messages: 0,
193            inputs: 1,
194            handlers: 0,
195        };
196        let stream = futures::stream::try_unfold(state, |mut state| async move {
197            let next = tokio::time::timeout_at(state.ctx.deadline, state.next())
198                .await
199                .map_err(|_| Status::deadline_exceeded("netget: subscription deadline"))??;
200            Ok(next.map(|next| (next, state)))
201        });
202        Ok(tonic::Response::new(Box::pin(stream)))
203    }
204}
205struct Subscription {
206    ctx: Context,
207    subscription: semantic::Subscription,
208    input: tonic::Streaming<pb::SubscribeRequest>,
209    pending: VecDeque<pb::SubscribeResponse>,
210    input_closed: bool,
211    cycle: bool,
212    initial: bool,
213    synced: bool,
214    finished: bool,
215    wait: Option<Duration>,
216    messages: usize,
217    inputs: usize,
218    handlers: usize,
219}
220impl Subscription {
221    fn input(
222        &mut self,
223        request: Option<pb::SubscribeRequest>,
224        allow_poll: bool,
225    ) -> Result<(), Status> {
226        let Some(request) = request else {
227            self.input_closed = true;
228            return Ok(());
229        };
230        self.inputs += 1;
231        if self.inputs > MAX_MESSAGES {
232            return Err(Status::resource_exhausted(
233                "subscription input count exceeds 256",
234            ));
235        }
236        if !request.extension.is_empty() {
237            return Err(Status::unimplemented("extensions excluded"));
238        }
239        if !allow_poll
240            || self.subscription.mode != Mode::Poll
241            || !matches!(
242                request.request,
243                Some(pb::subscribe_request::Request::Poll(_))
244            )
245        {
246            return Err(Status::invalid_argument(
247                "only POLL mode accepts Poll after its completed snapshot",
248            ));
249        }
250        self.cycle = true;
251        self.synced = false;
252        Ok(())
253    }
254    fn push(&mut self, response: pb::SubscribeResponse) -> Result<(), Status> {
255        self.messages += 1;
256        if self.messages > MAX_MESSAGES {
257            return Err(Status::resource_exhausted(
258                "subscription output count exceeds 256",
259            ));
260        }
261        if self.pending.len() >= 16 {
262            return Err(Status::resource_exhausted(
263                "subscription pending count exceeds 16",
264            ));
265        }
266        use prost::Message;
267        let bytes = self.pending.iter().map(Message::encoded_len).sum::<usize>();
268        if bytes.saturating_add(response.encoded_len()) > codec::MAX_MESSAGE_BYTES {
269            return Err(Status::resource_exhausted(
270                "pending subscription output exceeds 1 MiB",
271            ));
272        }
273        self.pending.push_back(value::checked(response)?);
274        Ok(())
275    }
276    fn sync(&mut self) -> Result<(), Status> {
277        if !self.cycle || self.synced {
278            return Err(Status::failed_precondition(
279                "sync belongs once to each initial/POLL snapshot",
280            ));
281        }
282        self.push(pb::SubscribeResponse {
283            response: Some(pb::subscribe_response::Response::SyncResponse(true)),
284            extension: vec![],
285        })?;
286        self.synced = true;
287        self.cycle = false;
288        match self.subscription.mode {
289            Mode::Once => self.finished = true,
290            Mode::Stream => self.wait = Some(Duration::from_millis(1000)),
291            Mode::Poll => {}
292        }
293        Ok(())
294    }
295    async fn decision(&mut self) -> Result<Vec<Answer>, Status> {
296        self.handlers += 1;
297        if self.handlers > MAX_HANDLERS {
298            return Err(Status::resource_exhausted(
299                "subscription handler count exceeds 258",
300            ));
301        }
302        let kind = if self.initial {
303            &*actions::SUBSCRIBE
304        } else if self.cycle {
305            &*actions::POLL
306        } else {
307            &*actions::TICK
308        };
309        let context = self.ctx.clone();
310        let future = context.decide(kind, self.subscription.event.clone());
311        tokio::pin!(future);
312        loop {
313            tokio::select! {
314                answer=&mut future=>return answer,
315                request=self.input.message(),if !self.input_closed=>{self.input(request?,false)?;}
316            }
317        }
318    }
319    fn apply(&mut self, answers: Vec<Answer>) -> Result<(), Status> {
320        let started_cycle = self.cycle;
321        let mut terminal = false;
322        for answer in answers {
323            if terminal {
324                return Err(Status::internal(
325                    "netget: action after terminal subscription control",
326                ));
327            }
328            match answer {
329                Answer::Update(notifications) => {
330                    if self.synced && started_cycle {
331                        return Err(Status::failed_precondition("snapshot update after sync"));
332                    }
333                    if self.subscription.updates_only && started_cycle {
334                        return Err(Status::failed_precondition(
335                            "updates_only snapshot cannot contain updates",
336                        ));
337                    }
338                    for notification in notifications {
339                        value::notification_encoding(&notification, self.subscription.encoding)?;
340                        self.push(pb::SubscribeResponse {
341                            response: Some(pb::subscribe_response::Response::Update(notification)),
342                            extension: vec![],
343                        })?;
344                    }
345                }
346                Answer::Sync => {
347                    self.sync()?;
348                    if self.subscription.mode != Mode::Stream {
349                        terminal = true;
350                    }
351                }
352                Answer::Wait(ms) => {
353                    if self.subscription.mode != Mode::Stream || !self.synced {
354                        return Err(Status::failed_precondition(
355                            "wait requires STREAM initial sync",
356                        ));
357                    }
358                    self.wait = Some(Duration::from_millis(ms));
359                    terminal = true;
360                }
361                Answer::Finish => {
362                    if self.subscription.mode != Mode::Stream || !self.synced {
363                        return Err(Status::failed_precondition(
364                            "finish requires STREAM initial sync",
365                        ));
366                    }
367                    self.finished = true;
368                    terminal = true;
369                }
370                Answer::Error(error) => return Err(error),
371                _ => return Err(Status::internal("netget: wrong subscription answer")),
372            }
373        }
374        if started_cycle && !self.synced {
375            return Err(Status::internal(
376                "netget: snapshot answer requires gnmi_sync",
377            ));
378        }
379        if !started_cycle && !terminal {
380            return Err(Status::internal(
381                "netget: stream answer requires wait or finish",
382            ));
383        }
384        self.initial = false;
385        Ok(())
386    }
387    async fn next(&mut self) -> Result<Option<pb::SubscribeResponse>, Status> {
388        loop {
389            if let Some(next) = self.pending.pop_front() {
390                return Ok(Some(next));
391            }
392            if self.finished {
393                return Ok(None);
394            }
395            if self.cycle {
396                if self.subscription.updates_only {
397                    self.sync()?;
398                    self.initial = false;
399                    continue;
400                }
401                let answer = self.decision().await?;
402                self.apply(answer)?;
403                continue;
404            }
405            if self.subscription.mode == Mode::Poll {
406                if self.input_closed {
407                    return Ok(None);
408                }
409                let request = self.input.message().await?;
410                self.input(request, true)?;
411                continue;
412            }
413            let wait = self
414                .wait
415                .take()
416                .ok_or_else(|| Status::internal("netget: missing stream wait"))?;
417            let sleep = tokio::time::sleep(wait);
418            tokio::pin!(sleep);
419            loop {
420                tokio::select! {
421                    _=&mut sleep=>break,
422                    request=self.input.message(),if !self.input_closed=>{self.input(request?,false)?;}
423                }
424            }
425            let answer = self.decision().await?;
426            self.apply(answer)?;
427        }
428    }
429}
430struct GuardedBody<G> {
431    body: tonic::body::BoxBody,
432    guard: Option<G>,
433}
434impl<G: Send + Unpin + 'static> hyper::body::Body for GuardedBody<G> {
435    type Data = Bytes;
436    type Error = Status;
437    fn poll_frame(
438        mut self: Pin<&mut Self>,
439        cx: &mut std::task::Context<'_>,
440    ) -> std::task::Poll<Option<Result<hyper::body::Frame<Bytes>, Status>>> {
441        let result = Pin::new(&mut self.body).poll_frame(cx);
442        if matches!(result, std::task::Poll::Ready(None | Some(Err(_)))) {
443            self.guard = None;
444        }
445        result
446    }
447    // Native tonic's trailers-only status must retain END_STREAM on its initial
448    // HEADERS. Hyper then drops the body/guard; no fabricated DATA frame is needed.
449    fn is_end_stream(&self) -> bool {
450        self.body.is_end_stream()
451    }
452    fn size_hint(&self) -> hyper::body::SizeHint {
453        self.body.size_hint()
454    }
455}
456fn hold_body<G: Send + Unpin + 'static>(
457    body: tonic::body::BoxBody,
458    guard: G,
459) -> tonic::body::BoxBody {
460    GuardedBody {
461        body,
462        guard: Some(guard),
463    }
464    .boxed_unsync()
465}
466async fn unary(request: Request<Incoming>) -> Result<Request<tonic::body::BoxBody>, Status> {
467    let (parts, mut body) = request.into_parts();
468    let mut bytes = Vec::new();
469    let mut length = None;
470    while let Some(frame) = body.frame().await {
471        let frame = frame.map_err(|_| Status::invalid_argument("unreadable gNMI body"))?;
472        if let Ok(data) = frame.into_data() {
473            if bytes.len().saturating_add(data.len()) > codec::MAX_MESSAGE_BYTES + 5 {
474                return Err(Status::resource_exhausted(
475                    "gNMI unary body exceeds message bound",
476                ));
477            }
478            bytes.extend_from_slice(&data);
479            if length.is_none() && bytes.len() >= 5 {
480                let size = u32::from_be_bytes(
481                    bytes[1..5]
482                        .try_into()
483                        .map_err(|_| Status::invalid_argument("frame prefix"))?,
484                ) as usize;
485                if size > codec::MAX_MESSAGE_BYTES {
486                    return Err(Status::resource_exhausted("gNMI message exceeds 1 MiB"));
487                }
488                length = Some(size + 5);
489            }
490            if length.is_some_and(|n| bytes.len() > n) {
491                return Err(Status::invalid_argument(
492                    "unary gNMI requires exactly one message",
493                ));
494            }
495        }
496    }
497    if length != Some(bytes.len()) {
498        return Err(Status::invalid_argument("incomplete gNMI message"));
499    }
500    Ok(Request::from_parts(
501        parts,
502        Full::new(Bytes::from(bytes))
503            .map_err(|never| match never {})
504            .boxed_unsync(),
505    ))
506}
507fn headers(request: &Request<Incoming>) -> Result<(), Status> {
508    let headers = request.headers();
509    if headers.len() > 64
510        || headers
511            .iter()
512            .map(|(n, v)| n.as_str().len() + v.as_bytes().len() + 4)
513            .sum::<usize>()
514            > 32768
515    {
516        return Err(Status::resource_exhausted("HTTP header bound"));
517    }
518    if request.method() != hyper::Method::POST
519        || request.version() != hyper::Version::HTTP_2
520        || request.uri().query().is_some()
521    {
522        return Err(Status::invalid_argument(
523            "gNMI requires POST over HTTP/2 without a query",
524        ));
525    }
526    let mut content = headers.get_all("content-type").iter();
527    let value = content
528        .next()
529        .and_then(|v| v.to_str().ok())
530        .unwrap_or("")
531        .split(';')
532        .next()
533        .unwrap_or("")
534        .trim();
535    if content.next().is_some() || !matches!(value, "application/grpc" | "application/grpc+proto") {
536        return Err(Status::invalid_argument(
537            "gNMI requires unique application/grpc content type",
538        ));
539    }
540    for name in ["grpc-encoding", "grpc-accept-encoding"] {
541        if headers.get_all(name).iter().count() > 1 {
542            return Err(Status::invalid_argument("duplicate gRPC encoding header"));
543        }
544    }
545    Ok(())
546}
547async fn serve<T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static>(
548    io: T,
549    ctx: Context,
550    rpcs: Arc<Semaphore>,
551    timeout: Duration,
552    next: Arc<AtomicU32>,
553) {
554    let executor = OwnedExecutor::default();
555    let _children = ConnectionTasks(executor.clone());
556    let activity = Arc::new(ConnectionActivity::new());
557    let service_activity = activity.clone();
558    let service_executor = executor.clone();
559    let service = hyper::service::service_fn(move |request: Request<Incoming>| {
560        let ctx = ctx.clone();
561        let rpcs = rpcs.clone();
562        let activity = service_activity.clone();
563        let executor = service_executor.clone();
564        let next = next.clone();
565        async move {
566            let prepare = (|| -> Result<_, Status> {
567                headers(&request)?;
568                if !matches!(
569                    request.uri().path(),
570                    "/gnmi.gNMI/Capabilities"
571                        | "/gnmi.gNMI/Get"
572                        | "/gnmi.gNMI/Set"
573                        | "/gnmi.gNMI/Subscribe"
574                ) {
575                    return Err(Status::unimplemented("unknown gNMI method"));
576                }
577                let timeout = crate::server::grpc::streaming::timeout(request.headers(), timeout)?;
578                let deadline = tokio::time::Instant::now() + timeout;
579                let permit = rpcs
580                    .try_acquire_owned()
581                    .map_err(|_| Status::unavailable("netget: receiver at RPC capacity"))?;
582                let timer = executor.deadline(deadline)?;
583                let busy = activity.busy();
584                let id = next
585                    .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |id| id.checked_add(1))
586                    .map_err(|_| Status::resource_exhausted("gNMI RPC identifiers exhausted"))?;
587                Ok((deadline, (permit, timer, busy), id))
588            })();
589            let (deadline, guard, id) = match prepare {
590                Ok(v) => v,
591                Err(status) => return Ok::<_, Infallible>(status.into_http()),
592            };
593            let mut ctx = ctx;
594            ctx.deadline = deadline;
595            ctx.id = id;
596            let call = async move {
597                let stream = request.uri().path() == "/gnmi.gNMI/Subscribe";
598                let request = if stream {
599                    request.map(|body| {
600                        body.map_err(|_| Status::invalid_argument("unreadable gNMI body"))
601                            .boxed_unsync()
602                    })
603                } else {
604                    unary(request).await?
605                };
606                let mut receiver = pb::g_nmi_server::GNmiServer::new(Receiver(ctx))
607                    .accept_compressed(CompressionEncoding::Gzip)
608                    .send_compressed(CompressionEncoding::Gzip)
609                    .max_decoding_message_size(codec::MAX_MESSAGE_BYTES)
610                    .max_encoding_message_size(codec::MAX_MESSAGE_BYTES);
611                match receiver.call(request).await {
612                    Ok(response) => Ok::<_, Status>(response),
613                    Err(never) => match never {},
614                }
615            };
616            let response = match tokio::time::timeout_at(deadline, call).await {
617                Ok(Ok(v)) => v,
618                Ok(Err(error)) => error.into_http(),
619                Err(_) => Status::deadline_exceeded("netget: gNMI RPC deadline").into_http(),
620            };
621            Ok(response.map(|body| hold_body(body, guard)))
622        }
623    });
624    let connection = hyper::server::conn::http2::Builder::new(executor)
625        .max_concurrent_streams(16)
626        .initial_stream_window_size(65536)
627        .initial_connection_window_size(1048576)
628        .max_header_list_size(32768)
629        .max_frame_size(16384)
630        .serve_connection(hyper_util::rt::TokioIo::new(io), service);
631    tokio::pin!(connection);
632    tokio::select! {_=&mut connection=>{},_=accept_bounded::watch_idle(activity,IDLE_BETWEEN_REQUESTS_TIMEOUT)=>{}}
633}
634pub async fn spawn(ctx: SpawnContext) -> anyhow::Result<std::net::SocketAddr> {
635    let params = ctx.startup_params.as_ref();
636    let tls = params
637        .map(|p| p.get_optional_bool("use_tls"))
638        .transpose()?
639        .flatten()
640        .unwrap_or(super::DEFAULT_TLS);
641    let cert = params
642        .map(|p| p.get_optional_string("cert_file"))
643        .transpose()?
644        .flatten();
645    let key = params
646        .map(|p| p.get_optional_string("key_file"))
647        .transpose()?
648        .flatten();
649    let timeout = params
650        .map(|p| p.get_optional_u64("rpc_timeout_secs"))
651        .transpose()?
652        .flatten()
653        .unwrap_or(super::DEFAULT_RPC_TIMEOUT_SECS);
654    anyhow::ensure!(
655        (1..=3600).contains(&timeout),
656        "rpc_timeout_secs must be 1..3600"
657    );
658    anyhow::ensure!(
659        tls || (cert.is_none() && key.is_none()),
660        "cert_file/key_file require use_tls"
661    );
662    let acceptor = if tls {
663        Some(tokio_rustls::TlsAcceptor::from(
664            super::tls::server(
665                cert.ok_or_else(|| anyhow::anyhow!("cert_file required"))?,
666                key.ok_or_else(|| anyhow::anyhow!("key_file required"))?,
667            )
668            .await?,
669        ))
670    } else {
671        None
672    };
673    let listen = ctx
674        .socket_addr()
675        .ok_or_else(|| anyhow::anyhow!("gNMI requires a literal IP host and port"))?;
676    let listener = crate::server::socket_helpers::create_reusable_tcp_listener(listen).await?;
677    let address = listener.local_addr()?;
678    let owner = ctx.state.clone();
679    let server = ctx.server_id;
680    let limiter = accept_bounded::ConnectionLimiter::new(MAX_CONNECTIONS);
681    let rpcs = Arc::new(Semaphore::new(MAX_ACTIVE_RPCS));
682    let next = Arc::new(AtomicU32::new(1));
683    let task = tokio::spawn(async move {
684        loop {
685            let Ok((socket, remote, permit)) = accept_bounded::accept_bounded(
686                &listener,
687                &limiter,
688                if tls { b"" } else { REFUSAL },
689                "gNMI",
690                Some(&ctx.status_tx),
691            )
692            .await
693            else {
694                break;
695            };
696            let id = ConnectionId::new(ctx.state.get_next_unified_id().await);
697            let now = crate::utils::clock::Instant::now();
698            ctx.state
699                .add_connection_to_server(
700                    server,
701                    crate::state::server::ConnectionState {
702                        id,
703                        remote_addr: remote,
704                        local_addr: address,
705                        bytes_sent: 0,
706                        bytes_received: 0,
707                        packets_sent: 0,
708                        packets_received: 0,
709                        last_activity: now,
710                        status: crate::state::server::ConnectionStatus::Active,
711                        status_changed_at: now,
712                        protocol_info: crate::state::server::ProtocolConnectionInfo::empty(),
713                    },
714                )
715                .await;
716            let context = Context {
717                llm: ctx.llm_client.clone(),
718                state: ctx.state.clone(),
719                server,
720                connection: id,
721                protocol: Arc::new(actions::GnmiProtocol),
722                id: 0,
723                deadline: tokio::time::Instant::now(),
724            };
725            let cleanup = ctx.state.clone();
726            let acceptor = acceptor.clone();
727            let rpcs = rpcs.clone();
728            let next = next.clone();
729            ctx.state.spawn_server_task(server,async move{
730                let _permit=permit;
731                if matches!(tokio::time::timeout(FIRST_BYTE_READ_TIMEOUT,socket.peek(&mut[0u8;1])).await,Ok(Ok(n)) if n>0){
732                    if let Some(acceptor)=acceptor{
733                        if let Ok(Ok(socket))=tokio::time::timeout(Duration::from_secs(10),acceptor.accept(socket)).await{
734                            if socket.get_ref().1.alpn_protocol()==Some(b"h2"){serve(socket,context,rpcs,Duration::from_secs(timeout),next).await;}
735                        }
736                    }else{serve(socket,context,rpcs,Duration::from_secs(timeout),next).await;}
737                }
738                cleanup.remove_connection_from_server(server,id).await;
739            }).await;
740        }
741    });
742    owner.register_server_task(server, task).await;
743    Ok(address)
744}