Skip to content

Commit

Permalink
Update code to use the new network-path aware API of quiche (java-nat…
Browse files Browse the repository at this point in the history
…ive-access#291)


Motivation:

Quiche changed its API to be network path aware and so be able to handle connection migration in the future.

Modifications:

- Adjust code to use the new API

Result:

Be able to use the new network-path aware API of quiche
  • Loading branch information
normanmaurer authored May 29, 2021
1 parent 3ee2360 commit 69fdc1c
Show file tree
Hide file tree
Showing 26 changed files with 1,192 additions and 288 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
<quicheHomeIncludeDir>${quicheHomeDir}/include</quicheHomeIncludeDir>
<quicheRepository>https://github.com/cloudflare/quiche</quicheRepository>
<quicheBranch>master</quicheBranch>
<quicheCommitSha>92e9561501a3a5ab179115675dca25f8b0feb185</quicheCommitSha>
<quicheCommitSha>6d070ed8694216806f3ce689d71ceb7ad76d425e</quicheCommitSha>
<generatedSourcesDir>${project.build.directory}/generated-sources</generatedSourcesDir>
<templateDir>${project.build.directory}/template</templateDir>
<cargoTarget />
Expand Down
183 changes: 174 additions & 9 deletions src/main/c/netty_quic_quiche.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif // _WIN32

#include <quiche.h>
#include "netty_jni_util.h"
#include "netty_quic_boringssl.h"
Expand Down Expand Up @@ -46,6 +56,97 @@ jint quic_get_java_env(JNIEnv **env)
return (*global_vm)->GetEnv(global_vm, (void **)env, NETTY_JNI_UTIL_JNI_VERSION);
}

static jint netty_quiche_afInet(JNIEnv* env, jclass clazz) {
return AF_INET;
}

static jint netty_quiche_afInet6(JNIEnv* env, jclass clazz) {
return AF_INET6;
}

static jint netty_quiche_sizeofSockaddrIn(JNIEnv* env, jclass clazz) {
return sizeof(struct sockaddr_in);
}

static jint netty_quiche_sizeofSockaddrIn6(JNIEnv* env, jclass clazz) {
return sizeof(struct sockaddr_in6);
}

static jint netty_quiche_sockaddrInOffsetofSinFamily(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in, sin_family);
}

static jint netty_quiche_sockaddrInOffsetofSinPort(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in, sin_port);
}

static jint netty_quiche_sockaddrInOffsetofSinAddr(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in, sin_addr);
}

static jint netty_quiche_inAddressOffsetofSAddr(JNIEnv* env, jclass clazz) {
return offsetof(struct in_addr, s_addr);
}

static jint netty_quiche_sockaddrIn6OffsetofSin6Family(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_family);
}

static jint netty_quiche_sockaddrIn6OffsetofSin6Port(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_port);
}

static jint netty_quiche_sockaddrIn6OffsetofSin6Flowinfo(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_flowinfo);
}

static jint netty_quiche_sockaddrIn6OffsetofSin6Addr(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_addr);
}

static jint netty_quiche_sockaddrIn6OffsetofSin6ScopeId(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_scope_id);
}

static jint netty_quiche_in6AddressOffsetofS6Addr(JNIEnv* env, jclass clazz) {
return offsetof(struct in6_addr, s6_addr);
}

static jint netty_quiche_sizeofSockaddrStorage(JNIEnv* env, jclass clazz) {
return sizeof(struct sockaddr_storage);
}
static jint netty_quiche_sizeofSizeT(JNIEnv* env, jclass clazz) {
return sizeof(size_t);
}

static jint netty_quiche_sizeofSocklenT(JNIEnv* env, jclass clazz) {
return sizeof(socklen_t);
}

static jint netty_quicheRecvInfoOffsetofFrom(JNIEnv* env, jclass clazz) {
return offsetof(quiche_recv_info, from);
}

static jint netty_quicheRecvInfoOffsetofFromLen(JNIEnv* env, jclass clazz) {
return offsetof(quiche_recv_info, from_len);
}

static jint netty_sizeofQuicheRecvInfo(JNIEnv* env, jclass clazz) {
return sizeof(quiche_recv_info);
}

static jint netty_quicheSendInfoOffsetofTo(JNIEnv* env, jclass clazz) {
return offsetof(quiche_send_info, to);
}

static jint netty_quicheSendInfoOffsetofToLen(JNIEnv* env, jclass clazz) {
return offsetof(quiche_send_info, to_len);
}

static jint netty_sizeofQuicheSendInfo(JNIEnv* env, jclass clazz) {
return sizeof(quiche_send_info);
}

static jint netty_quiche_max_conn_id_len(JNIEnv* env, jclass clazz) {
return QUICHE_MAX_CONN_ID_LEN;
}
Expand Down Expand Up @@ -176,13 +277,15 @@ static jint netty_quiche_retry(JNIEnv* env, jclass clazz, jlong scid, jint scid_
(uint32_t) version, (uint8_t *) out, (size_t) out_len);
}

static jlong netty_quiche_conn_new_with_tls(JNIEnv* env, jclass clazz, jlong scid, jint scid_len, jlong odcid, jint odcid_len, jlong config, jlong ssl, jboolean isServer) {
static jlong netty_quiche_conn_new_with_tls(JNIEnv* env, jclass clazz, jlong scid, jint scid_len, jlong odcid, jint odcid_len, jlong peer, jint peer_len, jlong config, jlong ssl, jboolean isServer) {
const uint8_t * odcid_pointer = NULL;
if (odcid_len != -1) {
odcid_pointer = (const uint8_t *) odcid;
}
const struct sockaddr *peer_pointer = (const struct sockaddr*) peer;
quiche_conn *conn = quiche_conn_new_with_tls((const uint8_t *) scid, (size_t) scid_len,
odcid_pointer, (size_t) odcid_len,
peer_pointer, (size_t) peer_len,
(quiche_config *) config, (void*) ssl, isServer == JNI_TRUE ? true : false);
if (conn == NULL) {
return -1;
Expand Down Expand Up @@ -226,12 +329,12 @@ static jbyteArray netty_quiche_conn_destination_id(JNIEnv* env, jclass clazz, jl
return to_byte_array(env, id, len);
}

static jint netty_quiche_conn_recv(JNIEnv* env, jclass clazz, jlong conn, jlong buf, jint buf_len) {
return (jint) quiche_conn_recv((quiche_conn *) conn, (uint8_t *) buf, (size_t) buf_len);
static jint netty_quiche_conn_recv(JNIEnv* env, jclass clazz, jlong conn, jlong buf, jint buf_len, jlong info) {
return (jint) quiche_conn_recv((quiche_conn *) conn, (uint8_t *) buf, (size_t) buf_len, (quiche_recv_info*) info);
}

static jint netty_quiche_conn_send(JNIEnv* env, jclass clazz, jlong conn, jlong out, jint out_len) {
return (jint) quiche_conn_send((quiche_conn *) conn, (uint8_t *) out, (size_t) out_len);
static jint netty_quiche_conn_send(JNIEnv* env, jclass clazz, jlong conn, jlong out, jint out_len, jlong info) {
return (jint) quiche_conn_send((quiche_conn *) conn, (uint8_t *) out, (size_t) out_len, (quiche_send_info*) info);
}

static void netty_quiche_conn_free(JNIEnv* env, jclass clazz, jlong conn) {
Expand Down Expand Up @@ -472,10 +575,71 @@ static jlong netty_buffer_memory_address(JNIEnv* env, jclass clazz, jobject buff
return (jlong) (*env)->GetDirectBufferAddress(env, buffer);
}

// Based on https://gist.github.com/kazuho/45eae4f92257daceb73e.
static jint netty_sockaddr_cmp(JNIEnv* env, jclass clazz, jlong addr1, jlong addr2) {
struct sockaddr* x = (struct sockaddr*) addr1;
struct sockaddr* y = (struct sockaddr*) addr2;

if (x == NULL && y == NULL) {
return 0;
}
if (x != NULL && y == NULL) {
return 1;
}
if (x == NULL && y != NULL) {
return -1;
}

#define CMP(a, b) if (a != b) return a < b ? -1 : 1

CMP(x->sa_family, y->sa_family);

if (x->sa_family == AF_INET) {
struct sockaddr_in *xin = (void*)x, *yin = (void*)y;
CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr));
CMP(ntohs(xin->sin_port), ntohs(yin->sin_port));
} else if (x->sa_family == AF_INET6) {
struct sockaddr_in6 *xin6 = (void*)x, *yin6 = (void*)y;
int r = memcmp(xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr, sizeof(xin6->sin6_addr.s6_addr));
if (r != 0)
return r;
CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port));
CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo);
CMP(xin6->sin6_scope_id, yin6->sin6_scope_id);
}

#undef CMP
return 0;
}

// JNI Registered Methods End

// JNI Method Registration Table Begin
static const JNINativeMethod statically_referenced_fixed_method_table[] = {
{ "afInet", "()I", (void *) netty_quiche_afInet },
{ "afInet6", "()I", (void *) netty_quiche_afInet6 },
{ "sizeofSockaddrIn", "()I", (void *) netty_quiche_sizeofSockaddrIn },
{ "sizeofSockaddrIn6", "()I", (void *) netty_quiche_sizeofSockaddrIn6 },
{ "sockaddrInOffsetofSinFamily", "()I", (void *) netty_quiche_sockaddrInOffsetofSinFamily },
{ "sockaddrInOffsetofSinPort", "()I", (void *) netty_quiche_sockaddrInOffsetofSinPort },
{ "sockaddrInOffsetofSinAddr", "()I", (void *) netty_quiche_sockaddrInOffsetofSinAddr },
{ "inAddressOffsetofSAddr", "()I", (void *) netty_quiche_inAddressOffsetofSAddr },
{ "sockaddrIn6OffsetofSin6Family", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Family },
{ "sockaddrIn6OffsetofSin6Port", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Port },
{ "sockaddrIn6OffsetofSin6Flowinfo", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Flowinfo },
{ "sockaddrIn6OffsetofSin6Addr", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Addr },
{ "sockaddrIn6OffsetofSin6ScopeId", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6ScopeId },
{ "in6AddressOffsetofS6Addr", "()I", (void *) netty_quiche_in6AddressOffsetofS6Addr },
{ "sizeofSockaddrStorage", "()I", (void *) netty_quiche_sizeofSockaddrStorage },
{ "sizeofSizeT", "()I", (void *) netty_quiche_sizeofSizeT },
{ "sizeofSocklenT", "()I", (void *) netty_quiche_sizeofSocklenT },
{ "quicheRecvInfoOffsetofFrom", "()I", (void *) netty_quicheRecvInfoOffsetofFrom },
{ "quicheRecvInfoOffsetofFromLen", "()I", (void *) netty_quicheRecvInfoOffsetofFromLen },
{ "sizeofQuicheRecvInfo", "()I", (void *) netty_sizeofQuicheRecvInfo },
{ "quicheSendInfoOffsetofTo", "()I", (void *) netty_quicheSendInfoOffsetofTo },
{ "quicheSendInfoOffsetofToLen", "()I", (void *) netty_quicheSendInfoOffsetofToLen },
{ "sizeofQuicheSendInfo", "()I", (void *) netty_sizeofQuicheSendInfo },

{ "quiche_protocol_version", "()I", (void *) netty_quiche_protocol_version },
{ "quiche_max_conn_id_len", "()I", (void *) netty_quiche_max_conn_id_len },
{ "quiche_shutdown_read", "()I", (void *) netty_quiche_shutdown_read },
Expand Down Expand Up @@ -510,9 +674,9 @@ static const JNINativeMethod fixed_method_table[] = {
{ "quiche_conn_trace_id", "(J)[B", (void *) netty_quiche_conn_trace_id },
{ "quiche_conn_source_id", "(J)[B", (void *) netty_quiche_conn_source_id },
{ "quiche_conn_destination_id", "(J)[B", (void *) netty_quiche_conn_destination_id },
{ "quiche_conn_new_with_tls", "(JIJIJJZ)J", (void *) netty_quiche_conn_new_with_tls },
{ "quiche_conn_recv", "(JJI)I", (void *) netty_quiche_conn_recv },
{ "quiche_conn_send", "(JJI)I", (void *) netty_quiche_conn_send },
{ "quiche_conn_new_with_tls", "(JIJIJIJJZ)J", (void *) netty_quiche_conn_new_with_tls },
{ "quiche_conn_recv", "(JJIJ)I", (void *) netty_quiche_conn_recv },
{ "quiche_conn_send", "(JJIJ)I", (void *) netty_quiche_conn_send },
{ "quiche_conn_free", "(J)V", (void *) netty_quiche_conn_free },
{ "quiche_conn_peer_streams_left_bidi", "(J)J", (void *) netty_quiche_conn_peer_streams_left_bidi },
{ "quiche_conn_peer_streams_left_uni", "(J)J", (void *) netty_quiche_conn_peer_streams_left_uni },
Expand Down Expand Up @@ -555,7 +719,8 @@ static const JNINativeMethod fixed_method_table[] = {
{ "quiche_config_set_cc_algorithm", "(JI)V", (void *) netty_quiche_config_set_cc_algorithm },
{ "quiche_config_enable_hystart", "(JZ)V", (void *) netty_quiche_config_enable_hystart },
{ "quiche_config_free", "(J)V", (void *) netty_quiche_config_free },
{ "buffer_memory_address", "(Ljava/nio/ByteBuffer;)J", (void *) netty_buffer_memory_address}
{ "buffer_memory_address", "(Ljava/nio/ByteBuffer;)J", (void *) netty_buffer_memory_address},
{ "sockaddr_cmp", "(JJ)I", (void *) netty_sockaddr_cmp}
};

static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.incubator.codec.quic;

import java.net.SocketAddress;

/**
* {@link QuicEvent} which is fired when an QUIC connection migration was detected.
*/
public final class QuicConnectionMigrationEvent implements QuicEvent {

private final SocketAddress from;
private final SocketAddress to;

QuicConnectionMigrationEvent(SocketAddress from, SocketAddress to) {
this.from = from;
this.to = to;
}

/**
* The old {@link SocketAddress} of the connection.
*
* @return the old {@link SocketAddress} of the connection.
*/
public SocketAddress from() {
return from;
}

/**
* The new {@link SocketAddress} of the connection.
*
* @return the new {@link SocketAddress} of the connection.
*/
public SocketAddress to() {
return to;
}
}
45 changes: 43 additions & 2 deletions src/main/java/io/netty/incubator/codec/quic/Quiche.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,44 @@ private static void loadNativeLibrary() {
}
}

static final short AF_INET = (short) QuicheNativeStaticallyReferencedJniMethods.afInet();
static final short AF_INET6 = (short) QuicheNativeStaticallyReferencedJniMethods.afInet6();
static final int SIZEOF_SOCKADDR_STORAGE = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrStorage();
static final int SIZEOF_SOCKADDR_IN = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrIn();
static final int SIZEOF_SOCKADDR_IN6 = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrIn6();
static final int SOCKADDR_IN_OFFSETOF_SIN_FAMILY =
QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinFamily();
static final int SOCKADDR_IN_OFFSETOF_SIN_PORT =
QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinPort();
static final int SOCKADDR_IN_OFFSETOF_SIN_ADDR =
QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinAddr();
static final int IN_ADDRESS_OFFSETOF_S_ADDR = QuicheNativeStaticallyReferencedJniMethods.inAddressOffsetofSAddr();
static final int SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY =
QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Family();
static final int SOCKADDR_IN6_OFFSETOF_SIN6_PORT =
QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Port();
static final int SOCKADDR_IN6_OFFSETOF_SIN6_FLOWINFO =
QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Flowinfo();
static final int SOCKADDR_IN6_OFFSETOF_SIN6_ADDR =
QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Addr();
static final int SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID =
QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6ScopeId();
static final int IN6_ADDRESS_OFFSETOF_S6_ADDR =
QuicheNativeStaticallyReferencedJniMethods.in6AddressOffsetofS6Addr();
static final int SIZEOF_SOCKLEN_T = QuicheNativeStaticallyReferencedJniMethods.sizeofSocklenT();
static final int SIZEOF_SIZE_T = QuicheNativeStaticallyReferencedJniMethods.sizeofSizeT();

static final int QUICHE_RECV_INFO_OFFSETOF_FROM =
QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofFrom();
static final int QUICHE_RECV_INFO_OFFSETOF_FROM_LEN =
QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofFromLen();
static final int SIZEOF_QUICHE_RECV_INFO = QuicheNativeStaticallyReferencedJniMethods.sizeofQuicheRecvInfo();
static final int QUICHE_SEND_INFO_OFFSETOF_TO =
QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofTo();
static final int QUICHE_SEND_INFO_OFFSETOF_TO_LEN =
QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofToLen();
static final int SIZEOF_QUICHE_SEND_INFO = QuicheNativeStaticallyReferencedJniMethods.sizeofQuicheSendInfo();

static final int QUICHE_PROTOCOL_VERSION = QuicheNativeStaticallyReferencedJniMethods.quiche_protocol_version();
static final int QUICHE_MAX_CONN_ID_LEN = QuicheNativeStaticallyReferencedJniMethods.quiche_max_conn_id_len();

Expand Down Expand Up @@ -229,6 +267,7 @@ static native int quiche_retry(long scidAddr, int scidLen, long dcidAddr, int dc
* See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L229">quiche_conn_new_with_tls</a>.
*/
static native long quiche_conn_new_with_tls(long scidAddr, int scidLen, long odcidAddr, int odcidLen,
long peerAddr, int peerLen,
long configAddr, long ssl, boolean isServer);

/**
Expand All @@ -240,12 +279,12 @@ static native long quiche_conn_new_with_tls(long scidAddr, int scidLen, long odc
/**
* See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L249">quiche_conn_recv</a>.
*/
static native int quiche_conn_recv(long connAddr, long bufAddr, int bufLen);
static native int quiche_conn_recv(long connAddr, long bufAddr, int bufLen, long infoAddr);

/**
* See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L262">quiche_conn_send</a>.
*/
static native int quiche_conn_send(long connAddr, long outAddr, int outLen);
static native int quiche_conn_send(long connAddr, long outAddr, int outLen, long infoAddr);

/**
* See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L373">quiche_conn_free</a>.
Expand Down Expand Up @@ -544,6 +583,8 @@ static native void quiche_config_enable_dgram(long configAddr, boolean enable,

private static native long buffer_memory_address(ByteBuffer buffer);

static native int sockaddr_cmp(long addr, long addr2);

/**
* Returns the memory address if the {@link ByteBuf}
*/
Expand Down
Loading

0 comments on commit 69fdc1c

Please sign in to comment.