#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
-#include <sys/types.h>
+#include <sys/types.h> // for ftruncate and others
+#include <unistd.h> // for ftruncate and others
+
+#include <fcntl.h> /* For O_* constants */
+#include <sys/mman.h> // for shared memory stuff
+#include <sys/select.h> // for fd_set
+#include <sys/stat.h> // umask
#ifdef CONFIG_FOR_FREEBSD
#include <netinet/in.h>
#endif
clock_source_private_data clocks_private[MAX_CLOCKS];
+client_record clients[MAX_CLIENTS];
+
+int find_client_id(char *client_shared_memory_interface_name) {
+ int response = -1; // signify not found
+ if (client_shared_memory_interface_name != NULL) {
+ int i = 0;
+ // first, see if yu can find it anywhere
+ while ((response == -1) && (i < MAX_CLIENTS)) {
+ if (strcmp(clients[i].shm_interface_name, client_shared_memory_interface_name) == 0)
+ response = i;
+ else
+ i++;
+ }
+ }
+ return response;
+}
+
+int get_client_id(char *client_shared_memory_interface_name) {
+ int response = -1; // signify not found
+ if (client_shared_memory_interface_name != NULL) {
+ int i = 0;
+ // first, see if yu can find it anywhere
+ while ((response == -1) && (i < MAX_CLIENTS)) {
+ if (strcmp(clients[i].shm_interface_name, client_shared_memory_interface_name) == 0)
+ response = i;
+ else
+ i++;
+ }
+
+ if (response == -1) { // no match, so create one
+ i = 0;
+ while ((response == -1) && (i < MAX_CLIENTS)) {
+ if (clients[i].shm_interface_name[0] == '\0')
+ response = i;
+ else
+ i++;
+ }
+ if (response != -1) {
+ pthread_mutexattr_t shared;
+ int err;
+ strncpy(clients[i].shm_interface_name, client_shared_memory_interface_name,
+ sizeof(clients[i].shm_interface_name));
+ // creat the named smi interface
+
+ // open a shared memory interface.
+ clients[i].shm_fd = -1;
+
+ mode_t oldumask = umask(0);
+ clients[i].shm_fd = shm_open(client_shared_memory_interface_name, O_RDWR | O_CREAT, 0666);
+ if (clients[i].shm_fd == -1) {
+ die("cannot open shared memory \"%s\".", client_shared_memory_interface_name);
+ }
+ (void)umask(oldumask);
+
+ if (ftruncate(clients[i].shm_fd, sizeof(struct shm_structure)) == -1) {
+ die("failed to set size of shared memory \"%s\".", client_shared_memory_interface_name);
+ }
+
+#ifdef CONFIG_FOR_FREEBSD
+ clients[i].shared_memory =
+ (struct shm_structure *)mmap(NULL, sizeof(struct shm_structure), PROT_READ | PROT_WRITE,
+ MAP_SHARED, clients[i].shm_fd, 0);
+#endif
+
+#ifdef CONFIG_FOR_LINUX
+ clients[i].shared_memory =
+ (struct shm_structure *)mmap(NULL, sizeof(struct shm_structure), PROT_READ | PROT_WRITE,
+ MAP_LOCKED | MAP_SHARED, clients[i].shm_fd, 0);
+#endif
+
+ if (clients[i].shared_memory == (struct shm_structure *)-1) {
+ die("failed to mmap shared memory \"%s\".", client_shared_memory_interface_name);
+ }
+
+ if ((close(clients[i].shm_fd) == -1)) {
+ warn("error closing \"%s\" after mapping.", client_shared_memory_interface_name);
+ }
+
+ // zero it
+ memset(clients[i].shared_memory, 0, sizeof(struct shm_structure));
+ clients[i].shared_memory->version = NQPTP_SHM_STRUCTURES_VERSION;
+
+ /*create mutex attr */
+ err = pthread_mutexattr_init(&shared);
+ if (err != 0) {
+ die("mutex attribute initialization failed - %s.", strerror(errno));
+ }
+ pthread_mutexattr_setpshared(&shared, 1);
+ /*create a mutex */
+ err = pthread_mutex_init((pthread_mutex_t *)&clients[i].shared_memory->shm_mutex, &shared);
+ if (err != 0) {
+ die("mutex initialization failed - %s.", strerror(errno));
+ }
+
+ err = pthread_mutexattr_destroy(&shared);
+ if (err != 0) {
+ die("mutex attribute destruction failed - %s.", strerror(errno));
+ }
+
+ for (i = 0; i < MAX_CLOCKS; i++) {
+ clocks_private[i].client_flags[response] =
+ 0; // turn off all client flags in every clock for this client
+ }
+ } else {
+ debug(1, "could not create a client record for client \"%s\".",
+ client_shared_memory_interface_name);
+ }
+ }
+ } else {
+ debug(1, "no client_shared_memory_interface_name");
+ }
+ return response;
+}
+
+int delete_clients() {
+ int response = 0; // okay unless something happens
+ int i;
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (clients[i].shm_interface_name[0] != '\0') {
+ if (clients[i].shared_memory != NULL) {
+ // mmap cleanup
+ if (munmap(clients[i].shared_memory, sizeof(struct shm_structure)) != 0) {
+ debug(1, "error unmapping shared memory");
+ response = -1;
+ }
+ // shm_open cleanup
+ if (shm_unlink(clients[i].shm_interface_name) == -1) {
+ debug(1, "error unlinking shared memory \"%s\"", clients[i].shm_interface_name);
+ response = -1;
+ }
+ }
+ clients[i].shm_interface_name[0] = '\0'; // remove the name, just in case
+ }
+ }
+ return response;
+}
int find_clock_source_record(char *sender_string, clock_source_private_data *clocks_private_info) {
// return the index of the clock in the clock information arrays or -1
int i = 0;
int found = 0;
while ((found == 0) && (i < MAX_CLOCKS)) {
- if ((clocks_private_info[i].in_use != 0) &&
+ if (((clocks_private_info[i].flags & (1 << clock_is_in_use)) != 0) &&
(strcasecmp(sender_string, (const char *)&clocks_private_info[i].ip) == 0))
found = 1;
else
int create_clock_source_record(char *sender_string,
clock_source_private_data *clocks_private_info) {
- // return the index of a clock entry in the clock information arrays or -1 if full
+ // return the index of a clock entry in the clock information arrays or -1 if full
// initialise the entries in the shared and private arrays
int response = -1;
int i = 0;
int found = 0; // trying to find an unused entry
while ((found == 0) && (i < MAX_CLOCKS)) {
- if (clocks_private_info[i].in_use == 0)
+ if ((clocks_private_info[i].flags & (1 << clock_is_in_use)) == 0)
found = 1;
else
i++;
#ifdef MAX_TIMING_SAMPLES
clocks_private_info[i].vacant_samples = MAX_TIMING_SAMPLES;
#endif
- clocks_private_info[i].in_use = 1;
+ clocks_private_info[i].flags |= (1 << clock_is_in_use);
debug(2, "create record for ip: %s, family: %s.", &clocks_private_info[i].ip,
clocks_private_info[i].family == AF_INET6 ? "IPv6" : "IPv4");
} else {
// do a garbage collect for clock records no longer in use
for (i = 0; i < MAX_CLOCKS; i++) {
// only if its in use and not a timing peer... don't need a mutex to check
- if ((clocks_private_info[i].in_use != 0) &&
+ if (((clocks_private_info[i].flags & (1 << clock_is_in_use)) != 0) &&
((clocks_private_info[i].flags & (1 << clock_is_a_timing_peer)) == 0)) {
int64_t time_since_last_use = reception_time - clocks_private_info[i].time_of_last_use;
// using a sync timeout to determine when to drop the record...
debug(2, "delete record for: %s.", &clocks_private_info[i].ip);
memset(&clocks_private_info[i], 0, sizeof(clock_source_private_data));
if (old_flags != 0)
- update_master();
+ update_master(0); // TODO
else
debug_log_nqptp_status(2);
}
// first, turn off all the self-id flags
int i;
for (i = 0; i < MAX_CLOCKS; i++) {
- clocks_private_info[i].is_one_of_ours = 0;
+ clocks_private_info[i].flags &= ~(1 << clock_is_one_of_ours);
}
struct ifaddrs *ifap, *ifa;
if (addr != NULL)
inet_ntop(family, addr, ip_string, sizeof(ip_string));
if (strlen(ip_string) != 0) {
- // now set the is_one_of_ours flag of any clock with this ip
+ // now set the clock_is_one_of_ours flag of any clock with this ip
for (i = 0; i < MAX_CLOCKS; i++) {
if (strcasecmp(ip_string, clocks_private_info[i].ip) == 0) {
debug(2, "found an entry for one of our clocks");
- clocks_private_info[i].is_one_of_ours = 1;
+ clocks_private_info[i].flags |= (1 << clock_is_one_of_ours);
}
}
}
int records_in_use = 0;
int i;
for (i = 0; i < MAX_CLOCKS; i++)
- if (clocks_private[i].in_use != 0)
+ if ((clocks_private[i].flags & (1 << clock_is_in_use)) != 0)
records_in_use++;
debug(level, "");
if (records_in_use > 0) {
uint32_t non_peer_clock_mask = (1 << clock_is_valid);
uint32_t non_peer_master_mask = non_peer_clock_mask | (1 << clock_is_master);
for (i = 0; i < MAX_CLOCKS; i++) {
- if (clocks_private[i].in_use != 0) {
+ if ((clocks_private[i].flags & (1 << clock_is_in_use)) != 0) {
if ((clocks_private[i].flags & peer_master_mask) == peer_master_mask) {
debug(level, " Peer Master: %" PRIx64 " %s.", clocks_private[i].clock_id,
clocks_private[i].ip);
}
}
-void update_master() {
+void update_master(int client_id) {
// This implements the IEEE 1588-2008 best master clock algorithm.
}
if (best_so_far == -1) {
// no master clock
- //if (old_master != -1) {
- // but there was a master clock, so remove it
- debug(1, "Remove master clock.");
- update_master_clock_info(0, NULL, 0, 0, 0);
+ // if (old_master != -1) {
+ // but there was a master clock, so remove it
+ debug(1, "Remove master clock.");
+ update_master_clock_info(0, NULL, 0, 0, 0);
//}
if (timing_peer_count == 0)
debug(2, "no valid qualified clocks ");
#include "nqptp.h"
-// transaction tracking
-enum stage { waiting_for_sync, sync_seen, follow_up_seen };
-
typedef enum {
+ clock_is_in_use,
+ clock_is_one_of_ours,
clock_is_valid,
clock_is_a_timing_peer,
clock_is_qualified,
clock_is_master
} clock_flags;
-// 8 samples per seconds
-// #define MAX_TIMING_SAMPLES 47
-// #define MAX_TIMING_SAMPLES 1
-
-#ifdef MAX_TIMING_SAMPLES
-typedef struct {
- uint64_t local_time, clock_time;
-} timing_samples;
-#endif
+/*
+typedef enum {
+ clock_is_a_timing_peer,
+ clock_is_becoming_master,
+ clock_is_master
+} client_flags;
+*/
// information about each clock source
typedef struct {
uint64_t local_time; // the local time when the offset was calculated
uint64_t source_time;
uint64_t local_to_source_time_offset; // add this to the local time to get source time
- uint32_t flags;
- uint16_t in_use;
uint64_t previous_offset, previous_offset_time, last_sync_time;
uint64_t mastership_start_time; // set to the time of the first sample used as master
// timing peer group
// (A member of the timing peer group could appear and disappear so will not be gc'ed.)
// for Announce Qualification
- uint64_t announce_times[4]; // we'll check qualification and currency using these
- int is_one_of_ours; // true if it is one of our own clocks
-
-#ifdef MAX_TIMING_SAMPLES
- timing_samples samples[MAX_TIMING_SAMPLES];
- int vacant_samples; // the number of elements in the timing_samples array that are not yet used
- int next_sample_goes_here; // point to where in the timing samples array the next entries should
- // go
-#endif
+ uint64_t announce_times[4]; // we'll check qualification and currency using these
+ uint8_t flags; // stuff related specifically to the clock itself
+ uint8_t client_flags[MAX_CLIENTS]; // stuff related to membership of the clients' timing lists
// these are for finding the best clock to use
// See Figure 27 and 27 pp 89 -- 90 for the Data set comparison algorithm
} clock_source_private_data;
+// information on each client
+typedef struct {
+ int shm_fd;
+ struct shm_structure *shared_memory; // the client's individual smi interface
+ char shm_interface_name[64]; // it's name
+ int client_id; // the 1-based index number of clocks' client_flags field associated with this
+ // interface
+} client_record;
+
int find_clock_source_record(char *sender_string, clock_source_private_data *clocks_private_info);
int create_clock_source_record(char *sender_string, clock_source_private_data *clocks_private_info);
void manage_clock_sources(uint64_t reception_time, clock_source_private_data *clocks_private_info);
+int find_client_id(char *client_shared_memory_interface_name);
+
+int get_client_id(char *client_shared_memory_interface_name);
+
+int delete_clients();
+
extern clock_source_private_data clocks_private[MAX_CLOCKS];
-void update_master();
+void update_master(int client_id);
void debug_log_nqptp_status(int level);
clock_source_private_data *clock_private_info) {
if (recv_len != -1) {
buf[recv_len - 1] = 0; // make sure there's a null in it!
- debug(2, "New timing peer list: \"%s\".", buf);
- if (buf[0] == 'T') {
-
- char *ip_list = buf + 1;
- if (*ip_list == ' ')
- ip_list++;
-
- // turn off all is_timing_peer flags
- int i;
- for (i = 0; i < MAX_CLOCKS; i++) {
- clock_private_info[i].flags &=
- ~(1 << clock_is_a_timing_peer); // turn off peer flag (but not the master flag!)
- clock_private_info[i].announcements_without_followups = 0; // to allow a possibly silent clocks to be revisited when added to a timing peer list
- if (strlen(buf) == 1) { // if it's giving an empty timing peer list, that means drop mastership from the past
- clock_private_info[i].flags &= ~(1 << clock_is_master);
- clock_private_info[i].mastership_start_time = 0;
- clock_private_info[i].previous_offset_time = 0;
- }
- }
-
- while (ip_list != NULL) {
- char *new_ip = strsep(&ip_list, " ");
- // look for the IP in the list of clocks, and create an inert entry if not there
- if ((new_ip != NULL) && (new_ip[0] != 0)) {
- int t = find_clock_source_record(new_ip, clock_private_info);
- if (t == -1)
- t = create_clock_source_record(new_ip, clock_private_info);
- if (t != -1) // if the clock table is not full, show it's a timing peer
- clock_private_info[t].flags |= (1 << clock_is_a_timing_peer);
- // otherwise, drop it
+ debug(1, "New control port message: \"%s\".", buf);
+ // we need to get the client shared memory interface name from the front
+ char *ip_list = buf;
+ char *smi_name = strsep(&ip_list, " ");
+ char *command = NULL;
+ if (smi_name != NULL) {
+ debug(1, "SMI Name: \"%s\"", smi_name);
+ int client_id = 0;
+ if (ip_list != NULL)
+ command = strsep(&ip_list, " ");
+ if ((command == NULL) || ((strcmp(command, "T") == 0) && (ip_list == NULL))) {
+ // clear all the flags, but only if the client exists
+ client_id = find_client_id(smi_name); // don't create a record
+ if (client_id != -1) {
+ // turn off all is_timing_peer flags
+ int i;
+ for (i = 0; i < MAX_CLOCKS; i++) {
+ // e.g. (obsolete)
+ clock_private_info[i].flags &= ~(1 << clock_is_master);
+ clock_private_info[i].mastership_start_time = 0;
+ clock_private_info[i].previous_offset_time = 0;
+
+ // if a clock would now stop being a master everywhere
+ // it should drop mastership history and do a sync when it becomes master again
+ if ((clock_private_info[i].client_flags[client_id] & (1 << clock_is_master)) !=
+ 0) { // if clock[i] is master for this client's timing group
+ int c;
+ int this_clock_is_master_elsewhere = 0;
+ for (c = 0; c < MAX_CLIENTS; c++) {
+ if ((c != client_id) &&
+ ((clock_private_info[i].client_flags[c] & (1 << clock_is_master)) != 0))
+ this_clock_is_master_elsewhere = 1;
+ }
+ if (this_clock_is_master_elsewhere == 0) {
+ clock_private_info[i].mastership_start_time = 0;
+ clock_private_info[i].previous_offset_time = 0;
+ }
+ }
+ clock_private_info[i].client_flags[client_id] = 0;
+ }
}
- }
+ } else {
+ client_id = get_client_id(smi_name); // create the record if it doesn't exist
+ if (client_id != -1) {
+ if (strcmp(command, "T") == 0) {
+ // turn off all is_timing_peer flags
+ int i;
+ for (i = 0; i < MAX_CLOCKS; i++) {
+ clock_private_info[i].flags &=
+ ~(1 << clock_is_a_timing_peer); // turn off peer flag (but not the master flag!)
+ clock_private_info[i].client_flags[client_id] &=
+ ~(1 << clock_is_a_timing_peer); // turn off peer flag (but not the master flag!)
+ clock_private_info[i].announcements_without_followups =
+ 0; // to allow a possibly silent clock to be revisited when added to a timing
+ // peer list
+ }
+ while (ip_list != NULL) {
+ char *new_ip = strsep(&ip_list, " ");
+ // look for the IP in the list of clocks, and create an inert entry if not there
+ if ((new_ip != NULL) && (new_ip[0] != 0)) {
+ int t = find_clock_source_record(new_ip, clock_private_info);
+ if (t == -1)
+ t = create_clock_source_record(new_ip, clock_private_info);
+ if (t != -1) { // if the clock table is not full, show it's a timing peer
+ clock_private_info[t].flags |= (1 << clock_is_a_timing_peer);
+ clock_private_info[t].client_flags[client_id] |= (1 << clock_is_a_timing_peer);
+ }
+ // otherwise, drop it
+ }
+ }
- // now find and mark the best clock in the timing peer list as the master
- update_master();
+ // now find and mark the best clock in the timing peer list as the master
+ update_master(client_id);
- debug(2, "Timing group start");
- for (i = 0; i < MAX_CLOCKS; i++) {
- if ((clock_private_info[i].flags & (1 << clock_is_a_timing_peer)) != 0)
- debug(2, "%s.", &clock_private_info[i].ip);
+ debug(2, "Timing group start");
+ for (i = 0; i < MAX_CLOCKS; i++) {
+ if ((clock_private_info[i].client_flags[client_id] & (1 << clock_is_a_timing_peer)) !=
+ 0)
+ debug(2, "%s.", &clock_private_info[i].ip);
+ }
+ debug(2, "Timing group end");
+ } else {
+ warn("Unrecognised string on the control port.");
+ }
+ } else {
+ warn("Could not find or create a record for SMI Interface \"%s\".", smi_name);
+ }
}
- debug(2, "Timing group end");
} else {
- warn("Unrecognised string on the control port.");
+ warn("SMI Interface Name not found on the control port.");
}
} else {
warn("Bad packet on the control port.");
void handle_announce(char *buf, ssize_t recv_len, clock_source_private_data *clock_private_info,
uint64_t reception_time) {
- // reject Announce messages from self
- if (clock_private_info->is_one_of_ours == 0) {
+ // only process Announce messages that do not come from self
+ if ((clock_private_info->flags & (1 << clock_is_one_of_ours)) == 0) {
// debug_print_buffer(1, buf, (size_t) recv_len);
// make way for the new time
if ((size_t)recv_len >= sizeof(struct ptp_announce_message)) {
clock_private_info->flags &= ~(1 << clock_is_qualified);
else
clock_private_info->flags |= (1 << clock_is_qualified);
- update_master();
+ update_master(0); // TODO -- use client_id here
}
} else {
if ((clock_private_info->flags & (1 << clock_is_qualified)) !=
time_since_previous_offset = reception_time - clock_private_info->previous_offset_time;
}
-
if ((clock_private_info->flags & (1 << clock_is_becoming_master)) != 0) {
// we definitely have at least one sample since the request was made to
// designate it a master, so we assume it is legitimate. That is, we assume
clock_private_info->flags |= 1 << clock_is_master;
clock_private_info->previous_offset_time = 0;
debug_log_nqptp_status(2);
- } else if ((clock_private_info->previous_offset_time != 0) && (time_since_previous_offset < 300000000000)) {
+ } else if ((clock_private_info->previous_offset_time != 0) &&
+ (time_since_previous_offset < 300000000000)) {
// i.e. if it's not becoming a master and there has been a previous follow_up
int64_t time_since_last_sync = reception_time - clock_private_info->last_sync_time;
int64_t sync_timeout = 300000000000; // nanoseconds
// we take any positive or a limited negative jitter as a sync event
if (jitter < 0) {
if (clock_private_info->follow_up_number <
- (5 * 8)) // at the beginning (8 samples per second)
+ (5 * 8)) // at the beginning (8 samples per second)
offset = clock_private_info->previous_offset + jitter / 16;
else
offset = clock_private_info->previous_offset + jitter / 64;
} else if (clock_private_info->follow_up_number <
- (5 * 8)) // at the beginning (8 samples per second)
+ (5 * 8)) // at the beginning (8 samples per second)
offset =
clock_private_info->previous_offset + jitter / 1; // accept positive changes quickly
else
clock_private_info->ip);
// leave the offset as it was coming in and take it as a sync time
clock_private_info->last_sync_time = reception_time;
- clock_private_info->mastership_start_time = reception_time; // mastership is reset to this time...
+ clock_private_info->mastership_start_time =
+ reception_time; // mastership is reset to this time...
clock_private_info->previous_offset_time = 0;
}
} else {
clock_private_info->last_sync_time = reception_time;
if (time_since_previous_offset >= 300000000000) {
- debug(1,"Long interval: %f seconds since previous follow_up", time_since_previous_offset * 1E-9);
- clock_private_info->mastership_start_time = reception_time; // mastership is reset to this time...
+ debug(1, "Long interval: %f seconds since previous follow_up",
+ time_since_previous_offset * 1E-9);
+ clock_private_info->mastership_start_time =
+ reception_time; // mastership is reset to this time...
clock_private_info->previous_offset_time = 0;
}
}
clock_private_info->ip);
clock_private_info->flags |=
(1 << clock_is_valid); // valid because it has at least one follow_up
- update_master();
+ update_master(0); // TODO
}
}
#ifndef NQPTP_MESSAGE_HANDLERS_H
#define NQPTP_MESSAGE_HANDLERS_H
-#include <sys/types.h>
#include "general-utilities.h"
#include "nqptp-clock-sources.h"
+#include <sys/types.h>
void handle_announce(char *buf, ssize_t recv_len, clock_source_private_data *clock_private_info,
uint64_t reception_time);
#ifndef NQPTP_SHM_STRUCTURES_H
#define NQPTP_SHM_STRUCTURES_H
-#define STORAGE_ID "/nqptp"
-#define MAX_CLOCKS 64
-#define NQPTP_SHM_STRUCTURES_VERSION 6
+#define NQPTP_SHM_STRUCTURES_VERSION 7
#define NQPTP_CONTROL_PORT 9000
-// the control port will accept a UDP packet with the first letter being:
-// "T", followed by a space and then a space-delimited
-// list of ip numbers, either IPv4 or IPv6
+// The control port will accept a UDP packet with the first letter being
+// "T", followed by the name of the shared memory interface, which should be of
+// the form nqptp-<up-to-12-hex-digits>. This can be followed by nothing or by
+// a space and then a space-delimited list of ip numbers, either IPv4 or IPv6
// the whole not to exceed 4096 characters in total
-// The IPs will become the new list of timing peers, replacing any previous
+// The IPs, if provided, will become the new list of timing peers, clearing or replacing any
+// previous list. If the master clock of the new list is the same as that of the old list, it is
+// retained without having to resynchronise. This means that non-master devices can be added and
+// removed without disturbing the existing-and-continuing master clock.
#include <inttypes.h>
#include <pthread.h>
struct shm_structure {
pthread_mutex_t shm_mutex; // for safely accessing the structure
uint16_t version; // check this is equal to NQPTP_SHM_STRUCTURES_VERSION
- uint32_t flags; // unused
uint64_t master_clock_id; // the current master clock
char master_clock_ip[64]; // where it's coming from
uint64_t local_time; // the time when the offset was calculated
sockets_open_bundle sockets_open_stuff;
-int master_clock_index = -1;
-
typedef struct {
uint64_t trigger_time;
uint64_t (*task)(uint64_t nominal_call_time, void *private_data);
void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time,
uint64_t local_to_master_offset, uint64_t mastership_start_time) {
- //debug(1,"update_master_clock_info start");
+ // debug(1,"update_master_clock_info start");
if (shared_memory->master_clock_id != master_clock_id)
debug_log_nqptp_status(1);
int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
rc = pthread_mutex_unlock(&shared_memory->shm_mutex);
if (rc != 0)
warn("Can't release mutex after updating master clock!");
- //debug(1,"update_master_clock_info done");
+ // debug(1,"update_master_clock_info done");
}
void goodbye(void) {
unsigned int i;
for (i = 0; i < sockets_open_stuff.sockets_open; i++)
close(sockets_open_stuff.sockets[i].number);
+ // close off shared memory interfaces
+
if (shared_memory != NULL) {
// mmap cleanup
if (munmap(shared_memory, sizeof(struct shm_structure)) != 0)
if (shm_unlink(STORAGE_ID) == -1)
debug(1, "error unlinking shared memory \"%s\"", STORAGE_ID);
}
+
+ delete_clients();
+
if (epoll_fd != -1)
close(epoll_fd);
int i;
for (i = 0; i < MAX_CLOCKS; i++) {
if ((clocks_private[i].announcements_without_followups == 3) &&
- (clocks_private[i].is_one_of_ours == 0)) {
+ ((clocks_private[i].flags & (1 << clock_is_one_of_ours)) == 0)) {
debug(1, "Found a silent clock %" PRIx64 " at %s.", clocks_private[i].clock_id,
clocks_private[i].ip);
// send an Announce message to attempt to waken this silent PTP clock by
}
}
-/*
- uint64_t announce_interval = 1;
- announce_interval = announce_interval << (8 + aPTPinitialLogAnnounceInterval);
- announce_interval = announce_interval * 1000000000;
- announce_interval = announce_interval >> 8; // nanoseconds
- return call_time + announce_interval;
-*/
+ /*
+ uint64_t announce_interval = 1;
+ announce_interval = announce_interval << (8 + aPTPinitialLogAnnounceInterval);
+ announce_interval = announce_interval * 1000000000;
+ announce_interval = announce_interval >> 8; // nanoseconds
+ return call_time + announce_interval;
+ */
return call_time + 50000000;
}
#include "nqptp-shm-structures.h"
+#define STORAGE_ID "/nqptp"
+#define MAX_CLOCKS 64
+#define MAX_CLIENTS 16
#define MAX_OPEN_SOCKETS 16
// When a new timing peer group is created, one of the clocks in the
-// group becomes the master and its native time becomes the "master time".
+// group may become the master and its native time becomes the "master time".
// This is what is provided to the client.
-extern int master_clock_index;
-extern struct shm_structure *shared_memory;
+// An NQPTP client interface communicates through a shared memory interface named by the
+// shm_interface_name It provides the shm_interface_name at the start of every control message it
+// sends through port 9000. Following the name, the client can specify the members -- the "PTP
+// Instances" -- of a "PTP Network" it wishes to monitor. This is a "timing group" in AirPlay 2
+// parlance, it seems.
void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time,
uint64_t local_to_master_offset, uint64_t mastership_start_time);