Coverage Report

Created: 2025-08-28 06:49

/src/gpac/src/utils/downloader_hmux.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *          GPAC Multimedia Framework
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2005-2025
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / downloader sub-project
9
 *
10
 *  GPAC is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU Lesser General Public License as published by
12
 *  the Free Software Foundation; either version 2, or (at your option)
13
 *  any later version.
14
 *
15
 *  GPAC is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU Lesser General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU Lesser General Public
21
 *  License along with this library; see the file COPYING.  If not, write to
22
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
 *
24
 */
25
26
#include "downloader.h"
27
28
#ifndef GPAC_DISABLE_NETWORK
29
30
#ifdef GPAC_HTTPMUX
31
32
//detach session from parent h2 / h3 session - the session mutex SHALL be grabbed before calling this
33
void hmux_detach_session(GF_HMUX_Session *hmux_sess, GF_DownloadSession *sess)
34
{
35
  if (!hmux_sess || !sess) return;
36
  gf_assert(sess->hmux_sess == hmux_sess);
37
  gf_assert(sess->mx);
38
39
  gf_list_del_item(hmux_sess->sessions, sess);
40
  if (!gf_list_count(hmux_sess->sessions)) {
41
    if (hmux_sess->close)
42
      hmux_sess->close(hmux_sess);
43
44
#ifdef GPAC_HAS_SSL
45
    if (sess->ssl) {
46
      GF_LOG(GF_LOG_DEBUG, GF_LOG_HTTP, ("[Downloader] shut down SSL context\n"));
47
      SSL_shutdown(sess->ssl);
48
      SSL_free(sess->ssl);
49
      sess->ssl = NULL;
50
    }
51
#endif
52
    dm_sess_sk_del(sess);
53
    if (hmux_sess->destroy)
54
      hmux_sess->destroy(hmux_sess);
55
56
    gf_list_del(hmux_sess->sessions);
57
    gf_mx_v(hmux_sess->mx);
58
    gf_mx_del(sess->mx);
59
    gf_free(hmux_sess);
60
  } else {
61
    GF_DownloadSession *asess = gf_list_get(hmux_sess->sessions, 0);
62
    gf_assert(asess->hmux_sess == hmux_sess);
63
64
    hmux_sess->net_sess = asess;
65
    //swap async buf if any to new active session
66
    if (sess->async_buf_alloc) {
67
      gf_assert(!asess->async_buf);
68
      asess->async_buf = sess->async_buf;
69
      asess->async_buf_alloc = sess->async_buf_alloc;
70
      asess->async_buf_size = sess->async_buf_size;
71
      sess->async_buf_alloc = sess->async_buf_size = 0;
72
      sess->async_buf = NULL;
73
    }
74
    sess->sock = NULL;
75
#ifdef GPAC_HAS_SSL
76
    sess->ssl = NULL;
77
#endif
78
    gf_mx_v(sess->mx);
79
  }
80
81
  if (sess->hmux_buf.data) {
82
    gf_free(sess->hmux_buf.data);
83
    memset(&sess->hmux_buf, 0, sizeof(hmux_reagg_buffer));
84
  }
85
  sess->hmux_sess = NULL;
86
  sess->mx = NULL;
87
}
88
89
90
GF_DownloadSession *hmux_get_session(void *user_data, s64 stream_id, Bool can_reassign)
91
{
92
  u32 i, nb_sess;
93
  GF_DownloadSession *first_not_assigned = NULL;
94
  GF_HMUX_Session *hmux_sess = (GF_HMUX_Session *)user_data;
95
96
  nb_sess = gf_list_count(hmux_sess->sessions);
97
  for (i=0;i<nb_sess; i++) {
98
    GF_DownloadSession *s = gf_list_get(hmux_sess->sessions, i);
99
    if (s->hmux_stream_id == stream_id)
100
      return s;
101
102
    if (s->server_mode && (s->hmux_stream_id<0) && !first_not_assigned) {
103
      first_not_assigned = s;
104
    }
105
  }
106
  if (can_reassign && first_not_assigned) {
107
    first_not_assigned->hmux_stream_id = stream_id;
108
    GF_LOG(GF_LOG_DEBUG, GF_LOG_HTTP, ("[%s] reassigning old server session to new stream %d\n", hmux_sess->net_sess->log_name, stream_id));
109
    first_not_assigned->status = GF_NETIO_CONNECTED;
110
    first_not_assigned->total_size = first_not_assigned->bytes_done = 0;
111
    first_not_assigned->hmux_data_done = 0;
112
    if (first_not_assigned->remote_path) gf_free(first_not_assigned->remote_path);
113
    first_not_assigned->remote_path = NULL;
114
    //reset internal reaggregation buffer
115
    first_not_assigned->hmux_buf.size = 0;
116
117
    gf_dm_sess_clear_headers(first_not_assigned);
118
    return first_not_assigned;
119
  }
120
  return NULL;
121
}
122
123
void hmux_flush_internal_data(GF_DownloadSession *sess, Bool store_in_init)
124
{
125
  gf_dm_data_received(sess, (u8 *) sess->hmux_buf.data, sess->hmux_buf.size, store_in_init, NULL, NULL);
126
  sess->hmux_buf.size = 0;
127
}
128
129
void hmux_fetch_data(GF_DownloadSession *sess, u8 *obuffer, u32 size, u32 *nb_bytes)
130
{
131
  u32 copy, nb_b_pck;
132
  u8 *data;
133
  *nb_bytes = 0;
134
  if (!sess->hmux_buf.size) {
135
    if (sess->hmux_is_eos) {
136
      if (!sess->total_size) {
137
        sess->total_size = sess->bytes_done;
138
        gf_dm_data_received(sess, obuffer, 0, GF_FALSE, NULL, NULL);
139
      }
140
141
      if (sess->status==GF_NETIO_DATA_EXCHANGE)
142
        sess->status = GF_NETIO_DATA_TRANSFERED;
143
    }
144
    return;
145
  }
146
147
  gf_assert(sess->hmux_buf.offset<=sess->hmux_buf.size);
148
149
  nb_b_pck = sess->hmux_buf.size - sess->hmux_buf.offset;
150
  if (nb_b_pck > size)
151
    copy = size;
152
  else
153
    copy = nb_b_pck;
154
155
  data = sess->hmux_buf.data + sess->hmux_buf.offset;
156
  memcpy(obuffer, data, copy);
157
  *nb_bytes = copy;
158
  //signal we received data (for event triggering / user callbacks)
159
  gf_dm_data_received(sess, (u8 *) data, copy, GF_FALSE, NULL, NULL);
160
161
  if (copy < nb_b_pck) {
162
    sess->hmux_buf.offset += copy;
163
  } else {
164
    sess->hmux_buf.size = sess->hmux_buf.offset = 0;
165
  }
166
  gf_assert(sess->hmux_buf.offset<=sess->hmux_buf.size);
167
}
168
169
GF_Err hmux_send_payload(GF_DownloadSession *sess, u8 *data, u32 size)
170
{
171
  GF_Err e = GF_OK;
172
  if (sess->hmux_send_data) {
173
    e = gf_sk_probe(sess->sock);
174
    if (e) return e;
175
    return GF_SERVICE_ERROR;
176
  }
177
178
  if (sess->hmux_stream_id<0)
179
    return GF_URL_REMOVED;
180
181
  gf_mx_p(sess->mx);
182
183
  GF_LOG(GF_LOG_DEBUG, GF_LOG_HTTP, ("[%s] Sending %d bytes on stream_id "LLD"\n", sess->log_name, size, sess->hmux_stream_id));
184
185
  assert(sess->hmux_send_data==NULL);
186
  sess->hmux_send_data = data;
187
  sess->hmux_send_data_len = size;
188
  if (sess->hmux_data_paused) {
189
    e = sess->hmux_sess->resume(sess);
190
    if (e) {
191
      gf_mx_v(sess->mx);
192
      return e;
193
    }
194
  }
195
  //if no data, signal end of stream, otherwise regular send
196
  if (!data || !size) {
197
    if (sess->local_buf_len) {
198
      gf_mx_v(sess->mx);
199
      if (sess->hmux_is_eos) {
200
        return GF_IP_NETWORK_EMPTY;
201
      }
202
      sess->hmux_is_eos = 1;
203
      sess->hmux_sess->write(sess);
204
      return GF_OK;
205
    }
206
    sess->hmux_is_eos = 1;
207
    sess->hmux_sess->write(sess);
208
    //stream_id is not yet 0 in case of PUT/PUSH, stream is closed once we get reply from server
209
  } else {
210
    sess->hmux_is_eos = 0;
211
    //send the data
212
    e = sess->hmux_sess->send_pending_data(sess);
213
    if (e && (e!=GF_IP_NETWORK_EMPTY)) {
214
      gf_mx_v(sess->mx);
215
      return e;
216
    }
217
  }
218
  gf_mx_v(sess->mx);
219
220
  if (!data || !size) {
221
    if (sess->put_state) {
222
      //we are done sending
223
      if (!sess->local_buf_len) {
224
        sess->put_state = 2;
225
        sess->status = GF_NETIO_WAIT_FOR_REPLY;
226
      }
227
      return GF_OK;
228
    }
229
  }
230
  if ((sess->hmux_stream_id<0) && sess->hmux_send_data)
231
    return GF_URL_REMOVED;
232
  return GF_OK;
233
}
234
235
#endif //GPAC_HTTPMUX
236
237
238
239
void gf_dm_sess_close_hmux(GF_DownloadSession *sess)
240
0
{
241
#ifdef GPAC_HTTPMUX
242
  if (sess->hmux_sess)
243
    sess->hmux_sess->close_session(sess);
244
#endif
245
0
}
246
247
GF_DownloadSession *gf_dm_sess_new_subsession(GF_DownloadSession *sess, s64 stream_id, void *usr_cbk, GF_Err *e)
248
0
{
249
#ifdef GPAC_HTTPMUX
250
  GF_DownloadSession *sub_sess;
251
  if (!sess->hmux_sess) return NULL;
252
  gf_mx_p(sess->mx);
253
  sub_sess = gf_dm_sess_new_internal(NULL, NULL, 0, sess->user_proc, usr_cbk, sess->sock, GF_TRUE, e);
254
  if (!sub_sess) {
255
    gf_mx_v(sess->mx);
256
    return NULL;
257
  }
258
  gf_list_add(sess->hmux_sess->sessions, sub_sess);
259
#ifdef GPAC_HAS_SSL
260
  sub_sess->ssl = sess->ssl;
261
#endif
262
  sub_sess->hmux_sess = sess->hmux_sess;
263
  if (sub_sess->mx) gf_mx_del(sub_sess->mx);
264
  sub_sess->mx = sess->hmux_sess->mx;
265
  sub_sess->hmux_stream_id = stream_id;
266
  sub_sess->status = GF_NETIO_CONNECTED;
267
268
  sub_sess->hmux_sess->setup_session(sub_sess, GF_FALSE);
269
270
  sub_sess->flags = sess->flags;
271
  gf_mx_v(sess->mx);
272
  return sub_sess;
273
#else
274
0
  return NULL;
275
0
#endif //GPAC_HTTPMUX
276
0
}
277
278
279
280
#endif //GPAC_DISABLE_NETWORK
281