Beispiel #1
0
    // Update is called once per frame
    void Update()
    {
        if (quicheConn == null || quicheConn.IsClosed)
        {
            return;
        }
        quicheConn.OnTimeout();
        if (receiveResult == null)
        {
            receiveResult = udpClient.BeginReceive((res) => {
                var recvBytes = udpClient.EndReceive(res, ref remoteIpEndPoint);
                var read      = quicheConn.Receive(recvBytes);
                if (read == (int)QuicheError.QUICHE_ERR_DONE)
                {
                    Debug.Log("done reading");
                    return;
                }
                if (read < 0)
                {
                    QuicheError err = (QuicheError)Enum
                                      .ToObject(typeof(QuicheError), read);
                    Debug.LogError($"recv failed {err}");
                    throw new Exception();
                }
            }, null);
        }
        if (receiveResult.IsCompleted)
        {
            receiveResult = null;
        }
        if (quicheConn.IsEstablished && h3Conn == null)
        {
            h3Conn = new H3Connection(quicheConn, h3Config);
        }
        if (h3Conn != null)
        {
            var reqsDone = 0;

            for (var i = reqsSent; i < reqsCount; i++)
            {
                Debug.Log($"sending HTTP request [{string.Join(",", req.Select(x=>H3Header.DebugString(x)))}]");
                var streamId = h3Conn.SendRequest(req, body == null);
                if (streamId == (int)H3Error.QUICHE_H3_TRANSPORT_ERROR)
                {
                    Debug.Log("not enough stream credits, retry later...");
                    break;
                }
                if (streamId < 0)
                {
                    H3Error err = (H3Error)Enum
                                  .ToObject(typeof(H3Error), streamId);
                    Debug.LogError($"recv failed {err}");
                    throw new Exception();
                }
                if (body != null)
                {
                    var e = h3Conn.SendBody((ulong)streamId, body, true);
                    if (e < 0)
                    {
                        H3Error err = (H3Error)Enum
                                      .ToObject(typeof(H3Error), e);
                        Debug.LogError($"recv failed {err}");
                        throw new Exception();
                    }
                }
                reqsDone++;
            }
            reqsSent += reqsDone;
        }
        if (h3Conn != null)
        {
            H3Event ev = null;
            // Process HTTP/3 events.
            while (h3Conn != null)
            {
                var streamId = h3Conn.Poll(ref ev);
                if (streamId == (int)H3Error.QUICHE_H3_DONE)
                {
                    break;
                }
                else if (streamId < 0)
                {
                    H3Error err = (H3Error)Enum
                                  .ToObject(typeof(H3Error), streamId);
                    Debug.LogError($"recv failed {err}");
                    return;
                }
                switch (ev.EventType)
                {
                case (uint)H3EventType.QUICHE_H3_EVENT_HEADERS:
                {
                    var rc = ev.ForEachHeader((name, nameLen, value, valueLen, argp) => {
                            Debug.Log($"got HTTP header: {name}={value}");
                        });
                    if (rc != 0)
                    {
                        Debug.LogError("failed to process headers");
                    }
                    break;
                }

                case (uint)H3EventType.QUICHE_H3_EVENT_DATA:
                {
                    var _out = new byte[65535];
                    var len  = h3Conn.ReceiveBody((ulong)streamId, _out);
                    if (len <= 0)
                    {
                        break;
                    }
                    Debug.Log($"{Encoding.ASCII.GetString(_out.Take((int)len).ToArray())}");
                    break;
                }

                case (uint)H3EventType.QUICHE_H3_EVENT_FINISHED:
                {
                    reqsComplete++;
                    if (reqsComplete == reqsCount)
                    {
                        Debug.Log($"{reqsComplete}/{reqsCount} response(s) received, cloing...");
                        var e = quicheConn.Close(true, 0, Encoding.ASCII.GetBytes("kthxbye"));
                        h3Conn.Dispose();
                        h3Conn = null;
                        if (e == (int)QuicheError.QUICHE_ERR_DONE)
                        {
                            break;
                        }
                        else if (e < 0)
                        {
                            QuicheError err = (QuicheError)Enum
                                              .ToObject(typeof(QuicheError), e);
                            Debug.LogError($"recv failed {err}");
                            throw new Exception();
                        }
                    }
                    break;
                }
                }
                ev.Dispose();
                ev = null;
            }
        }

        var write = quicheConn.Send(buf);

        if (write == (int)QuicheError.QUICHE_ERR_DONE)
        {
            return;
        }
        if (write < 0)
        {
            QuicheError err = (QuicheError)Enum
                              .ToObject(typeof(QuicheError), write);
            Debug.LogError($"send failed {err}");
            throw new Exception();
        }
        udpClient.Send(buf, write);
    }
    private void Poll()
    {
        if (conn == null)
        {
            return;
        }
        if (conn.IsClosed)
        {
            return;
        }
        conn.OnTimeout();
        if (receiveResult == null)
        {
            receiveResult = client.BeginReceive((res) => {
                var recvBytes = client.EndReceive(res, ref RemoteIpEndPoint);
                var read      = conn.Receive(recvBytes);
                if (read == (int)QuicheError.QUICHE_ERR_DONE)
                {
                    Debug.Log("done reading");
                    return;
                }
                if (read < 0)
                {
                    QuicheError err = (QuicheError)Enum
                                      .ToObject(typeof(QuicheError), read);
                    Debug.LogError($"recv failed {err}");
                    throw new Exception();
                }
            }, null);
        }
        if (receiveResult.IsCompleted)
        {
            receiveResult = null;
        }
        if (conn.IsEstablished)
        {
            if (!req_sent)
            {
                Debug.Log($"sending HTTP request for {uri.PathAndQuery}");
                var req         = Encoding.ASCII.GetBytes($"GET {uri.PathAndQuery}\r\n");
                var streamWrite = conn.StreamSend(HTTP_REQ_STREAM_ID, req, true);
                if (streamWrite < 0)
                {
                    QuicheError err = (QuicheError)Enum
                                      .ToObject(typeof(QuicheError), streamWrite);
                    Debug.LogError($"send failed {err}");
                    throw new Exception();
                }
                req_sent = true;
            }

            foreach (ulong streamId in conn.Readable())
            {
                bool fin        = false;
                var  readStream = conn.StreamReceive(
                    streamId, streamRecv, ref fin);
                if (readStream < 0)
                {
                    continue;
                }
                var res = Encoding.ASCII.GetString(
                    streamRecv.Take(readStream).ToArray());
                Debug.Log($"{res}");
                if (fin)
                {
                    var reason     = Encoding.ASCII.GetBytes("kthxbye");
                    int closeError = conn.Close(true, 0, reason);
                    if (closeError < 0)
                    {
                        QuicheError err = (QuicheError)Enum
                                          .ToObject(typeof(QuicheError), closeError);
                        Debug.LogError($"send failed {err}");
                        throw new Exception();
                    }
                }
            }
        }
        var write = conn.Send(buf);

        if (write == (int)QuicheError.QUICHE_ERR_DONE)
        {
            return;
        }
        if (write < 0)
        {
            QuicheError err = (QuicheError)Enum
                              .ToObject(typeof(QuicheError), write);
            Debug.LogError($"send failed {err}");
            throw new Exception();
        }
        client.Send(buf, write);
    }