Skip to content

Commit

Permalink
Websockets over http/1.1 minor fixes
Browse files Browse the repository at this point in the history
Signed-off-by: Aleksey Mikhaylov <aym@tempesta-tech.com>
  • Loading branch information
ttaym committed Apr 21, 2022
1 parent 012c5a9 commit 6fe99b0
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 49 deletions.
63 changes: 42 additions & 21 deletions fw/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -2312,8 +2312,8 @@ tfw_http_conn_msg_alloc(TfwConn *conn, TfwStream *stream)

mit->map = tfw_pool_alloc(hm->pool, sz);
if (unlikely(!mit->map)) {
T_WARN("HTTP/2: unable to allocate memory for "
"response header map\n");
T_WARN("HTTP/2: unable to allocate memory for"
" response header map\n");
goto clean;
}
mit->map->size = TFW_HDR_MAP_INIT_CNT;
Expand Down Expand Up @@ -5038,6 +5038,12 @@ tfw_http_req_cache_cb(TfwHttpMsg *msg)
/* Account current request in APM health monitoring statistics */
tfw_http_hm_srv_update((TfwServer *)srv_conn->peer, req);

/* We set TFW_CONN_B_UNSCHED on server connection. New requests must
* not be scheduled to it. It will be used only for websocket transport.
* If upgrade will fail, we clear it. */
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, req->flags)) {
set_bit(TFW_CONN_B_UNSCHED, &srv_conn->flags);
}
/* Forward request to the server. */
tfw_http_req_fwd_resched(srv_conn, req, &eq);
tfw_http_req_zap_error(&eq);
Expand Down Expand Up @@ -5944,6 +5950,8 @@ tfw_http_websocket_upgrade(TfwSrvConn *srv_conn, TfwCliConn * cli_conn)
cli_conn->pair = (TfwConn *)ws_conn;
ws_conn->pair = (TfwConn *)cli_conn;

tfw_ws_cli_mod_timer(cli_conn);

return TFW_PASS;
}

Expand Down Expand Up @@ -6213,6 +6221,10 @@ int
tfw_http_msg_process_generic(TfwConn *conn, TfwStream *stream,
struct sk_buff *skb)
{
int r;
TfwHttpMsg *req;
bool websocket = false;

if (WARN_ON_ONCE(!stream))
return -EINVAL;
if (unlikely(!stream->msg)) {
Expand All @@ -6229,9 +6241,24 @@ tfw_http_msg_process_generic(TfwConn *conn, TfwStream *stream,
T_DBG2("Add skb %p to message %p\n", skb, stream->msg);
ss_skb_queue_tail(&stream->msg->skb_head, skb);

return (TFW_CONN_TYPE(conn) & Conn_Clnt)
? tfw_http_req_process(conn, stream, skb)
: tfw_http_resp_process(conn, stream, skb);
if (TFW_CONN_TYPE(conn) & Conn_Clnt)
return tfw_http_req_process(conn, stream, skb);

/* That is paired request, it may be freed after resp processing */
req = ((TfwHttpMsg *)stream->msg)->pair;
websocket = test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, req->flags);
if ((r = tfw_http_resp_process(conn, stream, skb))) {
TfwSrvConn *srv_conn = (TfwSrvConn *)conn;
/*
* We must clear TFW_CONN_B_UNSCHED to make server connection
* available for request scheduling further if websocket upgrade
* request failed.
*/
if (websocket)
clear_bit(TFW_CONN_B_UNSCHED, &srv_conn->flags);
}

return r;
}

/**
Expand Down Expand Up @@ -6996,16 +7023,16 @@ TfwMod tfw_http_mod = {
.specs = tfw_http_specs,
};

/*
* We do not use http fsm for message processing any more, but only for
* frang checks, so to clearly show our intention we BUG() here.
*/
static int
tfw_http_msg_process_fsm(TfwConn *conn, TfwFsmData *data)
{
BUG();
return 0;
}
// /*
// * We do not use http fsm for message processing any more, but only for
// * frang checks, so to clearly show our intention we BUG() here.
// */
// static int
// tfw_http_msg_process_fsm(TfwConn *conn, TfwFsmData *data)
// {
// BUG();
// return 0;
// }

/*
* ------------------------------------------------------------------------
Expand All @@ -7016,11 +7043,6 @@ tfw_http_msg_process_fsm(TfwConn *conn, TfwFsmData *data)
int __init
tfw_http_init(void)
{
int r;

if ((r = tfw_gfsm_register_fsm(TFW_FSM_HTTP, tfw_http_msg_process_fsm)))
return r;

tfw_connection_hooks_register(&http_conn_hooks, TFW_FSM_HTTP);

tfw_mod_register(&tfw_http_mod);
Expand All @@ -7033,5 +7055,4 @@ tfw_http_exit(void)
{
tfw_mod_unregister(&tfw_http_mod);
tfw_connection_hooks_unregister(TFW_FSM_HTTP);
tfw_gfsm_unregister_fsm(TFW_FSM_HTTP);
}
1 change: 0 additions & 1 deletion fw/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ typedef struct {
* Called in process context at re-configuration time.
* @del_srv - delete single server added via add_srv.
* Called in SoftIRQ context.
*
* @sched_sg_conn - virtual method. Schedule a request to a server from
* given server group. Returns a server connection;
* @sched_srv_conn - schedule a request to the given server.
Expand Down
53 changes: 26 additions & 27 deletions fw/websocket.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,59 +131,58 @@ static struct tfw_cfg_ws_t {

typedef struct tfw_cfg_ws_t TfwCfgWs;

/**
* Rearm client connection timer for client timeout functionality,
* `client_ws_timeout` is a corresponding config setting.
* TODO #736: do not update time on each packet handling.
*/
void
tfw_ws_cli_mod_timer(TfwCliConn *conn)
{
BUG_ON(!(TFW_CONN_TYPE(conn) & Conn_Clnt));

spin_lock(&conn->timer_lock);
if (timer_pending(&conn->timer))
mod_timer(&conn->timer,
jiffies + msecs_to_jiffies(
(long)tfw_cfg_ws.client_ws_timeout
* 1000));
spin_unlock(&conn->timer_lock);
}

/**
* Process data for websocket connection without any introspection and
* analisis of the protocol. Just send it as is.
*
* Create light http msg with Conn_Srv flag just to append skb to it and forward
* it further. Client messages contain many fields not needed for websocket
* protocol.
*/
int
tfw_ws_msg_process(TfwConn *conn, struct sk_buff *skb)
{
int r;
TfwCliConn *cli_conn;
TfwHttpMsg *hm;
TfwMsg msg;

T_DBG2("%s: conn=[%p], skb=[%p]\n", __func__, conn, skb);

hm = __tfw_http_msg_alloc(Conn_Srv, false);
if (!hm) {
__kfree_skb(skb);
return T_DROP;
}
ss_skb_queue_tail(&msg.skb_head, skb);

ss_skb_queue_tail(&hm->msg.skb_head, skb);

if ((r = tfw_connection_send(conn->pair, (TfwMsg *)hm))) {
if ((r = tfw_connection_send(conn->pair, &msg))) {
T_DBG("%s: cannot send data to via websocket\n", __func__);
tfw_connection_close(conn, true);
}

/* When receiving data from client we consider client timeout */
if (TFW_CONN_TYPE(conn) & Conn_Clnt) {
cli_conn = (TfwCliConn *)conn;

spin_lock(&cli_conn->timer_lock);
if (timer_pending(&cli_conn->timer))
mod_timer(&cli_conn->timer,
jiffies + msecs_to_jiffies(
(long)tfw_cfg_ws.client_ws_timeout
* 1000));
spin_unlock(&cli_conn->timer_lock);
tfw_ws_cli_mod_timer((TfwCliConn *)conn);
}

tfw_http_msg_free(hm);

return r;
}

/**
* Websocket connection hooks.
*
* These hooks unified between wss and ws. For wss called tls and for
* plain ws called http conn_hook. No self recursion here just downcall.
* These hooks unified between wss and ws. For wss we call HTTPS state machine
* and for plain ws we call HTTP conn_hook. No self recursion here just
* downcall into lower layer through `tfw_conn_hook_call()`.
*
* TFW_CONN_HTTP_TYPE macro strips TFW_FSM_WEBSOCKET mark from connection type.
*/
Expand Down
1 change: 1 addition & 0 deletions fw/websocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ typedef struct tfw_conn_t TfwConn;

int tfw_ws_msg_process(TfwConn *conn, struct sk_buff *skb);
TfwConn *tfw_ws_srv_new_steal_sk(TfwSrvConn *srv_conn);
void tfw_ws_cli_mod_timer(TfwCliConn *conn);

#endif /* __TFW_WS_H__ */

0 comments on commit 6fe99b0

Please sign in to comment.