it2s-itss-facilities/src/config.c

533 lines
22 KiB
C

#include "config.h"
#include "facilities.h"
#include "tpm.h"
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <it2s-config.h>
#include <dirent.h>
#include <camv2/ProtectedCommunicationZone.h>
#include <tpm/TollingPaymentInfo.h>
#include <zmq.h>
#include <itss-management/ManagementRequest.h>
#include <itss-management/ManagementReply.h>
#include <itss-security/SecurityRequest.h>
#include <itss-security/SecurityReply.h>
static int fetch_target_address(char** addresses, uint16_t addresses_len) {
int index = -1;
for (int i = 0; i < addresses_len; ++i) {
char* addr = addresses[i];
// If TCP, ignore receiver addresses, e.g. tcp://*:[port]
if (!memcmp(addr, "tcp", 3)) {
bool found_astk = false;
for (int j = 0; j < strlen(addr); ++j) {
if (addr[j] == '*') {
found_astk = true;
break;
}
}
if (found_astk) continue;
}
index = i;
break;
}
return index;
}
int facilities_config(void* facilities_s) {
int rv = 0;
facilities_t *facilities = (facilities_t*) facilities_s;
it2s_config_t* config = calloc(1, sizeof(it2s_config_t));
rv = it2s_config_read("/etc/it2s/itss.toml", config);
if (rv) goto cleanup;
facilities->zmq.responders = calloc(config->facilities.zmq.addresses_len, sizeof(zmq_pollitem_t));
facilities->zmq.n_responders = 0;
for (int i = 0; i < config->facilities.zmq.addresses_len; ++i) {
char* addr = config->facilities.zmq.addresses[i];
// IPC
if (!memcmp(addr, "ipc", 3)) {
// Create dir
int lp = 0;
for (int j = 0; j < strlen(addr); ++j) {
if (addr[j] == '/') lp = j;
}
char dir[256];
memcpy(dir, addr+6, lp-6);
dir[lp-6] = 0;
struct stat st = {0};
if (stat(dir, &st) == -1) {
mkdir(dir, 0777);
}
// Bind
void* socket = zmq_socket(facilities->zmq.ctx, ZMQ_REP);
zmq_bind(socket, addr);
facilities->zmq.responders[facilities->zmq.n_responders].socket = socket;
facilities->zmq.responders[facilities->zmq.n_responders].events = ZMQ_POLLIN;
++facilities->zmq.n_responders;
} else if (!memcmp(addr, "tcp", 3)) {
bool found_astk = false;
for (int j = 0; j < strlen(addr); ++j) {
if (addr[j] == '*') {
found_astk = true;
break;
}
}
if (found_astk) {
// Bind
void* socket = zmq_socket(facilities->zmq.ctx, ZMQ_REP);
zmq_bind(socket, addr);
facilities->zmq.responders[facilities->zmq.n_responders].socket = socket;
facilities->zmq.responders[facilities->zmq.n_responders].events = ZMQ_POLLIN;
++facilities->zmq.n_responders;
}
}
}
if (!facilities->zmq.n_responders) {
syslog_info("[facilities] [config] a valid address to listen to was not found, exiting now");
rv = 1;
goto cleanup;
}
// Fetch [transport] address
int index = fetch_target_address(config->transport.zmq.addresses, config->transport.zmq.addresses_len);
if (index != -1) {
facilities->zmq.transport_address = malloc(strlen(config->transport.zmq.addresses[index])+1);
strcpy(facilities->zmq.transport_address, config->transport.zmq.addresses[index]);
} else {
syslog_err("[facilities] [config] a valid address for [transport] was not found");
rv = 1;
goto cleanup;
}
// Fetch [applications] address
index = fetch_target_address(config->applications.zmq.addresses, config->applications.zmq.addresses_len);
if (index != -1) {
facilities->zmq.applications_address = malloc(strlen(config->applications.zmq.addresses[index])+1);
strcpy(facilities->zmq.applications_address, config->applications.zmq.addresses[index]);
} else {
syslog_err("[facilities] [config] a valid address for [applications] was not found");
rv = 1;
goto cleanup;
}
// Fetch [security] address
index = fetch_target_address(config->security.zmq.addresses, config->security.zmq.addresses_len);
if (index != -1) {
facilities->zmq.security_address = malloc(strlen(config->security.zmq.addresses[index])+1);
strcpy(facilities->zmq.security_address, config->security.zmq.addresses[index]);
} else {
syslog_err("[facilities] [config] a valid address for [security] was not found");
rv = 1;
goto cleanup;
}
// Fetch [management] address
index = fetch_target_address(config->management.zmq.addresses, config->management.zmq.addresses_len);
if (index != -1) {
facilities->zmq.management_address = malloc(strlen(config->management.zmq.addresses[index])+1);
strcpy(facilities->zmq.management_address, config->management.zmq.addresses[index]);
} else {
syslog_err("[facilities] [config] a valid address for [management] was not found");
rv = 1;
goto cleanup;
}
// Values
// General
if (!strcmp("obu", config->general.itss_type)) {
facilities->station_type = 5;
} else if (!strcmp("rsu", config->general.itss_type)) {
facilities->station_type = 15;
} else if (!strcmp("unknown", config->general.itss_type)) {
facilities->station_type = 0;
} else if (!strcmp("pedestrian", config->general.itss_type)) {
facilities->station_type = 1;
} else if (!strcmp("cyclist", config->general.itss_type)) {
facilities->station_type = 2;
} else if (!strcmp("moped", config->general.itss_type)) {
facilities->station_type = 3;
} else if (!strcmp("motorcycle", config->general.itss_type)) {
facilities->station_type = 4;
} else if (!strcmp("passengerCar", config->general.itss_type)) {
facilities->station_type = 5;
} else if (!strcmp("bus", config->general.itss_type)) {
facilities->station_type = 6;
} else if (!strcmp("lightTruck", config->general.itss_type)) {
facilities->station_type = 7;
} else if (!strcmp("heavyTruck", config->general.itss_type)) {
facilities->station_type = 8;
} else if (!strcmp("trailer", config->general.itss_type)) {
facilities->station_type = 9;
} else if (!strcmp("specialVehicles", config->general.itss_type)) {
facilities->station_type = 10;
} else if (!strcmp("tram", config->general.itss_type)) {
facilities->station_type = 11;
} else if (!strcmp("roadSideUnit", config->general.itss_type)) {
facilities->station_type = 15;
} else {
syslog_err("[facilities] [config] unrecognized ITS-S type, running as OBU");
facilities->station_type = 5;
}
facilities->use_security = config->security.use_security;
pthread_mutex_init(&facilities->id.lock, NULL);
pthread_mutex_init(&facilities->id.change.lock, NULL);
facilities->id.change.random = config->security.identity.random;
if (facilities->id.change.random) {
// Ask [security] for station id
SecurityRequest_t* sREQ = calloc(1, sizeof(SecurityRequest_t));
SecurityReply_t* sREP = NULL;
sREQ->present = SecurityRequest_PR_ids;
sREQ->choice.ids.list.count = 2;
sREQ->choice.ids.list.size = 2*sizeof(void*);
sREQ->choice.ids.list.array = malloc(2*sizeof(void*));
sREQ->choice.ids.list.array[0] = calloc(1, sizeof(SecurityIdType_t));
*sREQ->choice.ids.list.array[0] = SecurityIdType_stationId;
sREQ->choice.ids.list.array[1] = calloc(1, sizeof(SecurityIdType_t));
*sREQ->choice.ids.list.array[1] = SecurityIdType_ipv6Address;
uint8_t b_sdu[256];
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_SecurityRequest, NULL, sREQ, b_sdu, 256);
void* ss = zmq_socket(facilities->zmq.ctx, ZMQ_REQ);
zmq_connect(ss, facilities->zmq.security_address);
zmq_send(ss, b_sdu, enc.encoded, 0);
zmq_recv(ss, b_sdu, 256, 0);
zmq_close(ss);
asn_dec_rval_t dec = oer_decode(NULL, &asn_DEF_SecurityReply, (void**) &sREP, b_sdu, 256);
if (sREP->returnCode == SecurityReplyReturnCode_rejected) {
// TODO handle it
goto cleanup;
}
for (int i = 0; i < sREP->data->choice.ids.list.count; ++i) {
switch (sREP->data->choice.ids.list.array[i]->present) {
case SecurityId_PR_stationId:
facilities->id.station_id = sREP->data->choice.ids.list.array[i]->choice.stationId;
break;
case SecurityId_PR_ipv6Address:
memcpy(facilities->id.ipv6_addr, sREP->data->choice.ids.list.array[i]->choice.ipv6Address.buf, 16);
break;
default:
break;
}
}
ASN_STRUCT_FREE(asn_DEF_SecurityRequest, sREQ);
ASN_STRUCT_FREE(asn_DEF_SecurityReply, sREP);
} else {
facilities->id.station_id = config->security.identity.station_id;
uint8_t src_mac[6];
unsigned int tmp_uint[6];
sscanf(config->security.identity.mac_address, "%02x:%02x:%02x:%02x:%02x:%02x",
&tmp_uint[0],
&tmp_uint[1],
&tmp_uint[2],
&tmp_uint[3],
&tmp_uint[4],
&tmp_uint[5]);
src_mac[0] = (uint8_t)tmp_uint[0];
src_mac[1] = (uint8_t)tmp_uint[1];
src_mac[2] = (uint8_t)tmp_uint[2];
src_mac[3] = (uint8_t)tmp_uint[3];
src_mac[4] = (uint8_t)tmp_uint[4];
src_mac[5] = (uint8_t)tmp_uint[5];
memset(facilities->id.ipv6_addr, 0, 8);
memcpy(facilities->id.ipv6_addr+8, src_mac, 3);
facilities->id.ipv6_addr[11] = 0xff;
facilities->id.ipv6_addr[12] = 0xfe;
memcpy(facilities->id.ipv6_addr+13, src_mac+3, 3);
facilities->id.ipv6_addr[8] ^= 0x02;
}
// DENM
facilities->den->n_max_events = config->facilities.denm.nmax_active_events;
// CAM
facilities->lightship->active = config->facilities.cam.activate;
facilities->lightship->vehicle_gen_min = config->facilities.cam.obu_period_min;
facilities->lightship->vehicle_gen_max = config->facilities.cam.obu_period_max;
facilities->lightship->rsu_gen_min = config->facilities.cam.rsu_period_min;
facilities->lightship->rsu_vehicle_permanence = config->facilities.cam.rsu_vehicle_permanence;
// IVIM
facilities->infrastructure->n_max_services = config->facilities.ivim.nmax_active_services;
facilities->infrastructure->replay_interval = config->facilities.ivim.replay_interval;
facilities->infrastructure->default_service_duration = config->facilities.ivim.default_service_duration * 60000;
// CPM
facilities->dissemination->active = config->facilities.cpm.activate;
facilities->dissemination->T_GenCpmMin = config->facilities.cpm.rsu_obu_period_min;
facilities->dissemination->T_GenCpmMax = config->facilities.cpm.rsu_obu_period_max;
facilities->dissemination->radar_rotation = config->applications.its_center.radar_rotation;
facilities->dissemination->tmc_connect = config->facilities.cpm.tmc_connected;
facilities->dissemination->T_AddSensorInformation = 1000;
facilities->dissemination->int_radar = malloc(strlen(config->facilities.cpm.radar_interface)+1);
strcpy(facilities->dissemination->int_radar,config->facilities.cpm.radar_interface);
facilities->dissemination->ip_radar = malloc(strlen(config->facilities.cpm.radar_ip)+1);
strcpy(facilities->dissemination->ip_radar,config->facilities.cpm.radar_ip);
// TPM
facilities->tolling.enabled = config->facilities.tpm.activate;
if (!strcmp("simple", config->facilities.tpm.protocol)) {
facilities->tolling.protocol.p = TOLLING_PROTOCOL_SIMPLE;
} else if (!strcmp("tls", config->facilities.tpm.protocol)) {
facilities->tolling.protocol.p = TOLLING_PROTOCOL_TLS;
} else {
syslog_err("[facilities] [config] unrecognized tolling protocol, defaulting to 'simple'");
facilities->tolling.protocol.p = TOLLING_PROTOCOL_SIMPLE;
}
facilities->tolling.station.obu.client_id = config->facilities.tpm.client_id;
// PCM
facilities->coordination.active = config->facilities.dcm.activate;
facilities->coordination.pcm_period_min = config->facilities.dcm.period_min;
facilities->coordination.pcm_period_max = config->facilities.dcm.period_max;
// Replay
facilities->replay = config->networking.replay.activate;
// PZ
if (facilities->station_type == 15) {
int i = 0;
DIR *d = opendir(config->facilities.protected_zones.path);
struct dirent *dir;
char file[256];
char pz_xml[2048];
if (d) {
while ((dir = readdir(d)) != NULL && i < 16) {
if (dir->d_name[0] == '.') continue;
sprintf(file, "%s/%s", config->facilities.protected_zones.path, dir->d_name);
FILE *fp = fopen(file, "r");
if (!fp) continue;
fseek(fp, 0, SEEK_END);
uint16_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (!size) {
fclose(fp);
continue;
}
if (!fread(pz_xml, 1, size, fp)) {
fclose(fp);
continue;
}
fclose(fp);
ProtectedCommunicationZone_t *zone = calloc(1, sizeof(ProtectedCommunicationZone_t));
asn_dec_rval_t dec = xer_decode(NULL, &asn_DEF_ProtectedCommunicationZone, (void**) &zone, pz_xml, size);
if (!dec.code) {
facilities->lightship->protected_zones.pz[i] = zone;
++facilities->lightship->protected_zones.pz_len;
++i;
syslog_debug("[facilities] [config] loaded protection zone @ (%lld, %lld)", zone->protectedZoneLatitude, zone->protectedZoneLongitude);
} else {
syslog_err("[facilities] [config] failure to decode protection zone '%s'", dir->d_name);
ASN_STRUCT_FREE(asn_DEF_ProtectedCommunicationZone, zone);
}
}
closedir(d);
}
}
// TZ
if (facilities->station_type == 15) {
int i = 0;
DIR *d = opendir(config->facilities.tpm.tis_path);
struct dirent *dir;
char file[256];
char ti_xml[2048];
if (d) {
while ((dir = readdir(d)) != NULL && i < TOLLING_INFOS_MAX_LENGTH) {
if (dir->d_name[0] == '.') continue;
sprintf(file, "%s/%s", config->facilities.tpm.tis_path, dir->d_name);
FILE *fp = fopen(file, "r");
if (!fp) continue;
fseek(fp, 0, SEEK_END);
uint16_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (!size) {
fclose(fp);
continue;
}
if (!fread(ti_xml, 1, size, fp)) {
fclose(fp);
continue;
}
fclose(fp);
TollingPaymentInfo_t *ti = calloc(1, sizeof(TollingPaymentInfo_t));
asn_dec_rval_t dec = xer_decode(NULL, &asn_DEF_TollingPaymentInfo, (void**) &ti, ti_xml, size);
if (!dec.code) {
facilities->tolling.infos.z[i] = calloc(1, sizeof(tolling_info_t));
facilities->tolling.infos.z[i]->asn = ti;
++facilities->tolling.infos.length;
++i;
syslog_debug("[facilities] [config] loaded tolling info | id:%lld type:%s",
ti->id,
ti->tollType==TollType_entry ? "entry": ti->tollType==TollType_exit ? "exit": "single"
);
} else {
syslog_err("[facilities] [config] failure to decode tolling info '%s'", dir->d_name);
ASN_STRUCT_FREE(asn_DEF_TollingPaymentInfo, ti);
}
}
closedir(d);
}
}
pthread_mutex_init(&facilities->epv.space.lock, NULL);
pthread_mutex_init(&facilities->epv.time.lock, NULL);
facilities->epv.time.resolution = TIME_MILLISECONDS;
ManagementRequest_t* mreq = calloc(1, sizeof(ManagementRequest_t));
mreq->present = ManagementRequest_PR_attributes;
mreq->choice.attributes.present = ManagementRequestAttributes_PR_get;
mreq->choice.attributes.choice.get.coordinates = 1;
mreq->choice.attributes.choice.get.altitude = 1;
mreq->choice.attributes.choice.get.heading = 1;
mreq->choice.attributes.choice.get.speed = 1;
mreq->choice.attributes.choice.get.gpsType = 1;
mreq->choice.attributes.choice.get.clockType = 1;
mreq->choice.attributes.choice.get.clock = 1;
mreq->choice.attributes.choice.get.clockOffset = 1;
mreq->choice.attributes.choice.get.trajectory = config->facilities.dcm.activate;
void* management_socket = zmq_socket(facilities->zmq.ctx, ZMQ_REQ);
zmq_connect(management_socket, facilities->zmq.management_address);
uint8_t buffer[256];
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_ManagementRequest, NULL, mreq, buffer, 256);
zmq_send(management_socket, buffer, enc.encoded, 0);
zmq_recv(management_socket, buffer, 256, 0);
ManagementReply_t* mrep = calloc(1, sizeof(ManagementReply_t));
oer_decode(NULL, &asn_DEF_ManagementReply, (void**) &mrep, buffer, 256);
long lat, lon, alt, alt_conf;
if (mrep->returnCode == ManagementReplyReturnCode_accepted &&
mrep->data &&
mrep->data->choice.attributes.coordinates &&
mrep->data->choice.attributes.altitude &&
mrep->data->choice.attributes.heading &&
mrep->data->choice.attributes.speed &&
mrep->data->choice.attributes.clockType &&
mrep->data->choice.attributes.clock &&
mrep->data->choice.attributes.clockOffset &&
mrep->data->choice.attributes.gpsType &&
(!!mrep->data->choice.attributes.trajectory == mreq->choice.attributes.choice.get.trajectory)) {
facilities->epv.space.latitude = mrep->data->choice.attributes.coordinates->latitude;
facilities->epv.space.latitude_conf = mrep->data->choice.attributes.coordinates->latitudeConfidence;
facilities->epv.space.longitude = mrep->data->choice.attributes.coordinates->longitude;
facilities->epv.space.longitude_conf = mrep->data->choice.attributes.coordinates->longitudeConfidence;
facilities->epv.space.altitude = mrep->data->choice.attributes.altitude->altitudeValue;
facilities->epv.space.altitude_conf = mrep->data->choice.attributes.altitude->altitudeConfidence;
facilities->epv.space.heading = mrep->data->choice.attributes.heading->headingValue;
facilities->epv.space.heading_conf = mrep->data->choice.attributes.heading->headingConfidence;
facilities->epv.space.speed = mrep->data->choice.attributes.speed->speedValue;
facilities->epv.space.speed_conf = mrep->data->choice.attributes.speed->speedConfidence;
facilities->epv.space.type = *mrep->data->choice.attributes.gpsType;
facilities->epv.time.type = *mrep->data->choice.attributes.clockType;
asn_INTEGER2ulong(mrep->data->choice.attributes.clock, (unsigned long long*) &facilities->epv.time.clock);
asn_INTEGER2ulong(mrep->data->choice.attributes.clockOffset,(unsigned long long*) &facilities->epv.time.offset);
if (config->facilities.dcm.activate) {
facilities->epv.trajectory.len = mrep->data->choice.attributes.trajectory->list.count;
for (int i = 0; i < mrep->data->choice.attributes.trajectory->list.count; ++i) {
facilities->epv.trajectory.path[i].latitude = mrep->data->choice.attributes.trajectory->list.array[i]->latitude;
facilities->epv.trajectory.path[i].longitude = mrep->data->choice.attributes.trajectory->list.array[i]->longitude;
asn_INTEGER2ulong(&mrep->data->choice.attributes.trajectory->list.array[i]->timestamp, (unsigned long long*) &facilities->epv.trajectory.path[i].timestamp);
}
}
} else {
syslog_err("[applications] rejected MR attribute request");
rv = 1;
goto cleanup;
}
ASN_STRUCT_FREE(asn_DEF_ManagementRequest, mreq);
ASN_STRUCT_FREE(asn_DEF_ManagementReply, mrep);
zmq_close(management_socket);
if (config->facilities.saem.activate) {
facilities->bulletin.to_provide_len = 1;
facilities->bulletin.to_provide[0] = calloc(1, sizeof(announcement_t));
facilities->bulletin.to_provide[0]->endpoint.port = 7011;
facilities->bulletin.to_provide[0]->its_aid = config->facilities.saem.service_to_advertise;
}
facilities->vehicle.length = config->facilities.vehicle.length;
facilities->vehicle.width = config->facilities.vehicle.width;
facilities->vehicle.role = config->facilities.vehicle.role;
// Logging
facilities->logging.recorder = config->facilities.logging.management;
if (config->general.logging.enabled && config->facilities.logging.dbms) {
facilities->logging.dbms = calloc(1, sizeof(it2s_tender_database_s));
if (it2s_tender_db_init(
facilities->logging.dbms,
config->general.logging.database,
config->general.logging.table_style,
ITSS_FACILITIES,
config->general.logging.host,
config->general.logging.port,
config->general.logging.username,
config->general.logging.password
)) {
syslog_err("[facilities] failed to initialize the database -> turning off logging");
free(facilities->logging.dbms);
facilities->logging.dbms = NULL;
}
}
cleanup:
it2s_config_free(config);
return rv;
}