// Start is called before the first frame update void Start() { uri = new Uri(urlString); Debug.Log(QuicheVersion.GetVersion()); if (isDebugLog) { QuicheDebug.EnableDebugLogging((line, argp) => { Debug.Log(line); }); } udpClient = new UdpClient(); quicheClient = new QuicheClient(CreateQuicheConfig()); udpClient.Connect($"{uri.Host}", uri.Port); quicheConn = quicheClient.Connect(uri.Authority); Debug.Log( $"connecting to {uri.Authority} from {udpClient.Client.LocalEndPoint} " + $"with scid {quicheClient.HexDump}"); // initial send int write = quicheConn.Send(buf); udpClient.Send(buf, write); h3Config = new H3Config(); // Prepare request. var reqList = new H3Header[] { new H3Header(":method", "GET"), new H3Header(":scheme", "https"), new H3Header(":authority", uri.Host), new H3Header(":path", uri.PathAndQuery), new H3Header("user-agent", "unity-quiche"), }.ToList(); // TODO Add custom headers to the request. // TODO Add body body = null; if (body != null) { reqList.Add(new H3Header( "content-length", $"{body.Length}")); } req = reqList.ToArray(); }
// 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); }