You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

254 lines
5.2 KiB

/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2017
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ccs7db.h"
#include <eth_ar/eth_ar.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct ccs7db_entry {
unsigned long id;
uint8_t mac[6];
};
struct ccs7db {
size_t nr_entries;
struct ccs7db_entry **id_index;
struct ccs7db_entry **mac_index;
};
struct ccs7db *ccs7db_create(void)
{
return calloc(1, sizeof(struct ccs7db));
}
void ccs7db_destroy(struct ccs7db *db)
{
size_t i;
for (i = 0; i < db->nr_entries; i++) {
free(db->id_index[i]);
}
free(db->id_index);
free(db->mac_index);
free(db);
}
static struct ccs7db_entry *ccs7db_find_by_id_nested(struct ccs7db *db, unsigned long id, size_t start, size_t end, size_t *off)
{
size_t half = start + (end - start) / 2;
if (end - start == 0) {
if (off)
*off = start;
return NULL;
}
if (db->id_index[half]->id == id) {
if (off)
*off = half;
return db->id_index[start];
}
if (db->id_index[half]->id > id) {
return ccs7db_find_by_id_nested(db, id, start, half, off);
} else {
return ccs7db_find_by_id_nested(db, id, half + 1, end, off);
}
}
struct ccs7db_entry *ccs7db_find_by_id(struct ccs7db *db, unsigned long id, size_t *off)
{
size_t start = 0;
size_t end = db->nr_entries;
if (!end) {
if (off)
*off = 0;
return NULL;
}
return ccs7db_find_by_id_nested(db, id, start, end, off);
}
static int compare_mac(const uint8_t *mac1, const uint8_t *mac2)
{
int i;
for (i = 0; i < 6; i++) {
if (mac1[i] < mac2[i])
return -1;
if (mac1[i] > mac2[i])
return 1;
}
return 0;
}
static struct ccs7db_entry *ccs7db_find_by_mac_nested(struct ccs7db *db, const uint8_t *mac, size_t start, size_t end, size_t *off)
{
size_t half = start + (end - start) / 2;
if (end - start == 0) {
if (off)
*off = start;
return NULL;
}
int compare = compare_mac(mac, db->mac_index[half]->mac);
if (compare == 0) {
if (off)
*off = half;
return db->mac_index[half];
}
if (compare < 0) {
return ccs7db_find_by_mac_nested(db, mac, start, half, off);
} else {
return ccs7db_find_by_mac_nested(db, mac, half + 1, end, off);
}
}
struct ccs7db_entry *ccs7db_find_by_mac(struct ccs7db *db, const uint8_t *mac, size_t *off)
{
size_t end = db->nr_entries;
if (!end) {
if (off)
*off = 0;
return NULL;
}
return ccs7db_find_by_mac_nested(db, mac, 0, end, off);
}
int ccs7db_id2mac(struct ccs7db *db, uint8_t mac[6], const unsigned long id)
{
struct ccs7db_entry *entry = ccs7db_find_by_id(db, id, NULL);
if (!entry)
return -1;
memcpy(mac, entry->mac, 6);
return 0;
}
int ccs7db_mac2id(struct ccs7db *db, unsigned long *id, const uint8_t mac[6])
{
struct ccs7db_entry *entry = ccs7db_find_by_mac(db, mac, NULL);
if (!entry)
return -1;
*id = entry->id;
return 0;
}
int ccs7db_add(struct ccs7db *db, char *callsign, char *idstr)
{
uint8_t mac[6];
unsigned long id = atol(idstr);
int r = 0;
size_t id_off;
size_t mac_off;
if (strlen(idstr) > 8) {
r = -1;
goto err_id;
}
if (eth_ar_call2mac(mac, callsign, 0, false)) {
r = -1;
goto err_mac;
}
struct ccs7db_entry *entry = ccs7db_find_by_id(db, id, &id_off);
if (!entry) {
ccs7db_find_by_mac(db, mac, &mac_off);
entry = malloc(sizeof(*entry));
if (!entry) {
r = -1;
goto err_alloc;
}
struct ccs7db_entry **ids = realloc(db->id_index, sizeof(entry) * (db->nr_entries+1));
if (!ids) {
r = -1;
goto err_realloc;
}
db->id_index = ids;
struct ccs7db_entry **macs = realloc(db->mac_index, sizeof(entry) * (db->nr_entries+1));
if (!macs) {
r = -1;
goto err_realloc;
}
db->mac_index = macs;
entry->id = id;
memcpy(entry->mac, mac, 6);
memmove(&db->id_index[id_off+1], &db->id_index[id_off], (db->nr_entries - id_off) * sizeof(entry));
db->id_index[id_off] = entry;
memmove(&db->mac_index[mac_off+1], &db->mac_index[mac_off], (db->nr_entries - mac_off) * sizeof(entry));
db->mac_index[mac_off] = entry;
db->nr_entries++;
}
err_realloc:
err_alloc:
err_mac:
err_id:
return r;
}
int ccs7db_csv_load(struct ccs7db *db, const char *filename)
{
FILE *fcsv;
char csvline[256] = {0};
int r = 0;
fcsv = fopen(filename, "r");
if (!fcsv) {
r = -1;
goto err_open;
}
/* skip first line */
fgets(csvline, sizeof(csvline)-1, fcsv);
while (fgets(csvline, sizeof(csvline)-1, fcsv)) {
char *save;
char *num;
char *callsign = NULL;
char *dmrid = NULL;
num = strtok_r(csvline, "; ", &save);
if (num)
callsign = strtok_r(NULL, "; .", &save);
if (callsign)
dmrid = strtok_r(NULL, "; .", &save);
if (callsign && dmrid) {
ccs7db_add(db, callsign, dmrid);
}
}
fclose(fcsv);
err_open:
return r;
}