Coverage Report

Created: 2026-08-14 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/sbi/nghttp2-server.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019,2024 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "ogs-sbi.h"
21
#include "yuarel.h"
22
23
#include <netinet/tcp.h>
24
#include <nghttp2/nghttp2.h>
25
26
#define USE_SEND_DATA_WITH_NO_COPY 1
27
28
static void server_init(int num_of_session_pool, int num_of_stream_pool);
29
static void server_final(void);
30
31
static int server_start(ogs_sbi_server_t *server,
32
        int (*cb)(ogs_sbi_request_t *request, void *data));
33
static void server_graceful_shutdown(ogs_sbi_server_t *server);
34
static void server_stop(ogs_sbi_server_t *server);
35
36
static bool server_send_rspmem_persistent(
37
        ogs_sbi_stream_t *stream, ogs_sbi_response_t *response);
38
static bool server_send_response(
39
        ogs_sbi_stream_t *stream, ogs_sbi_response_t *response);
40
41
static ogs_sbi_server_t *server_from_stream(ogs_sbi_stream_t *stream);
42
43
static ogs_pool_id_t id_from_stream(ogs_sbi_stream_t *stream);
44
static void *stream_find_by_id(ogs_pool_id_t id);
45
46
static void xact_attach(ogs_sbi_stream_t *stream, ogs_sbi_xact_t *xact);
47
static void xact_detach(ogs_sbi_xact_t *xact);
48
49
const ogs_sbi_server_actions_t ogs_nghttp2_server_actions = {
50
    server_init,
51
    server_final,
52
53
    server_start,
54
    server_graceful_shutdown,
55
    server_stop,
56
57
    server_send_rspmem_persistent,
58
    server_send_response,
59
60
    server_from_stream,
61
62
    id_from_stream,
63
    stream_find_by_id,
64
65
    xact_attach,
66
    xact_detach,
67
};
68
69
struct h2_settings {
70
    uint32_t max_concurrent_streams;
71
    bool enable_push;
72
};
73
74
typedef struct ogs_sbi_session_s {
75
    ogs_lnode_t             lnode;
76
77
    ogs_sock_t              *sock;
78
    ogs_sockaddr_t          *addr;
79
    struct {
80
        ogs_poll_t          *read;
81
        ogs_poll_t          *write;
82
    } poll;
83
84
    nghttp2_session         *session;
85
    ogs_list_t              write_queue;
86
87
    ogs_sbi_server_t        *server;
88
    ogs_list_t              stream_list;
89
    int32_t                 last_stream_id;
90
91
    struct h2_settings      settings;
92
    SSL*                    ssl;
93
} ogs_sbi_session_t;
94
95
typedef struct ogs_sbi_stream_s {
96
    ogs_lnode_t             lnode;
97
98
    ogs_pool_id_t           id;
99
100
    int32_t                 stream_id;
101
    ogs_sbi_request_t       *request;
102
    bool                    memory_overflow;
103
104
    ogs_sbi_session_t       *session;
105
106
    /*
107
     * Outbound SBI transactions originated by this inbound stream.
108
     * Populated automatically when ogs_sbi_discover_and_send() sees
109
     * xact->assoc_stream_id pointing at this stream, and drained at
110
     * stream close so response timers are freed promptly rather
111
     * than lingering until the SBI client wait timeout.
112
     */
113
    ogs_list_t              xact_list;
114
} ogs_sbi_stream_t;
115
116
static void session_remove(ogs_sbi_session_t *sbi_sess);
117
static void session_remove_all(ogs_sbi_server_t *server);
118
119
static void stream_remove(ogs_sbi_stream_t *stream);
120
121
static void accept_handler(short when, ogs_socket_t fd, void *data);
122
static void recv_handler(short when, ogs_socket_t fd, void *data);
123
124
static int session_set_callbacks(ogs_sbi_session_t *sbi_sess);
125
static int session_send_preface(ogs_sbi_session_t *sbi_sess);
126
static int session_send(ogs_sbi_session_t *sbi_sess);
127
static void session_write_to_buffer(
128
        ogs_sbi_session_t *sbi_sess, ogs_pkbuf_t *pkbuf);
129
130
static OGS_POOL(session_pool, ogs_sbi_session_t);
131
static OGS_POOL(stream_pool, ogs_sbi_stream_t);
132
133
static void server_init(int num_of_session_pool, int num_of_stream_pool)
134
0
{
135
0
    ogs_pool_init(&session_pool, num_of_session_pool);
136
0
    ogs_pool_init(&stream_pool, num_of_stream_pool);
137
0
}
138
139
static void server_final(void)
140
0
{
141
0
    ogs_pool_final(&stream_pool);
142
0
    ogs_pool_final(&session_pool);
143
0
}
144
145
#ifndef OPENSSL_NO_NEXTPROTONEG
146
static int next_proto_cb(SSL *ssl, const unsigned char **data,
147
                         unsigned int *len, void *arg)
148
0
{
149
0
    static unsigned char next_proto_list[256];
150
0
    (void)ssl;
151
0
    (void)arg;
152
153
0
    next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
154
0
    memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN);
155
156
0
    *data = next_proto_list;
157
0
    *len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
158
0
    return SSL_TLSEXT_ERR_OK;
159
0
}
160
#endif
161
162
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
163
static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
164
                                unsigned char *outlen, const unsigned char *in,
165
                                unsigned int inlen, void *arg)
166
0
{
167
0
    int rv;
168
0
    (void)ssl;
169
0
    (void)arg;
170
171
0
    rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
172
0
    if (rv != 1) {
173
0
        return SSL_TLSEXT_ERR_NOACK;
174
0
    }
175
176
0
    return SSL_TLSEXT_ERR_OK;
177
0
}
178
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
179
180
static int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max)
181
0
{
182
0
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
183
0
  if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 ||
184
0
      SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) {
185
0
    return -1;
186
0
  }
187
0
  return 0;
188
#else /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) */
189
  long int opts = 0;
190
191
  // TODO We depends on the ordering of protocol version macro in
192
  // OpenSSL.
193
  if (min > TLS1_VERSION) {
194
    opts |= SSL_OP_NO_TLSv1;
195
  }
196
  if (min > TLS1_1_VERSION) {
197
    opts |= SSL_OP_NO_TLSv1_1;
198
  }
199
  if (min > TLS1_2_VERSION) {
200
    opts |= SSL_OP_NO_TLSv1_2;
201
  }
202
203
  if (max < TLS1_2_VERSION) {
204
    opts |= SSL_OP_NO_TLSv1_2;
205
  }
206
  if (max < TLS1_1_VERSION) {
207
    opts |= SSL_OP_NO_TLSv1_1;
208
  }
209
210
  SSL_CTX_set_options(ssl_ctx, opts);
211
212
  return 0;
213
#endif /* OPENSSL_VERSION_NUMBER >= 0x1010000fL */
214
0
}
215
216
static SSL_CTX *create_ssl_ctx(
217
        const char *key_file, const char *cert_file,
218
        const char *sslkeylog_file)
219
0
{
220
0
    SSL_CTX *ssl_ctx;
221
0
    uint64_t ssl_opts;
222
223
0
    ogs_assert(key_file);
224
0
    ogs_assert(cert_file);
225
226
0
    ssl_ctx = SSL_CTX_new(TLS_server_method());
227
0
    if (!ssl_ctx) {
228
0
        ogs_error("Could not create SSL/TLS context: %s", ERR_error_string(ERR_get_error(), NULL));
229
0
        return NULL;
230
0
    }
231
232
    /* Set key log files for each SSL_CTX */
233
0
    if (sslkeylog_file) {
234
        /* Ensure app data is set for SSL objects */
235
0
        SSL_CTX_set_app_data(ssl_ctx, sslkeylog_file);
236
0
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
237
        /* Set the SSL Key Log callback */
238
0
        SSL_CTX_set_keylog_callback(ssl_ctx, ogs_sbi_keylog_callback);
239
0
#endif
240
0
    }
241
242
0
    ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
243
0
                  SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
244
0
                  SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
245
0
                  SSL_OP_SINGLE_ECDH_USE | SSL_OP_SINGLE_DH_USE |
246
0
                  SSL_OP_CIPHER_SERVER_PREFERENCE
247
0
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
248
                  // The reason for disabling built-in anti-replay in
249
                  // OpenSSL is that it only works if client gets back
250
                  // to the same server.  The freshness check
251
                  // described in
252
                  // https://tools.ietf.org/html/rfc8446#section-8.3
253
                  // is still performed.
254
0
                  | SSL_OP_NO_ANTI_REPLAY
255
0
#endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */
256
0
        ;
257
258
259
0
    SSL_CTX_set_options(ssl_ctx, ssl_opts);
260
261
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
262
    if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) {
263
        ogs_error("SSL_CTX_set1_curves_list failed: %s", ERR_error_string(ERR_get_error(), NULL));
264
        return NULL;
265
    }
266
#endif /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */
267
268
0
    SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
269
0
    SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
270
271
0
    if (SSL_CTX_set_default_verify_paths(ssl_ctx) != 1) {
272
0
        ogs_warn("Could not load system trusted ca certificates: %s",
273
0
                ERR_error_string(ERR_get_error(), NULL));
274
0
    }
275
276
0
#define OGS_TLS_MIN_VERSION TLS1_VERSION
277
0
#ifdef TLS1_3_VERSION
278
0
#define OGS_TLS_MAX_VERSION TLS1_3_VERSION
279
#else  /* !TLS1_3_VERSION */
280
#define OGS_TLS_MAX_VERSION TLS1_2_VERSION
281
#endif /* TLS1_3_VERSION */
282
0
    if (ssl_ctx_set_proto_versions(
283
0
                ssl_ctx, OGS_TLS_MIN_VERSION, OGS_TLS_MAX_VERSION) != 0) {
284
0
        ogs_error("Could not set TLS versions [%d:%d]",
285
0
                    OGS_TLS_MIN_VERSION, OGS_TLS_MAX_VERSION);
286
0
        return NULL;
287
0
    }
288
289
0
#define DEFAULT_CIPHER_LIST \
290
0
    "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-" \
291
0
    "AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-" \
292
0
    "POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-" \
293
0
    "AES256-GCM-SHA384"
294
0
    if (SSL_CTX_set_cipher_list(ssl_ctx, DEFAULT_CIPHER_LIST) == 0) {
295
0
        ogs_error("%s", ERR_error_string(ERR_get_error(), NULL));
296
0
        return NULL;
297
0
    }
298
299
0
    if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
300
0
        ogs_error("Could not read private key file - key_file=%s", key_file);
301
0
        return NULL;
302
0
    }
303
0
    if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
304
0
        ogs_error("Could not read certificate file - cert_file=%s ", cert_file);
305
0
        return NULL;
306
0
    }
307
0
    if (SSL_CTX_check_private_key(ssl_ctx) != 1) {
308
0
        ogs_error("SSL_CTX_check_private_key failed: %s",
309
0
                ERR_error_string(ERR_get_error(), NULL));
310
0
        return NULL;
311
0
    }
312
313
0
#ifndef OPENSSL_NO_NEXTPROTONEG
314
0
    SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
315
0
#endif /* !OPENSSL_NO_NEXTPROTONEG */
316
317
0
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
318
0
    SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
319
0
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
320
321
0
    return ssl_ctx;
322
0
}
323
324
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
325
0
{
326
0
    if (!preverify_ok) {
327
0
        int err = X509_STORE_CTX_get_error(ctx);
328
0
        int depth = X509_STORE_CTX_get_error_depth(ctx);
329
0
        if (err == X509_V_ERR_CERT_HAS_EXPIRED && depth == 0) {
330
0
            ogs_error("The client certificate has expired, but is accepted by "
331
0
                        "configuration");
332
0
            return 1;
333
0
        }
334
0
        ogs_error("client certificate verify error:num=%d:%s:depth=%d",
335
0
                err, X509_verify_cert_error_string(err), depth);
336
0
    }
337
0
    return preverify_ok;
338
0
}
339
340
static int server_start(ogs_sbi_server_t *server,
341
        int (*cb)(ogs_sbi_request_t *request, void *data))
342
0
{
343
0
    char buf[OGS_ADDRSTRLEN];
344
0
    ogs_sock_t *sock = NULL;
345
0
    ogs_sockaddr_t *addr = NULL;
346
0
    char *hostname = NULL;
347
348
0
    addr = server->node.addr;
349
0
    ogs_assert(addr);
350
351
    /* Create SSL CTX */
352
0
    if (server->scheme == OpenAPI_uri_scheme_https) {
353
354
0
        server->ssl_ctx = create_ssl_ctx(
355
0
                server->private_key, server->cert, server->sslkeylog);
356
0
        if (!server->ssl_ctx) {
357
0
            ogs_error("Cannot create SSL CTX");
358
0
            return OGS_ERROR;
359
0
        }
360
361
0
        if (server->verify_client_cacert) {
362
0
            char *context = NULL;
363
0
            STACK_OF(X509_NAME) *cert_names = NULL;
364
365
0
            if (SSL_CTX_load_verify_locations(
366
0
                        server->ssl_ctx,
367
0
                        server->verify_client_cacert, NULL) != 1) {
368
0
                ogs_error("Could not load trusted ca certificates from %s:%s",
369
0
                        server->verify_client_cacert,
370
0
                        ERR_error_string(ERR_get_error(), NULL));
371
372
0
                SSL_CTX_free(server->ssl_ctx);
373
374
0
                return OGS_ERROR;
375
0
            }
376
377
            /*
378
             * It is heard that SSL_CTX_load_verify_locations() may leave
379
             * error even though it returns success. See
380
             * http://forum.nginx.org/read.php?29,242540
381
             */
382
0
            cert_names = SSL_load_client_CA_file(server->verify_client_cacert);
383
0
            if (!cert_names) {
384
0
                ogs_error("Could not load ca certificates from %s:%s",
385
0
                    server->verify_client_cacert,
386
0
                    ERR_error_string(ERR_get_error(), NULL));
387
388
0
                SSL_CTX_free(server->ssl_ctx);
389
390
0
                return OGS_ERROR;
391
0
            }
392
0
            SSL_CTX_set_client_CA_list(server->ssl_ctx, cert_names);
393
394
0
            if (server->verify_client)
395
0
                SSL_CTX_set_verify(
396
0
                        server->ssl_ctx,
397
0
                        SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
398
0
                        SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
399
0
                        verify_callback);
400
401
0
            ogs_assert(server->id >= OGS_MIN_POOL_ID &&
402
0
                    server->id <= OGS_MAX_POOL_ID);
403
0
            context = ogs_msprintf("%d", server->id);
404
0
            if (!context) {
405
0
                ogs_error("ogs_sbi_server_id_context() failed");
406
407
0
                SSL_CTX_free(server->ssl_ctx);
408
409
0
                return OGS_ERROR;
410
0
            }
411
412
0
            if (!SSL_CTX_set_session_id_context(
413
0
                        server->ssl_ctx,
414
0
                        (unsigned char *)context, strlen(context))) {
415
0
                ogs_error("SSL_CTX_set_session_id_context() failed");
416
417
0
                ogs_free(context);
418
0
                SSL_CTX_free(server->ssl_ctx);
419
420
0
                return OGS_ERROR;
421
0
            }
422
423
0
            ogs_free(context);
424
0
        }
425
0
    }
426
427
0
    sock = ogs_tcp_server(addr, server->node.option);
428
0
    if (!sock) {
429
0
        ogs_error("Cannot start SBI server");
430
431
0
        if (server->ssl_ctx)
432
0
            SSL_CTX_free(server->ssl_ctx);
433
434
0
        return OGS_ERROR;
435
0
    }
436
437
0
    server->node.sock = sock;
438
439
    /* Setup callback function */
440
0
    server->cb = cb;
441
442
    /* Setup poll for server listening socket */
443
0
    server->node.poll = ogs_pollset_add(ogs_app()->pollset,
444
0
            OGS_POLLIN, sock->fd, accept_handler, server);
445
0
    ogs_assert(server->node.poll);
446
447
0
    hostname = ogs_gethostname(addr);
448
0
    if (hostname)
449
0
        ogs_info("nghttp2_server(%s) [%s://%s]:%d",
450
0
                server->interface ? server->interface : "",
451
0
                server->ssl_ctx ? "https" : "http",
452
0
                hostname, OGS_PORT(addr));
453
0
    else
454
0
        ogs_info("nghttp2_server(%s) [%s://%s]:%d",
455
0
                server->interface ? server->interface : "",
456
0
                server->ssl_ctx ? "https" : "http",
457
0
                OGS_ADDR(addr, buf), OGS_PORT(addr));
458
459
0
    return OGS_OK;
460
0
}
461
462
/* Gracefully shutdown the server by sending GOAWAY to each session. */
463
static void server_graceful_shutdown(ogs_sbi_server_t *server)
464
0
{
465
0
    ogs_sbi_session_t *sbi_sess = NULL;
466
0
    ogs_sbi_session_t *next_sbi_sess = NULL;
467
0
    int rv;
468
469
    /* Iterate over all active sessions in the server. */
470
0
    ogs_list_for_each_safe(&server->session_list, next_sbi_sess, sbi_sess) {
471
        /* Submit a GOAWAY frame using the last stream ID. */
472
0
        rv = nghttp2_submit_goaway(sbi_sess->session,
473
0
                                   NGHTTP2_FLAG_NONE,
474
0
                                   sbi_sess->last_stream_id,
475
0
                                   NGHTTP2_NO_ERROR,
476
0
                                   NULL, 0);
477
0
        if (rv != 0) {
478
0
            ogs_error("nghttp2_submit_goaway() failed (%d:%s)",
479
0
                      rv, nghttp2_strerror(rv));
480
0
        }
481
482
        /* Send the GOAWAY frame to the client. */
483
0
        if (session_send(sbi_sess) != OGS_OK) {
484
0
            ogs_error("session_send() failed during graceful shutdown");
485
0
        }
486
0
    }
487
0
}
488
489
static void server_stop(ogs_sbi_server_t *server)
490
0
{
491
0
    ogs_assert(server);
492
493
    /* Free SSL CTX */
494
0
    if (server->ssl_ctx)
495
0
        SSL_CTX_free(server->ssl_ctx);
496
497
0
    if (server->node.poll)
498
0
        ogs_pollset_remove(server->node.poll);
499
500
0
    if (server->node.sock)
501
0
        ogs_sock_destroy(server->node.sock);
502
503
0
    session_remove_all(server);
504
0
}
505
506
static void add_header(nghttp2_nv *nv, const char *key, const char *value)
507
0
{
508
0
    nv->name = (uint8_t *)key;
509
0
    nv->namelen = strlen(key);
510
0
    nv->value = (uint8_t *)value;
511
0
    nv->valuelen = strlen(value);
512
0
    nv->flags = NGHTTP2_NV_FLAG_NONE;
513
0
}
514
515
static char status_string[600][4] = {
516
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
517
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
518
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
519
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
520
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
521
 "100", "101", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
522
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
523
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
524
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
525
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
526
 "200", "201", "202", "203", "204", "205", "206", "", "", "", "", "", "", "", "", "", "", "", "", "",
527
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
528
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
529
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
530
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
531
 "300", "301", "302", "303", "304", "305", "306", "307", "308", "", "", "", "", "", "", "", "", "", "", "",
532
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
533
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
534
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
535
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
536
 "400", "401", "402", "403", "404", "405", "406", "407", "408", "409",
537
 "410", "411", "412", "413", "414", "415", "416", "417", "", "",
538
 "", "421", "", "", "", "", "426", "", "428", "429", "", "431", "", "", "", "", "", "", "", "",
539
 "", "", "", "", "", "", "", "", "", "", "", "451", "", "", "", "", "", "", "", "",
540
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
541
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
542
 "500", "501", "502", "503", "504", "505", "", "", "", "", "", "511", "", "", "", "", "", "", "", "",
543
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
544
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
545
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
546
 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
547
};
548
549
0
#define DATE_STRLEN 128
550
static char *get_date_string(char *date)
551
0
{
552
0
    static const char *const days[] = {
553
0
        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
554
0
    };
555
0
    static const char *const mons[] = {
556
0
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
557
0
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
558
0
    };
559
560
0
    ogs_assert(date);
561
562
0
    struct tm tm;
563
0
    ogs_gmtime(ogs_time_sec(ogs_time_now()), &tm);
564
565
0
    ogs_snprintf(date, DATE_STRLEN, "%3s, %02u %3s %04u %02u:%02u:%02u GMT",
566
0
            days[tm.tm_wday % 7],
567
0
            (unsigned int)tm.tm_mday,
568
0
            mons[tm.tm_mon % 12],
569
0
            (unsigned int)(1900 + tm.tm_year),
570
0
            (unsigned int)tm.tm_hour,
571
0
            (unsigned int)tm.tm_min,
572
0
            (unsigned int)tm.tm_sec);
573
574
0
    return date;
575
0
}
576
577
static ssize_t response_read_callback(nghttp2_session *session,
578
                                      int32_t stream_id,
579
                                      uint8_t *buf, size_t length,
580
                                      uint32_t *data_flags,
581
                                      nghttp2_data_source *source,
582
                                      void *user_data)
583
0
{
584
0
#if USE_SEND_DATA_WITH_NO_COPY
585
0
    int rv;
586
0
#endif
587
588
0
    ogs_sbi_response_t *response = NULL;
589
0
    ogs_sbi_stream_t *stream = NULL;
590
591
0
    ogs_assert(session);
592
593
0
    stream = nghttp2_session_get_stream_user_data(session, stream_id);
594
0
    if (!stream) {
595
0
        ogs_error("no stream [%d]", stream_id);
596
0
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
597
0
    }
598
599
0
    ogs_assert(source);
600
0
    response = source->ptr;
601
0
    ogs_assert(response);
602
603
0
    ogs_assert(response->http.content);
604
0
    ogs_assert(response->http.content_length);
605
606
0
#if USE_SEND_DATA_WITH_NO_COPY
607
0
    *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
608
#else
609
    memcpy(buf, response->http.content, response->http.content_length);
610
#endif
611
612
0
    *data_flags |= NGHTTP2_DATA_FLAG_EOF;
613
614
0
#if USE_SEND_DATA_WITH_NO_COPY
615
0
    rv = nghttp2_session_get_stream_remote_close(session, stream_id);
616
0
    if (rv == 0) {
617
0
        ogs_warn("nghttp2_session_get_stream_remote_close() failed");
618
0
        nghttp2_submit_rst_stream(
619
0
                session, NGHTTP2_FLAG_NONE, stream_id, NGHTTP2_NO_ERROR);
620
0
    } else if (rv != 1) {
621
0
        ogs_error("nghttp2_session_get_stream_remote_close() failed[%d]", rv);
622
0
    }
623
0
#endif
624
625
0
    return response->http.content_length;
626
0
}
627
628
static bool server_send_rspmem_persistent(
629
        ogs_sbi_stream_t *stream, ogs_sbi_response_t *response)
630
0
{
631
0
    ogs_sbi_session_t *sbi_sess = NULL;
632
0
    ogs_sock_t *sock = NULL;
633
0
    ogs_socket_t fd = INVALID_SOCKET;
634
635
0
    ogs_hash_index_t *hi;
636
0
    nghttp2_nv *nva;
637
0
    size_t nvlen;
638
0
    int i, rv;
639
0
    char datebuf[DATE_STRLEN];
640
0
    char srv_version[128];
641
0
    char clen[128];
642
643
0
    ogs_assert(response);
644
645
0
    if (response->status >= 600) {
646
0
        ogs_error("Invalid response status [%d]", response->status);
647
0
        return false;
648
0
    }
649
650
0
    ogs_assert(stream);
651
0
    sbi_sess = stream->session;
652
0
    ogs_assert(sbi_sess);
653
0
    ogs_assert(sbi_sess->session);
654
655
0
    sock = sbi_sess->sock;
656
0
    ogs_assert(sock);
657
0
    fd = sock->fd;
658
0
    ogs_assert(fd != INVALID_SOCKET); /* Check if session is removed */
659
660
0
    nvlen = 3; /* :status && server && date */
661
662
0
    for (hi = ogs_hash_first(response->http.headers);
663
0
            hi; hi = ogs_hash_next(hi))
664
0
        nvlen++;
665
666
0
    if (response->http.content && response->http.content_length)
667
0
        nvlen++;
668
669
0
    nva = ogs_calloc(nvlen, sizeof(nghttp2_nv));
670
0
    if (!nva) {
671
0
        ogs_error("ogs_calloc() failed");
672
0
        return false;
673
0
    }
674
675
0
    i = 0;
676
677
0
    if (strlen(status_string[response->status]) != 3) {
678
0
        ogs_fatal("response status [%d]", response->status);
679
0
        ogs_fatal("status string [%s]", status_string[response->status]);
680
0
        ogs_assert_if_reached();
681
0
        return false;
682
0
    }
683
684
0
    add_header(&nva[i++], ":status", status_string[response->status]);
685
686
0
    ogs_snprintf(srv_version, sizeof(srv_version),
687
0
            "Open5GS %s", ogs_app()->version ? ogs_app()->version : "TEST");
688
0
    add_header(&nva[i++], "server", srv_version);
689
0
    add_header(&nva[i++], "date", get_date_string(datebuf));
690
691
0
    if (response->http.content && response->http.content_length) {
692
0
        ogs_snprintf(clen, sizeof(clen),
693
0
                "%d", (int)response->http.content_length);
694
0
        add_header(&nva[i++], "content-length", clen);
695
0
    }
696
697
0
    for (hi = ogs_hash_first(response->http.headers);
698
0
            hi; hi = ogs_hash_next(hi)) {
699
0
        add_header(&nva[i++], ogs_hash_this_key(hi), ogs_hash_this_val(hi));
700
0
    }
701
702
0
    ogs_debug("STATUS [%d]", response->status);
703
704
0
    if (response->http.content && response->http.content_length) {
705
0
        nghttp2_data_provider data_prd;
706
707
0
        data_prd.source.ptr = response;
708
0
        data_prd.read_callback = response_read_callback;
709
710
0
        ogs_debug("SENDING...: %d", (int)response->http.content_length);
711
0
        ogs_debug("%s", response->http.content);
712
713
0
        rv = nghttp2_submit_response(sbi_sess->session,
714
0
                stream->stream_id, nva, nvlen, &data_prd);
715
0
    } else {
716
0
        rv = nghttp2_submit_response(sbi_sess->session,
717
0
                stream->stream_id, nva, nvlen, NULL);
718
0
    }
719
720
0
    if (rv != OGS_OK) {
721
0
        ogs_error("nghttp2_submit_response(%d) failed (%d:%s)",
722
0
                    (int)response->http.content_length,
723
0
                    rv, nghttp2_strerror(rv));
724
0
        nghttp2_submit_rst_stream(
725
0
                sbi_sess->session, NGHTTP2_FLAG_NONE, stream->stream_id, rv);
726
0
    }
727
728
0
    if (session_send(sbi_sess) != OGS_OK) {
729
0
        ogs_error("session_send() failed");
730
0
        session_remove(sbi_sess);
731
0
    }
732
733
0
    ogs_free(nva);
734
735
0
    return true;
736
0
}
737
738
static bool server_send_response(
739
        ogs_sbi_stream_t *stream, ogs_sbi_response_t *response)
740
0
{
741
0
    bool rc;
742
743
0
    ogs_assert(response);
744
745
0
    rc = server_send_rspmem_persistent(stream, response);
746
747
0
    ogs_sbi_response_free(response);
748
749
0
    return rc;
750
0
}
751
752
static ogs_sbi_server_t *server_from_stream(ogs_sbi_stream_t *stream)
753
0
{
754
0
    ogs_sbi_session_t *sbi_sess = NULL;
755
756
0
    ogs_assert(stream);
757
0
    sbi_sess = stream->session;
758
0
    ogs_assert(sbi_sess);
759
0
    ogs_assert(sbi_sess->server);
760
761
0
    return sbi_sess->server;
762
0
}
763
764
static ogs_sbi_stream_t *stream_add(
765
        ogs_sbi_session_t *sbi_sess, int32_t stream_id)
766
0
{
767
0
    ogs_sbi_stream_t *stream = NULL;
768
769
0
    ogs_assert(sbi_sess);
770
771
0
    ogs_pool_id_calloc(&stream_pool, &stream);
772
0
    if (!stream) {
773
0
        ogs_error("ogs_pool_id_calloc() failed");
774
0
        return NULL;
775
0
    }
776
777
0
    stream->request = ogs_sbi_request_new();
778
0
    if (!stream->request) {
779
0
        ogs_error("ogs_sbi_request_new() failed");
780
0
        ogs_pool_id_free(&stream_pool, stream);
781
0
        return NULL;
782
0
    }
783
784
0
    stream->stream_id = stream_id;
785
0
    sbi_sess->last_stream_id = stream_id;
786
787
0
    stream->session = sbi_sess;
788
789
0
    ogs_list_init(&stream->xact_list);
790
791
0
    ogs_list_add(&sbi_sess->stream_list, stream);
792
793
0
    return stream;
794
0
}
795
796
static void xact_attach(ogs_sbi_stream_t *stream, ogs_sbi_xact_t *xact)
797
0
{
798
0
    ogs_assert(stream);
799
0
    ogs_assert(xact);
800
801
    /*
802
     * Invariant: the server-layer wrapper (ogs_sbi_server_attach_xact)
803
     * already filtered out the already-attached case. Reaching the
804
     * backend with to_stream_list set is a programming error.
805
     */
806
0
    ogs_assert(!xact->to_stream_list);
807
808
    /*
809
     * Cache the list head so xact_detach() can unlink in O(1)
810
     * without re-resolving the stream from assoc_stream_id.
811
     * to_stream_list serves as both attachment flag and cached head.
812
     */
813
0
    ogs_list_add(&stream->xact_list, &xact->to_stream_node);
814
0
    xact->to_stream_list = &stream->xact_list;
815
0
}
816
817
static void xact_detach(ogs_sbi_xact_t *xact)
818
0
{
819
0
    ogs_assert(xact);
820
821
    /*
822
     * Invariant: the server-layer wrapper (ogs_sbi_server_detach_xact)
823
     * already filtered out the not-attached case. Reaching the
824
     * backend with to_stream_list cleared is a programming error.
825
     */
826
0
    ogs_assert(xact->to_stream_list);
827
828
0
    ogs_list_remove(xact->to_stream_list, &xact->to_stream_node);
829
830
0
    xact->to_stream_list = NULL;
831
0
    xact->assoc_stream_id = OGS_INVALID_POOL_ID;
832
0
}
833
834
/*
835
 * Cancel every outbound SBI transaction that was triggered by this
836
 * stream. Without this, ogs_sbi_xact_remove() and its response timer
837
 * would only be reached when the upstream NF responds or the SBI
838
 * client wait timer expires; a peer that rapidly resets streams
839
 * while the upstream NF stalls would pile up those timers until the
840
 * pool is exhausted (the crash signature in issues #4472 / #4473).
841
 *
842
 * ogs_sbi_xact_remove() invokes xact_detach() internally, which is
843
 * what unlinks the node from this list. ogs_list_for_each_entry_safe
844
 * caches the next pointer before the body runs, so detach-during-
845
 * iteration is well-defined.
846
 */
847
static void stream_remove_xact_all(ogs_sbi_stream_t *stream)
848
0
{
849
0
    ogs_sbi_xact_t *xact = NULL, *next_xact = NULL;
850
851
0
    ogs_assert(stream);
852
853
0
    ogs_list_for_each_entry_safe(
854
0
            &stream->xact_list, next_xact, xact, to_stream_node) {
855
        /*
856
         * Logged at error level so the cancellation shows up in
857
         * production traces alongside the upstream NF activity that
858
         * was abandoned. Useful for diagnosing #4472/#4473 style
859
         * patterns and any future regression where a peer resets
860
         * streams while upstream NFs are slow.
861
         */
862
0
        ogs_error("Canceling pending outbound SBI transaction "
863
0
                "on HTTP/2 stream close [xact:%d,stream:%d,service:%s]",
864
0
                (int)xact->id, stream->stream_id,
865
0
                OpenAPI_service_name_ToString(xact->service_name));
866
0
        ogs_sbi_xact_remove(xact);
867
0
    }
868
0
}
869
870
static void stream_remove(ogs_sbi_stream_t *stream)
871
0
{
872
0
    ogs_sbi_session_t *sbi_sess = NULL;
873
874
0
    ogs_assert(stream);
875
0
    sbi_sess = stream->session;
876
0
    ogs_assert(sbi_sess);
877
878
0
    ogs_list_remove(&sbi_sess->stream_list, stream);
879
880
0
    stream_remove_xact_all(stream);
881
882
0
    ogs_assert(stream->request);
883
0
    ogs_sbi_request_free(stream->request);
884
885
0
    ogs_pool_id_free(&stream_pool, stream);
886
0
}
887
888
static void stream_remove_all(ogs_sbi_session_t *sbi_sess)
889
0
{
890
0
    ogs_sbi_stream_t *stream = NULL, *next_stream = NULL;
891
892
0
    ogs_assert(sbi_sess);
893
894
0
    ogs_list_for_each_safe(&sbi_sess->stream_list, next_stream, stream)
895
0
        stream_remove(stream);
896
0
}
897
898
static ogs_pool_id_t id_from_stream(ogs_sbi_stream_t *stream)
899
0
{
900
0
    ogs_assert(stream);
901
0
    return stream->id;
902
0
}
903
904
static void *stream_find_by_id(ogs_pool_id_t id)
905
0
{
906
0
    return ogs_pool_find_by_id(&stream_pool, id);
907
0
}
908
909
static ogs_sbi_session_t *session_add(
910
        ogs_sbi_server_t *server, ogs_sock_t *sock)
911
0
{
912
0
    ogs_sbi_session_t *sbi_sess = NULL;
913
914
0
    ogs_assert(server);
915
0
    ogs_assert(sock);
916
917
0
    ogs_pool_alloc(&session_pool, &sbi_sess);
918
0
    if (!sbi_sess) {
919
0
        ogs_error("ogs_pool_alloc() failed");
920
0
        return NULL;
921
0
    }
922
0
    memset(sbi_sess, 0, sizeof(ogs_sbi_session_t));
923
924
0
    sbi_sess->server = server;
925
0
    sbi_sess->sock = sock;
926
927
0
    sbi_sess->addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
928
0
    if (!sbi_sess->addr) {
929
0
        ogs_error("ogs_calloc() failed");
930
0
        ogs_pool_free(&session_pool, sbi_sess);
931
0
        return NULL;
932
0
    }
933
0
    memcpy(sbi_sess->addr, &sock->remote_addr, sizeof(ogs_sockaddr_t));
934
935
0
    if (server->ssl_ctx) {
936
0
        char *context = NULL;
937
938
0
        sbi_sess->ssl = SSL_new(server->ssl_ctx);
939
0
        if (!sbi_sess->ssl) {
940
0
            ogs_error("SSL_new() failed");
941
0
            ogs_free(sbi_sess->addr);
942
0
            ogs_pool_free(&session_pool, sbi_sess);
943
0
            return NULL;
944
0
        }
945
946
0
        context = ogs_msprintf("%d",
947
0
                (int)ogs_pool_index(&session_pool, sbi_sess));
948
0
        if (!context) {
949
0
            ogs_error("No memory for session id context");
950
0
            SSL_free(sbi_sess->ssl);
951
0
            ogs_free(sbi_sess->addr);
952
0
            ogs_pool_free(&session_pool, sbi_sess);
953
0
            return NULL;
954
0
        }
955
956
0
        if (!SSL_set_session_id_context(
957
0
                    sbi_sess->ssl, (unsigned char *)context, strlen(context))) {
958
0
            ogs_error("SSL_set_session_id_context() failed");
959
0
            ogs_free(context);
960
0
            ogs_free(sbi_sess->addr);
961
0
            SSL_free(sbi_sess->ssl);
962
0
            ogs_pool_free(&session_pool, sbi_sess);
963
0
            return NULL;
964
0
        }
965
966
0
        ogs_free(context);
967
0
    }
968
969
0
    ogs_list_add(&server->session_list, sbi_sess);
970
971
0
    return sbi_sess;
972
0
}
973
974
static void session_remove(ogs_sbi_session_t *sbi_sess)
975
0
{
976
0
    ogs_sbi_server_t *server = NULL;
977
0
    ogs_pkbuf_t *pkbuf = NULL, *next_pkbuf = NULL;
978
979
0
    ogs_assert(sbi_sess);
980
0
    server = sbi_sess->server;
981
0
    ogs_assert(server);
982
983
0
    ogs_list_remove(&server->session_list, sbi_sess);
984
985
0
    if (sbi_sess->ssl)
986
0
        SSL_free(sbi_sess->ssl);
987
988
0
    stream_remove_all(sbi_sess);
989
0
    nghttp2_session_del(sbi_sess->session);
990
991
0
    if (sbi_sess->poll.read)
992
0
        ogs_pollset_remove(sbi_sess->poll.read);
993
994
0
    if (sbi_sess->poll.write)
995
0
        ogs_pollset_remove(sbi_sess->poll.write);
996
997
0
    ogs_list_for_each_safe(&sbi_sess->write_queue, next_pkbuf, pkbuf) {
998
0
        ogs_list_remove(&sbi_sess->write_queue, pkbuf);
999
0
        ogs_pkbuf_free(pkbuf);
1000
0
    }
1001
1002
0
    ogs_assert(sbi_sess->addr);
1003
0
    ogs_free(sbi_sess->addr);
1004
1005
0
    ogs_assert(sbi_sess->sock);
1006
0
    ogs_sock_destroy(sbi_sess->sock);
1007
1008
0
    ogs_pool_free(&session_pool, sbi_sess);
1009
0
}
1010
1011
static void session_remove_all(ogs_sbi_server_t *server)
1012
0
{
1013
0
    ogs_sbi_session_t *sbi_sess = NULL, *next_sbi_sess = NULL;
1014
1015
0
    ogs_assert(server);
1016
1017
0
    ogs_list_for_each_safe(&server->session_list, next_sbi_sess, sbi_sess)
1018
0
        session_remove(sbi_sess);
1019
0
}
1020
1021
static void accept_handler(short when, ogs_socket_t fd, void *data)
1022
0
{
1023
0
    ogs_sbi_server_t *server = data;
1024
0
    ogs_sbi_session_t *sbi_sess = NULL;
1025
0
    ogs_sock_t *sock = NULL;
1026
0
    ogs_sock_t *new = NULL;
1027
1028
0
    int on;
1029
1030
0
    ogs_assert(data);
1031
0
    ogs_assert(fd != INVALID_SOCKET);
1032
1033
0
    sock = server->node.sock;
1034
1035
0
    new = ogs_sock_accept(sock);
1036
0
    if (!new) {
1037
0
        ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "accept() failed");
1038
0
        return;
1039
0
    }
1040
0
    ogs_assert(new->fd != INVALID_SOCKET);
1041
1042
0
    on = 1;
1043
0
    if (setsockopt(new->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) {
1044
0
        ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
1045
0
                "setsockopt() for SCTP_NODELAY failed");
1046
0
        ogs_sock_destroy(new);
1047
0
        return;
1048
0
    }
1049
1050
0
    sbi_sess = session_add(server, new);
1051
0
    ogs_assert(sbi_sess);
1052
1053
0
    if (sbi_sess->ssl) {
1054
0
        int err;
1055
0
        SSL_set_fd(sbi_sess->ssl, new->fd);
1056
0
        SSL_set_accept_state(sbi_sess->ssl);
1057
0
        err = SSL_accept(sbi_sess->ssl);
1058
0
        if (err <= 0) {
1059
0
            ogs_error("SSL_accept failed [%s]", ERR_error_string(ERR_get_error(), NULL));
1060
0
            session_remove(sbi_sess);
1061
0
            return;
1062
0
        }
1063
0
    }
1064
1065
0
    sbi_sess->poll.read = ogs_pollset_add(ogs_app()->pollset,
1066
0
        OGS_POLLIN, new->fd, recv_handler, sbi_sess);
1067
0
    ogs_assert(sbi_sess->poll.read);
1068
1069
0
    if (session_set_callbacks(sbi_sess) != OGS_OK ||
1070
0
        session_send_preface(sbi_sess) != OGS_OK) {
1071
0
        ogs_error("session_add() failed");
1072
0
        session_remove(sbi_sess);
1073
0
    }
1074
0
}
1075
1076
static void recv_handler(short when, ogs_socket_t fd, void *data)
1077
0
{
1078
0
    char buf[OGS_ADDRSTRLEN];
1079
0
    ogs_sockaddr_t *addr = NULL;
1080
1081
0
    ogs_sbi_session_t *sbi_sess = data;
1082
0
    ogs_pkbuf_t *pkbuf = NULL;
1083
0
    ssize_t readlen;
1084
0
    int n;
1085
1086
0
    ogs_assert(sbi_sess);
1087
0
    ogs_assert(fd != INVALID_SOCKET);
1088
0
    addr = sbi_sess->addr;
1089
0
    ogs_assert(addr);
1090
1091
0
    pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
1092
0
    ogs_assert(pkbuf);
1093
1094
0
    if (sbi_sess->ssl)
1095
0
        n = SSL_read(sbi_sess->ssl, pkbuf->data, OGS_MAX_SDU_LEN);
1096
0
    else
1097
0
        n = ogs_recv(fd, pkbuf->data, OGS_MAX_SDU_LEN, 0);
1098
1099
0
    if (n > 0) {
1100
0
        ogs_pkbuf_put(pkbuf, n);
1101
1102
0
        ogs_assert(sbi_sess->session);
1103
0
        readlen = nghttp2_session_mem_recv(
1104
0
                sbi_sess->session, pkbuf->data, pkbuf->len);
1105
0
        if (readlen < 0) {
1106
0
            ogs_error("nghttp2_session_mem_recv() failed (%d:%s)",
1107
0
                        (int)readlen, nghttp2_strerror((int)readlen));
1108
0
            session_remove(sbi_sess);
1109
0
        } else {
1110
            /*
1111
             * Issues #2385
1112
             *
1113
             * Nokia AMF is sending GOAWAY because it didn't get
1114
             * ACK SETTINGS packet for the SETTINGS it set,
1115
             * this is according to http2 RFC, all settings must be
1116
             * ACK or connection will be dropped.
1117
             *
1118
             * Open5GS is not ACKing pure settings packets,
1119
             * looks like it is waiting for a header
1120
             * like POST/GET first to trigger
1121
             * sending settings ACK and then headers reply.
1122
             */
1123
1124
            /*
1125
             * [SOLVED]
1126
             *
1127
             * Whether or not to send a Setting ACK is determined
1128
             * by the nghttp2 library. Therefore, when nghttp2 informs us
1129
             * that it want to send an SETTING frame with ACK
1130
             * by nghttp2_session_want_write(), we need to call session_send()
1131
             * directly to send it.
1132
             */
1133
0
            if (nghttp2_session_want_write(sbi_sess->session))
1134
0
                session_send(sbi_sess);
1135
0
        }
1136
0
    } else {
1137
0
        if (n < 0) {
1138
0
            if (errno != OGS_ECONNRESET)
1139
0
                ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
1140
0
                                "lost connection [%s]:%d",
1141
0
                                OGS_ADDR(addr, buf), OGS_PORT(addr));
1142
0
        } else if (n == 0) {
1143
0
            ogs_debug("connection closed [%s]:%d",
1144
0
                        OGS_ADDR(addr, buf), OGS_PORT(addr));
1145
0
        }
1146
1147
0
        session_remove(sbi_sess);
1148
0
    }
1149
1150
0
    ogs_pkbuf_free(pkbuf);
1151
0
}
1152
1153
static int on_frame_recv(nghttp2_session *session,
1154
                         const nghttp2_frame *frame, void *user_data);
1155
static int on_stream_close(nghttp2_session *session, int32_t stream_id,
1156
                           uint32_t error_code, void *user_data);
1157
static int on_header(nghttp2_session *session,
1158
                     const nghttp2_frame *frame,
1159
                     nghttp2_rcbuf *name, nghttp2_rcbuf *value,
1160
                     uint8_t flags, void *user_data);
1161
static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
1162
                              int32_t stream_id, const uint8_t *data,
1163
                              size_t len, void *user_data);
1164
static int error_callback(nghttp2_session *session,
1165
                          const char *msg, size_t len, void *user_data);
1166
static int on_invalid_frame_recv(nghttp2_session *session,
1167
                                 const nghttp2_frame *frame,
1168
                                 int error_code, void *user_data);
1169
static int on_invalid_header(nghttp2_session *session,
1170
                             const nghttp2_frame *frame,
1171
                             const uint8_t *name, size_t namelen,
1172
                             const uint8_t *value, size_t valuelen,
1173
                             uint8_t flags, void *user_data);
1174
static int on_begin_frame(nghttp2_session *session,
1175
                          const nghttp2_frame_hd *hd, void *user_data);
1176
static int on_begin_headers(nghttp2_session *session,
1177
                            const nghttp2_frame *frame,
1178
                                     void *user_data);
1179
#if USE_SEND_DATA_WITH_NO_COPY
1180
static int on_send_data(nghttp2_session *session, nghttp2_frame *frame,
1181
                        const uint8_t *framehd, size_t length,
1182
                        nghttp2_data_source *source, void *user_data);
1183
#else
1184
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
1185
                             size_t length, int flags, void *user_data);
1186
#endif
1187
1188
static int session_set_callbacks(ogs_sbi_session_t *sbi_sess)
1189
0
{
1190
0
    int rv;
1191
0
    nghttp2_session_callbacks *callbacks = NULL;
1192
1193
0
    ogs_assert(sbi_sess);
1194
1195
0
    rv = nghttp2_session_callbacks_new(&callbacks);
1196
0
    if (rv != 0) {
1197
0
        ogs_error("nghttp2_session_callbacks_new() failed (%d:%s)",
1198
0
                    rv, nghttp2_strerror(rv));
1199
0
        return OGS_ERROR;
1200
0
    }
1201
1202
0
    nghttp2_session_callbacks_set_on_frame_recv_callback(
1203
0
            callbacks, on_frame_recv);
1204
1205
0
    nghttp2_session_callbacks_set_on_stream_close_callback(
1206
0
            callbacks, on_stream_close);
1207
1208
0
    nghttp2_session_callbacks_set_on_header_callback2(callbacks, on_header);
1209
1210
0
    nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
1211
0
            callbacks, on_data_chunk_recv);
1212
1213
0
    nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
1214
1215
0
    nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
1216
0
            callbacks, on_invalid_frame_recv);
1217
1218
0
    nghttp2_session_callbacks_set_on_invalid_header_callback(
1219
0
            callbacks, on_invalid_header);
1220
1221
0
    nghttp2_session_callbacks_set_on_begin_frame_callback(
1222
0
            callbacks, on_begin_frame);
1223
1224
0
    nghttp2_session_callbacks_set_on_begin_headers_callback(
1225
0
            callbacks, on_begin_headers);
1226
1227
0
#if USE_SEND_DATA_WITH_NO_COPY
1228
0
    nghttp2_session_callbacks_set_send_data_callback(callbacks, on_send_data);
1229
#else
1230
    nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
1231
#endif
1232
1233
0
    rv = nghttp2_session_server_new(&sbi_sess->session, callbacks, sbi_sess);
1234
0
    if (rv != 0) {
1235
0
        ogs_error("nghttp2_session_callbacks_new() failed (%d:%s)",
1236
0
                    rv, nghttp2_strerror(rv));
1237
0
        return OGS_ERROR;
1238
0
    }
1239
1240
0
    nghttp2_session_callbacks_del(callbacks);
1241
1242
0
    return OGS_OK;
1243
0
}
1244
1245
static int on_frame_recv(nghttp2_session *session,
1246
                         const nghttp2_frame *frame, void *user_data)
1247
0
{
1248
0
    int rv;
1249
0
    ogs_sbi_session_t *sbi_sess = user_data;
1250
1251
0
    ogs_sbi_server_t *server = NULL;
1252
0
    ogs_sbi_stream_t *stream = NULL;
1253
0
    ogs_sbi_request_t *request = NULL;
1254
1255
0
    ogs_assert(sbi_sess);
1256
0
    server = sbi_sess->server;
1257
0
    ogs_assert(server);
1258
0
    ogs_assert(server->cb);
1259
1260
0
    ogs_assert(session);
1261
0
    ogs_assert(frame);
1262
1263
0
    switch (frame->hd.type) {
1264
0
    case NGHTTP2_HEADERS:
1265
0
        stream = nghttp2_session_get_stream_user_data(
1266
0
                session, frame->hd.stream_id);
1267
0
        if (!stream) return 0;
1268
1269
0
        request = stream->request;
1270
0
        ogs_assert(request);
1271
1272
0
        if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
1273
0
            const char *expect100 =
1274
0
                ogs_sbi_header_get(request->http.headers, OGS_SBI_EXPECT);
1275
0
            if (expect100 && ogs_strcasecmp(expect100, "100-continue") == 0) {
1276
0
                nghttp2_nv nva;
1277
1278
0
                add_header(&nva, ":status", status_string[100]);
1279
0
                rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE,
1280
0
                           stream->stream_id, NULL, &nva, 1, NULL);
1281
0
                if (rv != 0) {
1282
0
                    ogs_error("nghttp2_submit_headers() failed (%d:%s)",
1283
0
                            rv, nghttp2_strerror(rv));
1284
0
                    nghttp2_submit_rst_stream(
1285
0
                            session, NGHTTP2_FLAG_NONE, stream->stream_id, rv);
1286
0
                    return 0;
1287
0
                }
1288
0
            }
1289
0
        }
1290
        /* fallthrough */
1291
0
        OGS_GNUC_FALLTHROUGH;
1292
1293
0
    case NGHTTP2_DATA:
1294
0
        stream = nghttp2_session_get_stream_user_data(
1295
0
                session, frame->hd.stream_id);
1296
0
        if (!stream) return 0;
1297
1298
0
        request = stream->request;
1299
0
        ogs_assert(request);
1300
1301
        /* HEADERS or DATA frame with +END_STREAM flag */
1302
0
        if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1303
0
            ogs_log_level_e level = OGS_LOG_DEBUG;
1304
1305
0
            if (stream->memory_overflow == true)
1306
0
                level = OGS_LOG_ERROR;
1307
1308
0
            ogs_log_message(level, 0,
1309
0
                    "[%s] %s", request->h.method, request->h.uri);
1310
1311
0
            if (request->http.content_length && request->http.content) {
1312
0
                ogs_log_message(level, 0,
1313
0
                        "RECEIVED: %d", (int)request->http.content_length);
1314
0
                ogs_log_message(level, 0, "%s", request->http.content);
1315
0
            }
1316
1317
0
            if (stream->memory_overflow == true) {
1318
0
                ogs_error("[DROP] Overflow");
1319
0
                break;
1320
0
            }
1321
1322
0
            if (server->cb(request,
1323
0
                        OGS_UINT_TO_POINTER(stream->id)) != OGS_OK) {
1324
0
                ogs_warn("server callback error");
1325
1326
                /* The callback may have sent a response and closed
1327
                 * the stream. */
1328
0
                stream = nghttp2_session_get_stream_user_data(
1329
0
                        session, frame->hd.stream_id);
1330
0
                if (!stream) {
1331
0
                    ogs_error("The server callback already sent a response "
1332
0
                            "but returned an error; it must return OGS_OK "
1333
0
                            "instead [%d]", frame->hd.stream_id);
1334
0
                    return 0;
1335
0
                }
1336
1337
0
                ogs_assert(true ==
1338
0
                    ogs_sbi_server_send_error(stream,
1339
0
                        OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL,
1340
0
                        "server callback error", NULL, NULL));
1341
1342
0
                return 0;
1343
0
            }
1344
0
        } else {
1345
            /* TODO : Need to implement the timeouf of reading STREAM */
1346
0
        }
1347
0
        break;
1348
0
    case NGHTTP2_SETTINGS:
1349
0
        ogs_debug("FLAGS(0x%x) [%s]",
1350
0
                frame->hd.flags,
1351
0
                frame->hd.flags & NGHTTP2_FLAG_ACK ? "ACK" : "NO-ACK");
1352
1353
0
        if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
1354
0
            sbi_sess->settings.max_concurrent_streams =
1355
0
                nghttp2_session_get_remote_settings(
1356
0
                    session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
1357
0
            sbi_sess->settings.enable_push =
1358
0
                nghttp2_session_get_remote_settings(
1359
0
                    session, NGHTTP2_SETTINGS_ENABLE_PUSH);
1360
0
            ogs_debug("MAX_CONCURRENT_STREAMS = %d",
1361
0
                sbi_sess->settings.max_concurrent_streams);
1362
0
            ogs_debug("ENABLE_PUSH = %s",
1363
0
                sbi_sess->settings.enable_push ? "TRUE" : "false");
1364
1365
0
            return 0;
1366
0
        }
1367
1368
        /*
1369
         * TODO:
1370
         *
1371
         * if Setting ACK received, need to stop Timer.
1372
         * Otherwise, we need to send NGHTTP2_GOAWAY
1373
         */
1374
0
        break;
1375
0
    case NGHTTP2_GOAWAY:
1376
#if 0 /* It is not neeed in other nghttp2 example */
1377
        rv = nghttp2_submit_goaway(
1378
             session, NGHTTP2_FLAG_NONE, sbi_sess->last_stream_id,
1379
             NGHTTP2_NO_ERROR, NULL, 0);
1380
        if (rv != 0) {
1381
            ogs_error("nghttp2_submit_goaway() failed (%d:%s)",
1382
                        rv, nghttp2_strerror(rv));
1383
            return OGS_ERROR;
1384
        }
1385
1386
        session_send(sbi_sess);
1387
#endif
1388
0
        ogs_info("GOAWAY received: last-stream-id=%d",
1389
0
                frame->goaway.last_stream_id);
1390
0
        ogs_info("error_code=%d", frame->goaway.error_code);
1391
0
        break;
1392
0
    case NGHTTP2_RST_STREAM:
1393
0
        ogs_info("RST_STREAM received: stream_id=%d", frame->hd.stream_id);
1394
0
        break;
1395
0
    case NGHTTP2_PING:
1396
0
        if (frame->hd.flags & NGHTTP2_FLAG_ACK)
1397
0
            ogs_info("PING ACK received");
1398
0
        break;
1399
0
    case NGHTTP2_PUSH_PROMISE:
1400
0
        ogs_info("PUSH_PROMISE recieved: stream_id=%d", frame->hd.stream_id);
1401
0
        ogs_info("promised_stream_id=%d",
1402
0
                frame->push_promise.promised_stream_id);
1403
0
        break;
1404
0
    default:
1405
0
        break;
1406
0
    }
1407
1408
0
    return 0;
1409
0
}
1410
1411
static int on_stream_close(nghttp2_session *session, int32_t stream_id,
1412
                           uint32_t error_code, void *user_data)
1413
0
{
1414
0
    ogs_sbi_stream_t *stream = NULL;
1415
1416
0
    ogs_assert(session);
1417
1418
0
    stream = nghttp2_session_get_stream_user_data(session, stream_id);
1419
0
    if (!stream) {
1420
0
        ogs_error("no stream [%d]", stream_id);
1421
0
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1422
0
    }
1423
1424
0
    if (error_code) {
1425
0
        ogs_error("on_stream_close_callback() failed (%d:%s)",
1426
0
                    error_code, nghttp2_http2_strerror(error_code));
1427
0
        nghttp2_submit_rst_stream(
1428
0
                session, NGHTTP2_FLAG_NONE, stream_id, error_code);
1429
0
    }
1430
1431
0
    ogs_debug("STREAM closed [%d]", stream_id);
1432
0
    stream_remove(stream);
1433
0
    return 0;
1434
0
}
1435
1436
static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
1437
                     nghttp2_rcbuf *name, nghttp2_rcbuf *value,
1438
                     uint8_t flags, void *user_data)
1439
0
{
1440
0
    ogs_sbi_session_t *sbi_sess = user_data;
1441
0
    ogs_sbi_stream_t *stream = NULL;
1442
0
    ogs_sbi_request_t *request = NULL;
1443
1444
0
    const char PATH[] = ":path";
1445
0
    const char METHOD[] = ":method";
1446
1447
0
    nghttp2_vec namebuf, valuebuf;
1448
0
    char *namestr = NULL, *valuestr = NULL;
1449
1450
0
    ogs_assert(session);
1451
0
    ogs_assert(frame);
1452
1453
0
    if (frame->hd.type != NGHTTP2_HEADERS ||
1454
0
        frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
1455
0
        return 0;
1456
0
    }
1457
1458
0
    stream = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
1459
0
    if (!stream) {
1460
0
        ogs_error("no stream [%d]", frame->hd.stream_id);
1461
0
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1462
0
    }
1463
1464
0
    ogs_assert(sbi_sess);
1465
1466
0
    request = stream->request;
1467
0
    ogs_assert(request);
1468
1469
0
    ogs_assert(name);
1470
0
    namebuf = nghttp2_rcbuf_get_buf(name);
1471
0
    ogs_assert(namebuf.base);
1472
0
    ogs_assert(namebuf.len);
1473
1474
0
    ogs_assert(value);
1475
0
    valuebuf = nghttp2_rcbuf_get_buf(value);
1476
0
    ogs_assert(valuebuf.base);
1477
1478
0
    if (valuebuf.len == 0) return 0;
1479
1480
0
    namestr = ogs_strndup((const char *)namebuf.base, namebuf.len);
1481
0
    ogs_assert(namestr);
1482
1483
0
    valuestr = ogs_strndup((const char *)valuebuf.base, valuebuf.len);
1484
0
    ogs_assert(valuestr);
1485
1486
0
    if (namebuf.len == sizeof(PATH) - 1 &&
1487
0
            memcmp(PATH, namebuf.base, namebuf.len) == 0) {
1488
0
        char *saveptr = NULL, *query;
1489
0
#define MAX_NUM_OF_PARAM_IN_QUERY 16
1490
0
        struct yuarel_param params[MAX_NUM_OF_PARAM_IN_QUERY+2];
1491
0
        int j;
1492
1493
0
        ogs_assert(request->h.uri == NULL);
1494
0
        request->h.uri = ogs_sbi_parse_uri(valuestr, "?", &saveptr);
1495
0
        ogs_assert(request->h.uri);
1496
1497
0
        memset(params, 0, sizeof(params));
1498
1499
0
        query = ogs_sbi_parse_uri(NULL, "?", &saveptr);
1500
0
        if (query && *query && strlen(query))
1501
0
            yuarel_parse_query(query, '&', params, MAX_NUM_OF_PARAM_IN_QUERY+1);
1502
1503
0
        j = 0;
1504
0
        while(params[j].key && params[j].val) {
1505
0
            if (j >= MAX_NUM_OF_PARAM_IN_QUERY) {
1506
0
                ogs_error("Too many query params (max=%d)",
1507
0
                        MAX_NUM_OF_PARAM_IN_QUERY);
1508
0
                ogs_sbi_server_send_error(stream,
1509
0
                        OGS_SBI_HTTP_STATUS_BAD_REQUEST, NULL,
1510
0
                        "Too many query parameters", NULL, NULL);
1511
1512
0
                ogs_free(query);
1513
1514
0
                ogs_free(namestr);
1515
0
                ogs_free(valuestr);
1516
1517
0
                return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1518
0
            }
1519
1520
0
            if (strlen(params[j].key))
1521
0
                ogs_sbi_header_set(request->http.params,
1522
0
                        params[j].key, params[j].val);
1523
0
            else
1524
0
                ogs_warn("No KEY in Query-Parms");
1525
1526
0
            j++;
1527
0
        }
1528
1529
0
        ogs_free(query);
1530
1531
0
    } else if (namebuf.len == sizeof(METHOD) - 1 &&
1532
0
            memcmp(METHOD, namebuf.base, namebuf.len) == 0) {
1533
1534
0
        ogs_assert(request->h.method == NULL);
1535
0
        request->h.method = ogs_strdup(valuestr);
1536
0
        ogs_assert(request->h.method);
1537
1538
0
    } else {
1539
1540
0
        ogs_sbi_header_set(request->http.headers, namestr, valuestr);
1541
1542
0
    }
1543
1544
0
    ogs_free(namestr);
1545
0
    ogs_free(valuestr);
1546
1547
0
    return 0;
1548
0
}
1549
1550
static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
1551
                              int32_t stream_id, const uint8_t *data,
1552
                              size_t len, void *user_data)
1553
0
{
1554
0
    ogs_sbi_stream_t *stream = NULL;
1555
0
    ogs_sbi_request_t *request = NULL;
1556
0
    char *content = NULL;
1557
1558
0
    size_t offset = 0;
1559
1560
0
    ogs_assert(session);
1561
1562
0
    stream = nghttp2_session_get_stream_user_data(session, stream_id);
1563
0
    if (!stream) {
1564
0
        ogs_error("no stream [%d]", stream_id);
1565
0
        return 0;
1566
0
    }
1567
1568
0
    request = stream->request;
1569
0
    ogs_assert(request);
1570
1571
0
    ogs_assert(data);
1572
0
    ogs_assert(len);
1573
1574
0
#define MAX_HTTP_CONTENT_LEN (256 * 1024 * 1024) /* 256MB */
1575
0
    if (request->http.content_length + len > MAX_HTTP_CONTENT_LEN) {
1576
0
        stream->memory_overflow = true;
1577
1578
0
        ogs_error("Payload too large : Content-Length[%d], len[%d]",
1579
0
                    (int)request->http.content_length, (int)len);
1580
1581
0
        ogs_sbi_server_send_error(stream,
1582
0
                OGS_SBI_HTTP_STATUS_PAYLOAD_TOO_LARGE,
1583
0
                NULL, "Payload too large", NULL, NULL);
1584
1585
0
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1586
0
    }
1587
1588
0
    if (request->http.content == NULL) {
1589
0
        ogs_assert(request->http.content_length == 0);
1590
0
        ogs_assert(offset == 0);
1591
1592
0
        content = (char*)ogs_malloc(len + 1);
1593
0
    } else {
1594
0
        ogs_assert(request->http.content_length != 0);
1595
1596
0
        content = (char*)ogs_realloc(
1597
0
                request->http.content, request->http.content_length + len + 1);
1598
0
    }
1599
1600
0
    if (!content) {
1601
0
        stream->memory_overflow = true;
1602
1603
0
        ogs_error("Memory Overflow : Content-Length[%d], len[%d]",
1604
0
                    (int)request->http.content_length, (int)len);
1605
0
        ogs_log_hexdump(OGS_LOG_ERROR, data, len);
1606
1607
0
        ogs_sbi_server_send_error(stream,
1608
0
                OGS_SBI_HTTP_STATUS_SERVICE_UNAVAILABLE,
1609
0
                NULL, "Memory Overflow", NULL, NULL);
1610
1611
0
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1612
0
    }
1613
1614
0
    request->http.content = content;
1615
1616
0
    offset = request->http.content_length;
1617
0
    request->http.content_length += len;
1618
1619
0
    memcpy(request->http.content + offset, data, len);
1620
0
    request->http.content[request->http.content_length] = '\0';
1621
1622
0
    return 0;
1623
0
}
1624
1625
static int error_callback(nghttp2_session *session,
1626
                          const char *msg, size_t len, void *user_data)
1627
0
{
1628
0
    char buf[OGS_ADDRSTRLEN];
1629
0
    ogs_sockaddr_t *addr = NULL;
1630
0
    ogs_sbi_session_t *sbi_sess = user_data;
1631
1632
0
    ogs_assert(sbi_sess);
1633
0
    addr = sbi_sess->addr;
1634
0
    ogs_assert(addr);
1635
1636
0
    ogs_assert(msg);
1637
1638
0
    ogs_error("[%s]:%d http2 error: %.*s",
1639
0
            OGS_ADDR(addr, buf), OGS_PORT(addr), (int)len, msg);
1640
1641
0
    return 0;
1642
0
}
1643
1644
static int on_invalid_frame_recv(nghttp2_session *session,
1645
                                 const nghttp2_frame *frame,
1646
                                 int error_code, void *user_data)
1647
0
{
1648
0
    char buf[OGS_ADDRSTRLEN];
1649
0
    ogs_sockaddr_t *addr = NULL;
1650
1651
0
    ogs_sbi_session_t *sbi_sess = user_data;
1652
1653
0
    ogs_assert(sbi_sess);
1654
0
    addr = sbi_sess->addr;
1655
0
    ogs_assert(addr);
1656
1657
0
    ogs_error("[%s]:%d invalid frame (%d:%s)",
1658
0
            OGS_ADDR(addr, buf), OGS_PORT(addr),
1659
0
            error_code, nghttp2_strerror(error_code));
1660
0
    return 0;
1661
0
}
1662
1663
static int on_invalid_header(nghttp2_session *session,
1664
                             const nghttp2_frame *frame,
1665
                             const uint8_t *name, size_t namelen,
1666
                             const uint8_t *value, size_t valuelen,
1667
                             uint8_t flags, void *user_data)
1668
0
{
1669
0
    char buf[OGS_ADDRSTRLEN];
1670
0
    ogs_sockaddr_t *addr = NULL;
1671
0
    char *namestr = NULL, *valuestr = NULL;
1672
1673
0
    ogs_sbi_session_t *sbi_sess = user_data;
1674
1675
0
    ogs_assert(sbi_sess);
1676
0
    addr = sbi_sess->addr;
1677
0
    ogs_assert(addr);
1678
1679
0
    namestr = ogs_strndup((const char *)name, namelen);
1680
0
    ogs_assert(namestr);
1681
1682
0
    valuestr = ogs_strndup((const char *)value, valuelen);
1683
0
    ogs_assert(valuestr);
1684
1685
0
    ogs_error("[%s]:%d invalid header (%s:%s)",
1686
0
            OGS_ADDR(addr, buf), OGS_PORT(addr), namestr, valuestr);
1687
1688
0
    ogs_free(namestr);
1689
0
    ogs_free(valuestr);
1690
1691
0
    return 0;
1692
0
}
1693
1694
static int on_begin_frame(nghttp2_session *session, const nghttp2_frame_hd *hd,
1695
                          void *user_data)
1696
0
{
1697
0
    char buf[OGS_ADDRSTRLEN];
1698
0
    ogs_sockaddr_t *addr = NULL;
1699
0
    ogs_sbi_session_t *sbi_sess = user_data;
1700
1701
0
    ogs_assert(sbi_sess);
1702
0
    addr = sbi_sess->addr;
1703
0
    ogs_assert(addr);
1704
1705
0
    ogs_assert(hd);
1706
1707
0
    if ((hd->type == NGHTTP2_HEADERS) &&
1708
0
        (hd->stream_id < sbi_sess->last_stream_id)) {
1709
0
        ogs_error("[%s]:%d invalid stream id(%d) >= last stream id(%d)",
1710
0
                OGS_ADDR(addr, buf), OGS_PORT(addr),
1711
0
                hd->stream_id, sbi_sess->last_stream_id);
1712
0
        return NGHTTP2_ERR_CALLBACK_FAILURE;
1713
0
    }
1714
1715
0
    return 0;
1716
0
}
1717
1718
static int on_begin_headers(nghttp2_session *session,
1719
                            const nghttp2_frame *frame, void *user_data)
1720
0
{
1721
0
    ogs_sbi_session_t *sbi_sess = user_data;
1722
0
    ogs_sbi_stream_t *stream = NULL;
1723
0
    int rv;
1724
1725
0
    ogs_assert(sbi_sess);
1726
0
    ogs_assert(session);
1727
0
    ogs_assert(frame);
1728
1729
0
    if (frame->hd.type != NGHTTP2_HEADERS ||
1730
0
        frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
1731
0
        return 0;
1732
0
    }
1733
1734
0
    stream = stream_add(sbi_sess, frame->hd.stream_id);
1735
0
    if (!stream) {
1736
0
        ogs_error("stream_add() failed for stream [%d]",
1737
0
                frame->hd.stream_id);
1738
1739
0
        rv = nghttp2_submit_rst_stream(
1740
0
                session, NGHTTP2_FLAG_NONE,
1741
0
                frame->hd.stream_id, NGHTTP2_REFUSED_STREAM);
1742
0
        if (rv != 0)
1743
0
            ogs_error("nghttp2_submit_rst_stream() failed (%d:%s)",
1744
0
                    rv, nghttp2_strerror(rv));
1745
1746
0
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1747
0
    }
1748
1749
0
    ogs_debug("STREAM added [%d]", frame->hd.stream_id);
1750
1751
0
    nghttp2_session_set_stream_user_data(session, frame->hd.stream_id, stream);
1752
1753
0
    return 0;
1754
0
}
1755
1756
static int session_send_preface(ogs_sbi_session_t *sbi_sess)
1757
0
{
1758
0
    int rv;
1759
0
    nghttp2_settings_entry iv[1] = {
1760
0
        { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, ogs_app()->pool.stream }
1761
0
    };
1762
1763
0
    ogs_assert(sbi_sess);
1764
0
    ogs_assert(sbi_sess->session);
1765
1766
0
    rv = nghttp2_submit_settings(
1767
0
            sbi_sess->session, NGHTTP2_FLAG_NONE, iv, OGS_ARRAY_SIZE(iv));
1768
0
    if (rv != 0) {
1769
0
        ogs_error("nghttp2_submit_settings() failed (%d:%s)",
1770
0
                    rv, nghttp2_strerror(rv));
1771
0
        return OGS_ERROR;
1772
0
    }
1773
1774
0
    return session_send(sbi_sess);
1775
0
}
1776
1777
#if USE_SEND_DATA_WITH_NO_COPY
1778
static int on_send_data(nghttp2_session *session, nghttp2_frame *frame,
1779
                        const uint8_t *framehd, size_t length,
1780
                        nghttp2_data_source *source, void *user_data)
1781
0
{
1782
0
    ogs_sbi_session_t *sbi_sess = user_data;
1783
1784
0
    ogs_sbi_response_t *response = NULL;
1785
0
    ogs_sbi_stream_t *stream = NULL;
1786
0
    ogs_pkbuf_t *pkbuf = NULL;
1787
0
    size_t padlen = 0;
1788
1789
0
    ogs_assert(session);
1790
0
    ogs_assert(frame);
1791
1792
0
    stream = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
1793
0
    if (!stream) {
1794
0
        ogs_error("no stream [%d]", frame->hd.stream_id);
1795
0
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1796
0
    }
1797
1798
0
    ogs_assert(sbi_sess);
1799
1800
0
    ogs_assert(source);
1801
0
    response = source->ptr;
1802
0
    ogs_assert(response);
1803
1804
0
    ogs_assert(response->http.content);
1805
0
    ogs_assert(response->http.content_length);
1806
1807
0
    ogs_assert(framehd);
1808
0
    ogs_assert(length);
1809
1810
0
    pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
1811
0
    ogs_assert(pkbuf);
1812
0
    ogs_pkbuf_put_data(pkbuf, framehd, 9);
1813
1814
0
    padlen = frame->data.padlen;
1815
1816
0
    if (padlen > 0) {
1817
0
        ogs_pkbuf_put_u8(pkbuf, padlen-1);
1818
0
    }
1819
1820
0
    ogs_pkbuf_put_data(pkbuf,
1821
0
            response->http.content, response->http.content_length);
1822
1823
0
    if (padlen > 0) {
1824
0
        memset(pkbuf->tail, 0, padlen-1);
1825
0
        ogs_pkbuf_put(pkbuf, padlen-1);
1826
0
    }
1827
1828
0
    session_write_to_buffer(sbi_sess, pkbuf);
1829
1830
0
    return 0;
1831
0
}
1832
#else
1833
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
1834
                             size_t length, int flags, void *user_data)
1835
{
1836
    ogs_sbi_session_t *sbi_sess = user_data;
1837
    ogs_sock_t *sock = NULL;
1838
    ogs_socket_t fd = INVALID_SOCKET;
1839
1840
    ogs_pkbuf_t *pkbuf = NULL;
1841
1842
    ogs_assert(sbi_sess);
1843
    sock = sbi_sess->sock;
1844
    ogs_assert(sock);
1845
    fd = sock->fd;
1846
    ogs_assert(fd != INVALID_SOCKET);
1847
1848
    ogs_assert(data);
1849
    ogs_assert(length);
1850
1851
    pkbuf = ogs_pkbuf_alloc(NULL, length);
1852
    ogs_assert(pkbuf);
1853
    ogs_pkbuf_put_data(pkbuf, data, length);
1854
1855
    session_write_to_buffer(sbi_sess, pkbuf);
1856
1857
    return length;
1858
}
1859
#endif
1860
1861
static int session_send(ogs_sbi_session_t *sbi_sess)
1862
0
{
1863
0
#if USE_SEND_DATA_WITH_NO_COPY
1864
0
    ogs_pkbuf_t *pkbuf = NULL;
1865
#else
1866
    int rv;
1867
#endif
1868
1869
0
    ogs_assert(sbi_sess);
1870
0
    ogs_assert(sbi_sess->session);
1871
1872
0
#if USE_SEND_DATA_WITH_NO_COPY
1873
0
    for (;;) {
1874
0
        const uint8_t *data = NULL;
1875
0
        ssize_t data_len;
1876
1877
0
        data_len = nghttp2_session_mem_send(sbi_sess->session, &data);
1878
0
        if (data_len < 0) {
1879
0
            ogs_error("nghttp2_session_mem_send() failed (%d:%s)",
1880
0
                        (int)data_len, nghttp2_strerror((int)data_len));
1881
0
            return OGS_ERROR;
1882
0
        }
1883
1884
0
        if (data_len == 0) {
1885
0
            break;
1886
0
        }
1887
1888
0
        pkbuf = ogs_pkbuf_alloc(NULL, data_len);
1889
0
        ogs_assert(pkbuf);
1890
0
        ogs_pkbuf_put_data(pkbuf, data, data_len);
1891
1892
0
        session_write_to_buffer(sbi_sess, pkbuf);
1893
0
    }
1894
#else
1895
    rv = nghttp2_session_send(sbi_sess->session);
1896
    if (rv != 0) {
1897
        ogs_error("nghttp_session_send() failed (%d:%s)",
1898
                    rv, nghttp2_strerror(rv));
1899
        return OGS_ERROR;
1900
    }
1901
#endif
1902
1903
0
    return OGS_OK;
1904
0
}
1905
1906
static void session_write_callback(short when, ogs_socket_t fd, void *data)
1907
0
{
1908
0
    ogs_sbi_session_t *sbi_sess = data;
1909
0
    ogs_pkbuf_t *pkbuf = NULL;
1910
1911
0
    ogs_assert(sbi_sess);
1912
1913
0
    if (ogs_list_empty(&sbi_sess->write_queue) == true) {
1914
0
        if (sbi_sess->poll.write) {
1915
0
            ogs_pollset_remove(sbi_sess->poll.write);
1916
0
            sbi_sess->poll.write = NULL;
1917
0
        } else
1918
0
            ogs_warn("poll.write has already been removed");
1919
1920
0
        return;
1921
0
    }
1922
1923
0
    pkbuf = ogs_list_first(&sbi_sess->write_queue);
1924
0
    ogs_assert(pkbuf);
1925
0
    ogs_list_remove(&sbi_sess->write_queue, pkbuf);
1926
1927
0
    if (sbi_sess->ssl)
1928
0
        SSL_write(sbi_sess->ssl, pkbuf->data, pkbuf->len);
1929
0
    else
1930
0
        ogs_send(fd, pkbuf->data, pkbuf->len, 0);
1931
1932
0
    ogs_log_hexdump(OGS_LOG_DEBUG, pkbuf->data, pkbuf->len);
1933
1934
0
    ogs_pkbuf_free(pkbuf);
1935
0
}
1936
1937
static void session_write_to_buffer(
1938
        ogs_sbi_session_t *sbi_sess, ogs_pkbuf_t *pkbuf)
1939
0
{
1940
0
    ogs_sock_t *sock = NULL;
1941
0
    ogs_socket_t fd = INVALID_SOCKET;
1942
1943
0
    ogs_assert(pkbuf);
1944
1945
0
    ogs_assert(sbi_sess);
1946
0
    sock = sbi_sess->sock;
1947
0
    ogs_assert(sock);
1948
0
    fd = sock->fd;
1949
0
    ogs_assert(fd != INVALID_SOCKET);
1950
1951
0
    ogs_list_add(&sbi_sess->write_queue, pkbuf);
1952
1953
0
    if (!sbi_sess->poll.write) {
1954
0
        sbi_sess->poll.write = ogs_pollset_add(ogs_app()->pollset,
1955
0
            OGS_POLLOUT, fd, session_write_callback, sbi_sess);
1956
0
        ogs_assert(sbi_sess->poll.write);
1957
0
    }
1958
0
}