| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2023-09-07 16:59:15 +08:00
										 |  |  |  * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
					
						
							|  |  |  |  * this file except in compliance with the License.  You can obtain a copy | 
					
						
							|  |  |  |  * in the file LICENSE in the source distribution or at | 
					
						
							|  |  |  |  * https://www.openssl.org/source/license.html
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "internal/uint_set.h"
 | 
					
						
							|  |  |  | #include "internal/common.h"
 | 
					
						
							|  |  |  | #include "internal/quic_sf_list.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct stream_frame_st { | 
					
						
							|  |  |  |     struct stream_frame_st *prev, *next; | 
					
						
							|  |  |  |     UINT_RANGE range; | 
					
						
							| 
									
										
										
										
											2022-10-31 22:39:13 +08:00
										 |  |  |     OSSL_QRX_PKT *pkt; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     const unsigned char *data; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void stream_frame_free(SFRAME_LIST *fl, STREAM_FRAME *sf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-06-13 00:16:35 +08:00
										 |  |  |     if (fl->cleanse && sf->data != NULL) | 
					
						
							|  |  |  |         OPENSSL_cleanse((unsigned char *)sf->data, | 
					
						
							|  |  |  |                         (size_t)(sf->range.end - sf->range.start)); | 
					
						
							| 
									
										
										
										
											2022-10-31 22:39:13 +08:00
										 |  |  |     ossl_qrx_pkt_release(sf->pkt); | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     OPENSSL_free(sf); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 22:39:13 +08:00
										 |  |  | static STREAM_FRAME *stream_frame_new(UINT_RANGE *range, OSSL_QRX_PKT *pkt, | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |                                       const unsigned char *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STREAM_FRAME *sf = OPENSSL_zalloc(sizeof(*sf)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 17:28:58 +08:00
										 |  |  |     if (sf == NULL) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 22:39:13 +08:00
										 |  |  |     if (pkt != NULL) | 
					
						
							|  |  |  |         ossl_qrx_pkt_up_ref(pkt); | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sf->range = *range; | 
					
						
							|  |  |  |     sf->pkt = pkt; | 
					
						
							|  |  |  |     sf->data = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return sf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 22:39:13 +08:00
										 |  |  | void ossl_sframe_list_init(SFRAME_LIST *fl) | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     memset(fl, 0, sizeof(*fl)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ossl_sframe_list_destroy(SFRAME_LIST *fl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STREAM_FRAME *sf, *next_frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (sf = fl->head; sf != NULL; sf = next_frame) { | 
					
						
							|  |  |  |         next_frame = sf->next; | 
					
						
							|  |  |  |         stream_frame_free(fl, sf); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int append_frame(SFRAME_LIST *fl, UINT_RANGE *range, | 
					
						
							| 
									
										
										
										
											2022-10-31 22:39:13 +08:00
										 |  |  |                         OSSL_QRX_PKT *pkt, | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |                         const unsigned char *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STREAM_FRAME *new_frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((new_frame = stream_frame_new(range, pkt, data)) == NULL) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     new_frame->prev = fl->tail; | 
					
						
							|  |  |  |     if (fl->tail != NULL) | 
					
						
							|  |  |  |         fl->tail->next = new_frame; | 
					
						
							|  |  |  |     fl->tail = new_frame; | 
					
						
							|  |  |  |     ++fl->num_frames; | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ossl_sframe_list_insert(SFRAME_LIST *fl, UINT_RANGE *range, | 
					
						
							| 
									
										
										
										
											2022-10-31 22:39:13 +08:00
										 |  |  |                             OSSL_QRX_PKT *pkt, | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |                             const unsigned char *data, int fin) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STREAM_FRAME *sf, *new_frame, *prev_frame, *next_frame; | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | #ifndef NDEBUG
 | 
					
						
							|  |  |  |     uint64_t curr_end = fl->tail != NULL ? fl->tail->range.end | 
					
						
							|  |  |  |                                          : fl->offset; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |     /* This check for FINAL_SIZE_ERROR is handled by QUIC FC already */ | 
					
						
							|  |  |  |     assert((!fin || curr_end <= range->end) | 
					
						
							|  |  |  |            && (!fl->fin || curr_end >= range->end)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |     if (fl->offset >= range->end) | 
					
						
							|  |  |  |         goto end; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |     /* nothing there yet */ | 
					
						
							|  |  |  |     if (fl->tail == NULL) { | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |         fl->tail = fl->head = stream_frame_new(range, pkt, data); | 
					
						
							|  |  |  |         if (fl->tail == NULL) | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |         ++fl->num_frames; | 
					
						
							|  |  |  |         goto end; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* optimize insertion at the end */ | 
					
						
							|  |  |  |     if (fl->tail->range.start < range->start) { | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |         if (fl->tail->range.end >= range->end) | 
					
						
							|  |  |  |             goto end; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 02:30:30 +08:00
										 |  |  |         if (!append_frame(fl, range, pkt, data)) | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         goto end; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     prev_frame = NULL; | 
					
						
							|  |  |  |     for (sf = fl->head; sf != NULL && sf->range.start < range->start; | 
					
						
							|  |  |  |          sf = sf->next) | 
					
						
							|  |  |  |         prev_frame = sf; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |     if (!ossl_assert(sf != NULL)) | 
					
						
							|  |  |  |         /* frame list invariant broken */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |     if (prev_frame != NULL && prev_frame->range.end >= range->end) | 
					
						
							|  |  |  |         goto end; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Now we must create a new frame although in the end we might drop it, | 
					
						
							|  |  |  |      * because we will be potentially dropping existing overlapping frames. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     new_frame = stream_frame_new(range, pkt, data); | 
					
						
							|  |  |  |     if (new_frame == NULL) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (next_frame = sf; | 
					
						
							|  |  |  |          next_frame != NULL && next_frame->range.end <= range->end;) { | 
					
						
							|  |  |  |         STREAM_FRAME *drop_frame = next_frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         next_frame = next_frame->next; | 
					
						
							|  |  |  |         if (next_frame != NULL) | 
					
						
							|  |  |  |             next_frame->prev = drop_frame->prev; | 
					
						
							|  |  |  |         if (prev_frame != NULL) | 
					
						
							|  |  |  |             prev_frame->next = drop_frame->next; | 
					
						
							|  |  |  |         if (fl->head == drop_frame) | 
					
						
							|  |  |  |             fl->head = next_frame; | 
					
						
							|  |  |  |         if (fl->tail == drop_frame) | 
					
						
							|  |  |  |             fl->tail = prev_frame; | 
					
						
							|  |  |  |         --fl->num_frames; | 
					
						
							|  |  |  |         stream_frame_free(fl, drop_frame); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     if (next_frame != NULL) { | 
					
						
							|  |  |  |         /* check whether the new_frame is redundant because there is no gap */ | 
					
						
							|  |  |  |         if (prev_frame != NULL | 
					
						
							|  |  |  |             && next_frame->range.start <= prev_frame->range.end) { | 
					
						
							|  |  |  |             stream_frame_free(fl, new_frame); | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  |             goto end; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |         next_frame->prev = new_frame; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         fl->tail = new_frame; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     new_frame->next = next_frame; | 
					
						
							|  |  |  |     new_frame->prev = prev_frame; | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     if (prev_frame != NULL) | 
					
						
							|  |  |  |         prev_frame->next = new_frame; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         fl->head = new_frame; | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     ++fl->num_frames; | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |  end: | 
					
						
							|  |  |  |     fl->fin = fin || fl->fin; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ossl_sframe_list_peek(const SFRAME_LIST *fl, void **iter, | 
					
						
							|  |  |  |                           UINT_RANGE *range, const unsigned char **data, | 
					
						
							|  |  |  |                           int *fin) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STREAM_FRAME *sf = *iter; | 
					
						
							|  |  |  |     uint64_t start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (sf == NULL) { | 
					
						
							|  |  |  |         start = fl->offset; | 
					
						
							|  |  |  |         sf = fl->head; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         start = sf->range.end; | 
					
						
							|  |  |  |         sf = sf->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     range->start = start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (sf == NULL || sf->range.start > start | 
					
						
							|  |  |  |         || !ossl_assert(start < sf->range.end)) { | 
					
						
							|  |  |  |         range->end = start; | 
					
						
							|  |  |  |         *data = NULL; | 
					
						
							|  |  |  |         *iter = NULL; | 
					
						
							|  |  |  |         /* set fin only if we are at the end */ | 
					
						
							|  |  |  |         *fin = sf == NULL ? fl->fin : 0; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     range->end = sf->range.end; | 
					
						
							| 
									
										
										
										
											2022-12-01 02:30:30 +08:00
										 |  |  |     if (sf->data != NULL) | 
					
						
							|  |  |  |         *data = sf->data + (start - sf->range.start); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         *data = NULL; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     *fin = sf->next == NULL ? fl->fin : 0; | 
					
						
							|  |  |  |     *iter = sf; | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ossl_sframe_list_drop_frames(SFRAME_LIST *fl, uint64_t limit) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STREAM_FRAME *sf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* offset cannot move back or past the data received */ | 
					
						
							|  |  |  |     if (!ossl_assert(limit >= fl->offset) | 
					
						
							|  |  |  |         || !ossl_assert(fl->tail == NULL | 
					
						
							|  |  |  |                         || limit <= fl->tail->range.end) | 
					
						
							|  |  |  |         || !ossl_assert(fl->tail != NULL | 
					
						
							|  |  |  |                         || limit == fl->offset)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fl->offset = limit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (sf = fl->head; sf != NULL && sf->range.end <= limit;) { | 
					
						
							|  |  |  |         STREAM_FRAME *drop_frame = sf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         sf = sf->next; | 
					
						
							|  |  |  |         --fl->num_frames; | 
					
						
							|  |  |  |         stream_frame_free(fl, drop_frame); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fl->head = sf; | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     if (sf != NULL) | 
					
						
							|  |  |  |         sf->prev = NULL; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         fl->tail = NULL; | 
					
						
							| 
									
										
										
										
											2022-10-11 14:44:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 02:30:30 +08:00
										 |  |  |     fl->head_locked = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ossl_sframe_list_lock_head(SFRAME_LIST *fl, UINT_RANGE *range, | 
					
						
							|  |  |  |                                const unsigned char **data, | 
					
						
							|  |  |  |                                int *fin) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  |     void *iter = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (fl->head_locked) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = ossl_sframe_list_peek(fl, &iter, range, data, fin); | 
					
						
							|  |  |  |     if (ret) | 
					
						
							|  |  |  |         fl->head_locked = 1; | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ossl_sframe_list_is_head_locked(SFRAME_LIST *fl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return fl->head_locked; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ossl_sframe_list_move_data(SFRAME_LIST *fl, | 
					
						
							|  |  |  |                                sframe_list_write_at_cb *write_at_cb, | 
					
						
							|  |  |  |                                void *cb_arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STREAM_FRAME *sf = fl->head, *prev_frame = NULL; | 
					
						
							|  |  |  |     uint64_t limit = fl->offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (sf == NULL) | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (fl->head_locked) | 
					
						
							|  |  |  |         sf = sf->next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (; sf != NULL; sf = sf->next) { | 
					
						
							|  |  |  |         size_t len; | 
					
						
							|  |  |  |         const unsigned char *data = sf->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (limit < sf->range.start) | 
					
						
							|  |  |  |             limit = sf->range.start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (data != NULL) { | 
					
						
							|  |  |  |             if (limit > sf->range.start) | 
					
						
							|  |  |  |                 data += (size_t)(limit - sf->range.start); | 
					
						
							|  |  |  |             len = (size_t)(sf->range.end - limit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!write_at_cb(limit, data, len, cb_arg)) | 
					
						
							|  |  |  |                 /* data did not fit */ | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 00:16:35 +08:00
										 |  |  |             if (fl->cleanse) | 
					
						
							|  |  |  |                 OPENSSL_cleanse((unsigned char *)sf->data, | 
					
						
							|  |  |  |                                 (size_t)(sf->range.end - sf->range.start)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 02:30:30 +08:00
										 |  |  |             /* release the packet */ | 
					
						
							|  |  |  |             sf->data = NULL; | 
					
						
							|  |  |  |             ossl_qrx_pkt_release(sf->pkt); | 
					
						
							|  |  |  |             sf->pkt = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         limit = sf->range.end; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* merge contiguous frames */ | 
					
						
							|  |  |  |         if (prev_frame != NULL | 
					
						
							|  |  |  |             && prev_frame->range.end >= sf->range.start) { | 
					
						
							|  |  |  |             prev_frame->range.end = sf->range.end; | 
					
						
							|  |  |  |             prev_frame->next = sf->next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (sf->next != NULL) | 
					
						
							|  |  |  |                 sf->next->prev = prev_frame; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 fl->tail = prev_frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             --fl->num_frames; | 
					
						
							|  |  |  |             stream_frame_free(fl, sf); | 
					
						
							|  |  |  |             sf = prev_frame; | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         prev_frame = sf; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:08:43 +08:00
										 |  |  |     return 1; | 
					
						
							|  |  |  | } |