d9d7689816da66862df00fe25cc01ab4f5bfe07a
3 * @author David Llewellyn-Jones <david@flypig.co.uk>
8 * Copyright David Llewellyn-Jones, 2020
9 * Released under the GPLv2.
11 * @brief Provides a way to match collected RPIs with downloaded DTKs.
12 * @section DESCRIPTION
14 * This class provides functionality allowing RPIs that have been collected
15 * over Bluetooth to be matched against DTKs downloaded from a Diagnosis
18 * The list of RPIs and DTKs can be constructed easily using the
19 * \ref Container functions.
23 /** \addtogroup Matching
34 #include <openssl/crypto.h>
35 #include <openssl/hmac.h>
36 #include <openssl/err.h>
38 #include "contrac/contrac.h"
39 #include "contrac/utils.h"
40 #include "contrac/log.h"
41 #include "contrac/rpi_list.h"
42 #include "contrac/dtk_list.h"
44 #include "contrac/match.h"
51 * @brief A match list element
53 * This is an opaque structure that represents a single item in the list and
54 * captures a match between an RPI and a DTK.
56 * The structure typedef is in match.h
58 struct _MatchListItem
{
60 uint8_t time_interval_number
;
66 * @brief The head of a match list
68 * This is an opaque structure that represents the head of the list. Each item
69 * in the list captures a match between an RPI and a DTK.
71 * This is the object usually passed as the first parameter of every non-static
74 * The structure typedef is in match.h
78 MatchListItem
* first
;
82 // Function prototypes
84 MatchListItem
* match_list_item_new();
85 void match_list_item_delete(MatchListItem
* data
);
86 void match_list_append(MatchList
* data
, MatchListItem
* item
);
88 // Function definitions
91 * Creates a new instance of the class.
93 * @return The newly created object.
95 MatchList
* match_list_new() {
98 data
= calloc(sizeof(MatchList
), 1);
104 * Deletes an instance of the class, freeing up the memory allocated to it.
106 * This will also delete all items contained in the list.
108 * @param data The instance to free.
110 void match_list_delete(MatchList
* data
) {
112 match_list_clear(data
);
119 * Creates a new instance of the class.
121 * @return The newly created object.
123 MatchListItem
* match_list_item_new() {
124 MatchListItem
* data
;
126 data
= calloc(sizeof(MatchListItem
), 1);
132 * Deletes an instance of the class, freeing up the memory allocated to it.
134 * @param data The instance to free.
136 void match_list_item_delete(MatchListItem
* data
) {
143 * Clears all items from the list.
145 * Removes all items from the list to create an empty list. The memory
146 * associated with the items in the list is freed.
148 * @param data The list to operate on.
150 void match_list_clear(MatchList
* data
) {
151 MatchListItem
* item
;
152 MatchListItem
* next
;
157 match_list_item_delete(item
);
167 * Returns the number of items in the list.
169 * Immediately after creation, or after the \ref match_list_clear() function
170 * has been called, this will return zero.
172 * @param data The list to operate on.
174 size_t match_list_count(MatchList
* data
) {
179 * Returns the first item in the list.
181 * Useful for iterating through the items in the list.
183 * @param data The list to operate on.
184 * @return The first item of the list.
186 MatchListItem
const * match_list_first(MatchList
const * data
) {
191 * Returns the next item in the list.
193 * Useful for iterating through the items in the list.
195 * @param data The current item in the list.
196 * @return The next item in the list following the current item.
198 MatchListItem
const * match_list_next(MatchListItem
const * data
) {
204 * Returns the day number of the item in the list.
206 * This will represent the day number of when an interaction occurred with
207 * someone who has subsequently uploaded their DTK to a diagnosis server due to
210 * @param data The list to operate on.
211 * @return The day number for this item.
213 uint32_t match_list_get_day_number(MatchListItem
const * data
) {
214 return data
->day_number
;
218 * Returns the time interval number of the item in the list.
220 * This will represent the time interval number of when an interaction occurred
221 * with someone who has subsequently uploaded their DTK to a diagnosis server
222 * due to testing positive.
224 * @param data The list to operate on.
225 * @return The time interval number for this item.
227 uint8_t match_list_get_time_interval_number(MatchListItem
const * data
) {
228 return data
->time_interval_number
;
232 * Adds an item to the list.
234 * This adds a match to the list. It's primarily for internal use.
236 * @param data The list to append to.
237 * @param item The match to append.
239 void match_list_append(MatchList
* data
, MatchListItem
* item
) {
240 if (data
->last
== NULL
) {
245 data
->last
->next
= item
;
252 * Returns a list of matches found between the beacons and diagnoses.
254 * This searches through the list of DTKs and the list of RPIs provided, and
255 * returns a list of matches.
257 * If the returned list has any elements in, this would suggest that the user
258 * has been in contact with someone who tested positive and uploaded their DTK
259 * to a Diagnosis Server.
261 * The match list isn't cleared by this call and so any new values will be
264 * @param data The list that any matches will be appended to.
265 * @param beacons A list of RPIs extracted from overheard BLE beacons.
266 * @param diagnosis_keys A list of DTKs downloaed from a Diagnosis Server.
268 void match_list_find_matches(MatchList
* data
, RpiList
* beacons
, DtkList
* diagnosis_keys
) {
269 // For each diagnosis key, generate the RPIs and compare them against the captured RPI beacons
270 DtkListItem
const * dtk_item
;
271 RpiListItem
const * rpi_item
;
275 MatchListItem
* match
;
276 Dtk
const * diagnosis_key
;
279 dtk_item
= dtk_list_first(diagnosis_keys
);
280 generated
= rpi_new();
282 while (dtk_item
!= NULL
) {
283 diagnosis_key
= dtk_list_get_dtk(dtk_item
);
284 // Generate all possible RPIs for this dtk and compare agsinst the beacons
285 for (interval
= 0; interval
< RPI_INTERVAL_MAX
; ++interval
) {
286 result
= rpi_generate_proximity_id(generated
, diagnosis_key
, interval
);
288 // Check against all beacons
289 rpi_item
= rpi_list_first(beacons
);
290 while (rpi_item
!= NULL
) {
291 rpi
= rpi_list_get_rpi(rpi_item
);
292 result
= rpi_compare(rpi
, generated
);
295 if (interval
!= rpi_get_time_interval_number(rpi
)) {
297 LOG(LOG_DEBUG
, "Matched beacons don't match intervals\n");
302 match
= match_list_item_new();
303 match
->day_number
= dtk_get_day_number(diagnosis_key
);
304 match
->time_interval_number
= interval
;
305 match_list_append(data
, match
);
308 rpi_item
= rpi_list_next(rpi_item
);
313 dtk_item
= dtk_list_next(dtk_item
);
316 rpi_delete(generated
);
319 /** @} addtogroup Matching*/