Latest changes

- [API Change] Add optional callback to call when handshake is done
- [API Change, BUGFIX] After send failure, wait until transport available
This commit is contained in:
Dmitri Tikhonov 2018-05-21 15:02:33 -04:00
parent 04468d215d
commit c44946ecd7
10 changed files with 107 additions and 3 deletions

View file

@ -1,3 +1,8 @@
2018-05-21
- [API Change] Add optional callback to call when handshake is done
- [API Change, BUGFIX] After send failure, wait until transport available
2018-05-18
- [API] Expose useful lsquic_ver2str[] in lsquic.h

View file

@ -97,6 +97,13 @@ LSQUIC_CUBIC_SAMPLING_RATE
Only available in debug builds.
LSQUIC_RANDOM_SEND_FAILURE
Frequency with which sending of packets fails: one out of this many
times on average.
Only available when compiled with -DLSQUIC_RANDOM_SEND_FAILURE=1
Control Network-Related Stuff
-----------------------------
@ -141,3 +148,9 @@ More Compilation Options
Add relatively expensive run-time sanity checks
-DLSQUIC_RANDOM_SEND_FAILURE=1
Simulate failure to send packets to test send resumption logic. When
this flag is specified, sending of packets will randomly fail, about
one out of every 10 attempts. Set environment variable
LSQUIC_RANDOM_SEND_FAILURE to change this frequency.

View file

@ -143,6 +143,14 @@ struct lsquic_stream_if {
void (*on_read) (lsquic_stream_t *s, lsquic_stream_ctx_t *h);
void (*on_write) (lsquic_stream_t *s, lsquic_stream_ctx_t *h);
void (*on_close) (lsquic_stream_t *s, lsquic_stream_ctx_t *h);
/**
* When handshake is completed, this callback is called. `ok' is set
* to true if handshake was successful; otherwise, `ok' is set to
* false.
*
* This callback is optional.
*/
void (*on_hsk_done)(lsquic_conn_t *c, int ok);
};
/**
@ -428,7 +436,9 @@ struct lsquic_out_spec
/**
* Returns number of packets successfully sent out or -1 on error. -1 should
* only be returned if no packets were sent out.
* only be returned if no packets were sent out. If -1 is returned,
* no packets will be attempted to be sent out until
* @ref lsquic_engine_send_unsent_packets() is called.
*/
typedef int (*lsquic_packets_out_f)(
void *packets_out_ctx,
@ -519,6 +529,10 @@ lsquic_engine_has_unsent_packets (lsquic_engine_t *engine);
/**
* Send out as many unsent packets as possibe: until we are out of unsent
* packets or until @ref ea_packets_out() fails.
*
* If @ref ea_packets_out() does fail (that is, it returns an error), this
* function must be called to signify that sending of packets is possible
* again.
*/
void
lsquic_engine_send_unsent_packets (lsquic_engine_t *engine);

View file

@ -302,6 +302,7 @@ lsquic_engine_new (unsigned flags,
return NULL;
}
engine->pub.enp_ver_tags_len = tag_buf_len;
engine->pub.enp_flags = ENPUB_CAN_SEND;
engine->flags = flags;
engine->stream_if = api->ea_stream_if;
@ -951,7 +952,9 @@ send_batch (lsquic_engine_t *engine, struct conns_out_iter *conns_iter,
LSQ_DEBUG("packets out returned %d (out of %u)", n_sent, n_to_send);
else
{
engine->pub.enp_flags &= ~ENPUB_CAN_SEND;
LSQ_DEBUG("packets out returned an error: %s", strerror(errno));
EV_LOG_GENERIC_EVENT("cannot send packets");
n_sent = 0;
}
if (n_sent > 0)
@ -1147,6 +1150,12 @@ lsquic_engine_send_unsent_packets (lsquic_engine_t *engine)
STAILQ_INIT(&closed_conns);
reset_deadline(engine, lsquic_time_now());
if (!(engine->pub.enp_flags & ENPUB_CAN_SEND))
{
LSQ_DEBUG("can send again");
EV_LOG_GENERIC_EVENT("can send again");
engine->pub.enp_flags |= ENPUB_CAN_SEND;
}
send_packets_out(engine, &closed_conns);
@ -1199,7 +1208,8 @@ process_connections (lsquic_engine_t *engine, conn_iter_f next_conn,
STAILQ_INSERT_TAIL(&ticked_conns, conn, cn_next_ticked);
}
if (lsquic_engine_has_unsent_packets(engine))
if ((engine->pub.enp_flags & ENPUB_CAN_SEND)
&& lsquic_engine_has_unsent_packets(engine))
send_packets_out(engine, &closed_conns);
while ((conn = STAILQ_FIRST(&closed_conns))) {

View file

@ -21,6 +21,7 @@ struct lsquic_engine_public {
ENPUB_PROC = (1 << 0), /* Being processed by one of the user-facing
* functions.
*/
ENPUB_CAN_SEND = (1 << 1),
} enp_flags;
unsigned char enp_ver_tags_buf[ sizeof(lsquic_ver_tag_t) * N_LSQVER ];
unsigned enp_ver_tags_len;

View file

@ -3033,6 +3033,8 @@ full_conn_ci_handshake_ok (lsquic_conn_t *lconn)
lconn->cn_flags |= LSCONN_HANDSHAKE_DONE;
else
conn->fc_flags |= FC_ERROR;
if (conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done)
conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done(lconn, 1);
}
@ -3043,6 +3045,8 @@ full_conn_ci_handshake_failed (lsquic_conn_t *lconn)
LSQ_DEBUG("handshake failed");
lsquic_alarmset_unset(&conn->fc_alset, AL_HANDSHAKE);
conn->fc_flags |= FC_HSK_FAILED;
if (conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done)
conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done(lconn, 0);
}
@ -3389,7 +3393,8 @@ full_conn_ci_is_tickable (lsquic_conn_t *lconn)
if (!TAILQ_EMPTY(&conn->fc_pub.service_streams))
return 1;
if (lsquic_send_ctl_can_send(&conn->fc_send_ctl)
if ((conn->fc_enpub->enp_flags & ENPUB_CAN_SEND)
&& lsquic_send_ctl_can_send(&conn->fc_send_ctl)
&& (should_generate_ack(conn) ||
!lsquic_send_ctl_sched_is_blocked(&conn->fc_send_ctl)))
{

View file

@ -147,6 +147,13 @@ http_client_on_conn_closed (lsquic_conn_t *conn)
}
static void
http_client_on_hsk_done (lsquic_conn_t *conn, int ok)
{
LSQ_INFO("handshake %s", ok ? "completed successfully" : "failed");
}
struct lsquic_stream_ctx {
lsquic_stream_t *stream;
struct http_client_ctx *client_ctx;
@ -398,6 +405,7 @@ const struct lsquic_stream_if http_client_if = {
.on_read = http_client_on_read,
.on_write = http_client_on_write,
.on_close = http_client_on_close,
.on_hsk_done = http_client_on_hsk_done,
};

View file

@ -419,3 +419,24 @@ prog_is_stopped (void)
{
return prog_stopped != 0;
}
static void
send_unsent (evutil_socket_t fd, short what, void *arg)
{
struct prog *const prog = arg;
assert(prog->prog_send);
event_del(prog->prog_send);
event_free(prog->prog_send);
prog->prog_send = NULL;
lsquic_engine_send_unsent_packets(prog->prog_engine);
}
void
prog_sport_cant_send (struct prog *prog, int fd)
{
assert(!prog->prog_send);
prog->prog_send = event_new(prog->prog_eb, fd, EV_WRITE, send_unsent, prog);
event_add(prog->prog_send, NULL);
}

View file

@ -23,6 +23,7 @@ struct prog
int prog_version_cleared;
struct event_base *prog_eb;
struct event *prog_timer,
*prog_send,
*prog_usr1;
struct sport_head *prog_sports;
struct lsquic_engine *prog_engine;
@ -83,4 +84,7 @@ prog_is_stopped (void);
void
prog_process_conns (struct prog *);
void
prog_sport_cant_send (struct prog *, int fd);
#endif

View file

@ -875,6 +875,23 @@ send_packets_one_by_one (const struct lsquic_out_spec *specs, unsigned count)
if (0 == count)
return 0;
#if LSQUIC_RANDOM_SEND_FAILURE
{
const char *freq_str = getenv("LSQUIC_RANDOM_SEND_FAILURE");
int freq;
if (freq_str)
freq = atoi(freq_str);
else
freq = 10;
if (rand() % freq == 0)
{
assert(count > 0);
sport = specs[0].peer_ctx;
LSQ_NOTICE("sending \"randomly\" fails");
goto random_send_failure;
}
}
#endif
for (n = 0; n < count; ++n)
{
@ -931,7 +948,13 @@ send_packets_one_by_one (const struct lsquic_out_spec *specs, unsigned count)
if (n > 0)
return n;
else if (s < 0)
{
#if LSQUIC_RANDOM_SEND_FAILURE
random_send_failure:
#endif
prog_sport_cant_send(sport->sp_prog, sport->fd);
return -1;
}
else
return 0;
}