diff options
Diffstat (limited to 'lib/libtle_l4p')
-rw-r--r-- | lib/libtle_l4p/tcp_stream.c | 79 | ||||
-rw-r--r-- | lib/libtle_l4p/tle_tcp.h | 20 |
2 files changed, 79 insertions, 20 deletions
diff --git a/lib/libtle_l4p/tcp_stream.c b/lib/libtle_l4p/tcp_stream.c index 59299f7..59d94a4 100644 --- a/lib/libtle_l4p/tcp_stream.c +++ b/lib/libtle_l4p/tcp_stream.c @@ -503,6 +503,26 @@ tle_tcp_stream_open(struct tle_ctx *ctx, } /* + * Helper function, used by close()/shutdown API + * Check stream state, if FIN was not generatedi yet, then + * change stream state and queue it for TX. + */ +static inline int +stream_finalize(struct tle_ctx *ctx, struct tle_tcp_stream *s, uint32_t state) +{ + if (state != TLE_TCP_ST_ESTABLISHED && state != TLE_TCP_ST_CLOSE_WAIT) + return -EINVAL; + + /* change state */ + s->tcb.state = (state == TLE_TCP_ST_ESTABLISHED) ? + TLE_TCP_ST_FIN_WAIT_1 : TLE_TCP_ST_LAST_ACK; + + /* queue stream into to-send queue */ + txs_enqueue(ctx, s); + return 0; +} + +/* * Helper function, used by close API. */ static inline int @@ -515,26 +535,12 @@ stream_close(struct tle_ctx *ctx, struct tle_tcp_stream *s) return rc; /* generate FIN and proceed with normal connection termination */ - if (rc == TLE_TCP_ST_ESTABLISHED || rc == TLE_TCP_ST_CLOSE_WAIT) { - - /* change state */ - s->tcb.state = (rc == TLE_TCP_ST_ESTABLISHED) ? - TLE_TCP_ST_FIN_WAIT_1 : TLE_TCP_ST_LAST_ACK; + stream_finalize(ctx, s, rc); - /* mark stream as writable/readable again */ - tcp_stream_up(s); - - /* queue stream into to-send queue */ - txs_enqueue(ctx, s); - return 0; - } + /* mark stream as writable/readable again */ + tcp_stream_up(s); - /* - * accroding to the state, close() was already invoked, - * should never that point. - */ - RTE_ASSERT(0); - return -EINVAL; + return 0; } uint32_t @@ -629,6 +635,43 @@ tle_tcp_stream_abort(struct tle_stream *ts) } int +tle_tcp_stream_shutdown(struct tle_stream *ts) +{ + int32_t rc; + uint16_t uop; + struct tle_ctx *ctx; + struct tle_tcp_stream *s; + + const uint16_t nop = TLE_TCP_OP_SHUTDOWN; + + s = TCP_STREAM(ts); + if (ts == NULL || s->s.type >= TLE_VNUM) + return -EINVAL; + + ctx = s->s.ctx; + + /* check was shutdown() or close() already invoked */ + uop = s->tcb.uop; + if ((uop & (TLE_TCP_OP_CLOSE | nop)) != 0) + return -EDEADLK; + + /* record that shutdown was invoked */ + if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | nop) == 0) + return -EDEADLK; + + /* mark stream as unavaialbe for RX/TX. */ + tcp_stream_down(s); + + /* change state, generate FIN */ + rc = stream_finalize(ctx, s, s->tcb.state); + + /* mark stream as writable/readable again */ + tcp_stream_up(s); + + return rc; +} + +int tle_tcp_stream_get_addr(const struct tle_stream *ts, struct tle_tcp_stream_addr *addr) { diff --git a/lib/libtle_l4p/tle_tcp.h b/lib/libtle_l4p/tle_tcp.h index 289683f..8a42f75 100644 --- a/lib/libtle_l4p/tle_tcp.h +++ b/lib/libtle_l4p/tle_tcp.h @@ -48,8 +48,9 @@ enum { TLE_TCP_OP_ACCEPT = 0x2, TLE_TCP_OP_CONNECT = 0x4, TLE_TCP_OP_ESTABLISH = 0x8, - TLE_TCP_OP_CLOSE = 0x10, - TLE_TCP_OP_ABORT = 0x20, + TLE_TCP_OP_SHUTDOWN = 0x10, + TLE_TCP_OP_CLOSE = 0x20, + TLE_TCP_OP_ABORT = 0x40, }; #define TLE_TCP_OP_CLOSE_ABORT (TLE_TCP_OP_CLOSE | TLE_TCP_OP_ABORT) @@ -168,6 +169,21 @@ tle_tcp_stream_open(struct tle_ctx *ctx, int tle_tcp_stream_close(struct tle_stream *s); /** + * half-close for open stream. + * if the stream is in connected or close-wait state, then: + * - FIN packet will be generated and stream state will be changed accordingly. + * Note that stream will remain open till user will call actual close() + * for that stream (even if actual connection was already terminated). + * @param s + * Pointer to the stream to close. + * @return + * zero on successful completion. + * - -EINVAL - invalid parameter passed to function + * - -EDEADLK - shutdown/close was already invoked on that stream + */ +int tle_tcp_stream_shutdown(struct tle_stream *s); + +/** * abnormal stream termination. * if the stream is in connected state, then: * - abnormal connection termination would be performed. |