Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package nqptp for openSUSE:Factory checked 
in at 2024-09-05 15:47:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nqptp (Old)
 and      /work/SRC/openSUSE:Factory/.nqptp.new.10096 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nqptp"

Thu Sep  5 15:47:36 2024 rev:2 rq:1198918 version:1.2.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/nqptp/nqptp.changes      2023-06-26 
18:16:51.066672213 +0200
+++ /work/SRC/openSUSE:Factory/.nqptp.new.10096/nqptp.changes   2024-09-05 
15:48:26.875211250 +0200
@@ -1,0 +2,24 @@
+Tue Sep  3 09:06:57 UTC 2024 - Wolfgang Frisch <wolfgang.fri...@suse.com>
+
+- Backports from 1.2.5-dev
+  - Add backport-b5321a88d21b854aaa461dc0f6c226d650309b91.patch
+    Remove setcap call.
+  - Add backport-050a8c2de9f3e1f4859abf9b36d2f18afd4c34d7.patch
+    Set capability in the systemd unit instead.
+
+- Add disable-user-group-generation.patch
+  Disable user/group generation in the Makefile.
+  Let systemd-sysusers handle this instead.
+
+- Update to 1.2.4
+  - Further changes are introduced to make the communication path between NQPTP
+    and Shairport Sync resistant to outside interference. These changes have
+    necessitated changing the SMI interface. The SMI interface is now at
+    version 10, and Shairport Sync must also be updated to be compatible with
+    it.
+
+- Update to 1.2.3
+  - Fix CVE-2023-43771: nqptp: NULL pointer dereference caused by invalid
+    control port message (boo#1213060)
+
+-------------------------------------------------------------------

Old:
----
  nqptp-1.2.1.tar.gz

New:
----
  backport-050a8c2de9f3e1f4859abf9b36d2f18afd4c34d7.patch
  backport-b5321a88d21b854aaa461dc0f6c226d650309b91.patch
  disable-user-group-generation.patch
  nqptp-1.2.4.tar.gz
  nqptp-user.conf

BETA DEBUG BEGIN:
  New:    Remove setcap call.
  - Add backport-050a8c2de9f3e1f4859abf9b36d2f18afd4c34d7.patch
    Set capability in the systemd unit instead.
  New:- Backports from 1.2.5-dev
  - Add backport-b5321a88d21b854aaa461dc0f6c226d650309b91.patch
    Remove setcap call.
  New:
- Add disable-user-group-generation.patch
  Disable user/group generation in the Makefile.
BETA DEBUG END:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ nqptp.spec ++++++
--- /var/tmp/diff_new_pack.fOWLv9/_old  2024-09-05 15:48:27.271227696 +0200
+++ /var/tmp/diff_new_pack.fOWLv9/_new  2024-09-05 15:48:27.275227862 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package nqptp
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,16 +17,24 @@
 
 
 Name:           nqptp
-Version:        1.2.1
+Version:        1.2.4
 Release:        0
 Summary:        Not Quite PTP
 License:        GPL-2.0-only
 URL:            https://github.com/mikebrady/nqptp
 Source0:        
https://github.com/mikebrady/%{name}/archive/%{version}/%{name}-%{version}.tar.gz
+Source1:        nqptp-user.conf
+# Backported from 1.2.5-dev:
+Patch0:         backport-050a8c2de9f3e1f4859abf9b36d2f18afd4c34d7.patch
+# Backported from 1.2.5-dev:
+Patch1:         backport-b5321a88d21b854aaa461dc0f6c226d650309b91.patch
+Patch2:         disable-user-group-generation.patch
 BuildRequires:  autoconf
 BuildRequires:  automake
 BuildRequires:  systemd-rpm-macros
+BuildRequires:  sysuser-tools
 %{?systemd_ordering}
+%sysusers_requires
 
 %description
 nqptp is a daemon that monitors timing data from any PTP clocks – up to 64 
– it
@@ -37,18 +45,20 @@
 for AirPlay 2 operation.
 
 %prep
-%autosetup
+%autosetup -p1
 
 %build
 autoreconf -i -f
 %configure --with-systemd-startup
 %make_build
+%sysusers_generate_pre %{SOURCE1} nqptp nqptp-user.conf
 
 %install
 %make_install
 mkdir -p %{buildroot}%{_unitdir}
 mv %{buildroot}%{_libdir}/systemd/system/%{name}.service \
    %{buildroot}%{_unitdir}/%{name}.service
+install -D -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/nqptp.conf
 
 %pre
 %service_add_pre %{name}.service
@@ -67,4 +77,5 @@
 %doc README.md RELEASE_NOTES.md
 %{_bindir}/%{name}
 %{_unitdir}/%{name}.service
+%{_sysusersdir}/nqptp.conf
 

++++++ backport-050a8c2de9f3e1f4859abf9b36d2f18afd4c34d7.patch ++++++
>From 050a8c2de9f3e1f4859abf9b36d2f18afd4c34d7 Mon Sep 17 00:00:00 2001
From: Hs_Yeah <bye...@gmail.com>
Date: Tue, 19 Sep 2023 03:12:47 +0800
Subject: [PATCH] Added AmbientCapabilities to nqptp.service.in

Added AmbientCapabilities=CAP_NET_BIND_SERVICE
so that the systemd service can be used without the  capability set on the 
built nqptp binary.
---
 nqptp.service.in | 1 +
 1 file changed, 1 insertion(+)

diff --git a/nqptp.service.in b/nqptp.service.in
index 6f1eb0c..53e6a2e 100644
--- a/nqptp.service.in
+++ b/nqptp.service.in
@@ -8,6 +8,7 @@ Before=shairport-sync.service
 ExecStart=@prefix@/bin/nqptp
 User=nqptp
 Group=nqptp
+AmbientCapabilities=CAP_NET_BIND_SERVICE
 
 [Install]
 WantedBy=multi-user.target

++++++ backport-b5321a88d21b854aaa461dc0f6c226d650309b91.patch ++++++
>From b5321a88d21b854aaa461dc0f6c226d650309b91 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebr...@users.noreply.github.com>
Date: Tue, 19 Sep 2023 11:08:27 +0100
Subject: [PATCH] Improve some of the error messages. Remove the setcap command
 from Makefile.am, since we are now using an AmbientCapabilities setting in
 the systemd service file.

---
 Makefile.am       |  5 +++--
 configure.ac      |  2 +-
 nqptp-utilities.c | 14 +++++---------
 nqptp.c           |  2 +-
 4 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 78f36d7..d2b3992 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,8 +19,9 @@ endif
 
 install-exec-hook:
 if BUILD_FOR_LINUX
-# NQPTP runs as user/group nqptp/nqptp on Linux and uses setcap to access 
ports 319 and 320
-       setcap 'cap_net_bind_service=+ep' $(bindir)/nqptp
+# Note: NQPTP runs as user/group nqptp/nqptp on Linux.
+# Access is given via AmbientCapabilities in the service file.
+# If you want to run it from the command line, e.g. for debugging, run it as 
root user.
 # no installer for System V
 if INSTALL_SYSTEMD_STARTUP
        getent group nqptp &>/dev/null || groupadd -r nqptp &>/dev/null
diff --git a/nqptp-utilities.c b/nqptp-utilities.c
index 9d6a95d..9964b22 100644
--- a/nqptp-utilities.c
+++ b/nqptp-utilities.c
@@ -105,15 +105,11 @@ void open_sockets_at_port(const char *node, uint16_t port,
   }
   freeaddrinfo(info);
   if (sockets_opened == 0) {
-    if (port < 1024)
-      die("unable to listen on port %d. The error is: \"%s\". NQPTP must run 
as root to access "
-          "this port. Or is another PTP daemon -- possibly another instance on 
NQPTP -- running "
-          "already?",
-          port, strerror(errno));
-    else
-      die("unable to listen on port %d. The error is: \"%s\". "
-          "Is another instance on NQPTP running already?",
-          port, strerror(errno));
+    if (errno == EACCES) {
+      die("nqptp does not have permission to access port %u. It must (a) 
[Linux only] have been given CAP_NET_BIND_SERVICE capabilities using e.g. 
setcap or systemd's AmbientCapabilities, or (b) run as root.", port);
+    } else {
+      die("nqptp is unable to listen on port %u. The error is: %d, \"%s\".", 
port, errno, strerror(errno));
+    }
   }
 }
 
diff --git a/nqptp.c b/nqptp.c
index e5f2988..a1a3c76 100644
--- a/nqptp.c
+++ b/nqptp.c
@@ -198,7 +198,7 @@ int main(int argc, char **argv) {
   mode_t oldumask = umask(0);
   shm_fd = shm_open(NQPTP_INTERFACE_NAME, O_RDWR | O_CREAT, 0644);
   if (shm_fd == -1) {
-    die("cannot open shared memory \"%s\".", NQPTP_INTERFACE_NAME);
+    die("nqptp cannot open the shared memory \"%s\" for writing. Is another 
copy of nqptp (e.g. an nqptp daemon) running already?", NQPTP_INTERFACE_NAME);
   }
   (void)umask(oldumask);
 

++++++ disable-user-group-generation.patch ++++++
Index: nqptp-1.2.4/Makefile.am
===================================================================
--- nqptp-1.2.4.orig/Makefile.am
+++ nqptp-1.2.4/Makefile.am
@@ -24,8 +24,6 @@ if BUILD_FOR_LINUX
 # If you want to run it from the command line, e.g. for debugging, run it as 
root user.
 # no installer for System V
 if INSTALL_SYSTEMD_STARTUP
-       getent group nqptp &>/dev/null || groupadd -r nqptp &>/dev/null
-       getent passwd nqptp &> /dev/null || useradd -r -M -g nqptp -s 
/usr/sbin/nologin nqptp &>/dev/null
        [ -e $(DESTDIR)$(libdir)/systemd/system ] || mkdir -p 
$(DESTDIR)$(libdir)/systemd/system
 # don't replace a service file if it already exists...
        [ -e $(DESTDIR)$(libdir)/systemd/system/nqptp.service ] || cp 
nqptp.service $(DESTDIR)$(libdir)/systemd/system

++++++ nqptp-1.2.1.tar.gz -> nqptp-1.2.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/Makefile.am new/nqptp-1.2.4/Makefile.am
--- old/nqptp-1.2.1/Makefile.am 2023-05-22 11:18:48.000000000 +0200
+++ new/nqptp-1.2.4/Makefile.am 2023-09-16 19:51:55.000000000 +0200
@@ -19,14 +19,20 @@
 
 install-exec-hook:
 if BUILD_FOR_LINUX
+# NQPTP runs as user/group nqptp/nqptp on Linux and uses setcap to access 
ports 319 and 320
+       setcap 'cap_net_bind_service=+ep' $(bindir)/nqptp
+# no installer for System V
 if INSTALL_SYSTEMD_STARTUP
+       getent group nqptp &>/dev/null || groupadd -r nqptp &>/dev/null
+       getent passwd nqptp &> /dev/null || useradd -r -M -g nqptp -s 
/usr/sbin/nologin nqptp &>/dev/null
        [ -e $(DESTDIR)$(libdir)/systemd/system ] || mkdir -p 
$(DESTDIR)$(libdir)/systemd/system
 # don't replace a service file if it already exists...
        [ -e $(DESTDIR)$(libdir)/systemd/system/nqptp.service ] || cp 
nqptp.service $(DESTDIR)$(libdir)/systemd/system
 endif
 endif
- # no installer for FreeBSD yet
+
 if BUILD_FOR_FREEBSD
+# NQPTP runs as root on FreeBSD to access ports 319 and 320
 if INSTALL_FREEBSD_STARTUP
        cp nqptp.freebsd /usr/local/etc/rc.d/nqptp
        chmod 555 /usr/local/etc/rc.d/nqptp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/README.md new/nqptp-1.2.4/README.md
--- old/nqptp-1.2.1/README.md   2023-05-22 11:18:48.000000000 +0200
+++ new/nqptp-1.2.4/README.md   2023-09-16 19:51:55.000000000 +0200
@@ -1,11 +1,8 @@
 # NQPTP – Not Quite PTP
-`nqptp` is a daemon that monitors timing data from any 
[PTP](https://en.wikipedia.org/wiki/Precision_Time_Protocol) clocks – up to 
64 – it sees on ports 319 and 320. It maintains records for each clock, 
identified by Clock ID and IP.
+`nqptp` is a daemon that monitors timing data from 
[PTP](https://en.wikipedia.org/wiki/Precision_Time_Protocol) clocks it sees on 
ports 319 and 320. It maintains records for one clock, identified by its Clock 
ID.
 
 It is a companion application to [Shairport 
Sync](https://github.com/mikebrady/shairport-sync) and provides timing 
information for AirPlay 2 operation.
 
-# Development
-This branch -- the `development` branch -- changes relatively rapidly and may 
contain significant bugs. The `main` branch is the most stable. Use it with the 
`development` branch of Shairport Sync.
-
 ## Installation
 
 This guide is for recent Linux and FreeBSD systems.
@@ -25,9 +22,10 @@
 ```
 ### Remove Old Service Files
 #### Linux
-If you are updating from version 1.1-dev-51 or earlier in Linux, remove the 
service file `nqptp.service` from the directory `/lib/systemd/system` (you'll 
need superuser privileges):
+If you are updating from version `1.2.4d0` or earlier in Linux, remove the 
service file `nqptp.service` from the directory `/lib/systemd/system` (you'll 
need superuser privileges):
 ```
 # rm /lib/systemd/system/nqptp.service
+# systemctl daemon-reload
 ```
 Don't worry if you get a message stating that the file doesn't exist -- no 
harm done.
 
@@ -44,8 +42,6 @@
 ```
 $ git clone https://github.com/mikebrady/nqptp.git
 $ cd nqptp
-$ git checkout development
-$ autoreconf -fi
 $ ./configure --with-systemd-startup
 $ make
 # make install
@@ -54,7 +50,6 @@
 ```
 $ git clone https://github.com/mikebrady/nqptp.git
 $ cd nqptp
-$ git checkout development
 $ autoreconf -fi
 $ ./configure --with-freebsd-startup
 $ make
@@ -111,9 +106,10 @@
 ```
 
 ## Notes
-Please note that `nqptp` must run in `root` mode to be able to access ports 
319 and 320.
-
-Since `nqptp` uses ports 319 and 320, it can not coexist with any other user 
of those ports, such as full PTP service daemons.
+The `nqptp` application requires exclusive access to ports 319 and 320.
+This means that it can not coexist with any other user of those ports, such as 
full PTP service daemons.
+In Linux, `nqptp` runs as a low-priviliged user but is given special access to 
ports 319 and 320 during installation using the `setcap` utility.
+In FreeBSD, `nqptp` runs as `root` user.
 
 ## Programming Notes
 Commands and status information are sent to `nqptp` over port 9000. 
@@ -123,23 +119,30 @@
 
 Here are details of the interface:
 ```c
-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
+typedef struct {
   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
   uint64_t local_to_master_time_offset; // add this to the local time to get 
master clock time
   uint64_t master_clock_start_time;     // this is when the master clock 
became master
+} shm_structure_set;
+
+// The actual interface comprises a shared memory region of type struct 
shm_structure.
+// This comprises two records of type shm_structure_set. 
+// The secondary record is written strictly after all writes to the main 
record are
+// complete. This is ensured using the __sync_synchronize() construct.
+// The reader should ensure that both copies match for a read to be valid.
+// For safety, the secondary record should be read strictly after the first.
+
+struct shm_structure {
+  uint16_t version; // check this is equal to NQPTP_SHM_STRUCTURES_VERSION
+  shm_structure_set main;
+  shm_structure_set secondary;
 };
 ```
 
-If you wish to use the shared mutex to ensure records are not altered while 
you are accessing them, you should open your side of the shared memory 
interface with read-write permission. Be aware that while your program has the 
mutex lock, it is in a "critical region" where it can halt `nqptp`, so keep any 
activity while you have the lock very short and very simple, e.g. copying the 
contents of shared memory to local memory. 
-
 Clock records that are not updated for a period are deleted.
-
 ## Known Issues
-* `nqptp` has not been checked or audited for security issues. Note that it 
must run in `root` mode.
+* `nqptp` has not been thoroughly checked or audited for security issues. Note 
that it runs in `root` mode on FreeBSD.
 * It's probably buggy!
 * `nqptp` does not take advantage of hardware timestamping.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/RELEASE_NOTES.md 
new/nqptp-1.2.4/RELEASE_NOTES.md
--- old/nqptp-1.2.1/RELEASE_NOTES.md    2023-05-22 11:18:48.000000000 +0200
+++ new/nqptp-1.2.4/RELEASE_NOTES.md    2023-09-16 19:51:55.000000000 +0200
@@ -1,10 +1,20 @@
-## Version: 1.2
-
-***Pesky Changes You Can't Ignore***
+## Version: 1.2.4
+This is an important security update. The Shared Memory Interface of the 
updated NQPTP is now 10, i.e. `smi10`:
+```
+$ nqptp -V
+Version: 1.2.4. Shared Memory Interface Version: smi10.
+```
+1. When updating NQPTP on Linux, be sure to remove the old service file as 
directed in the 
[README](https://github.com/mikebrady/nqptp/blob/main/README.md#remove-old-service-files).
+2. You must update Shairport Sync to ensure that it's Shared Memory Interface 
version is also 10 in order to be compatible with this NQPTP update.
+3. Having completed both updates and installations, remember to restart NQPTP 
first and then restart Shairport Sync.
 
-* **Important**. The protocol that Shairport Sync and NQPTP use to communicate 
with one another has been updated to reflect changes in NQPTP's operation. 
Please update both NQPTP and Shairport Sync so that they both use the same 
Shared Memory Interface Version. 
+**Security Updates**
+* A crashing bug in NQPTP has been fixed.
+* The communications protocol used between NQPTP and Shairport Sync has been 
revised and made more resilient to attempted misuse.
+* In Linux systems, NQPTP no longer runs as `root` -- instead it is installed 
at the `# make install` stage to run as the restriced user `nqptp`, with access 
to ports 319 and 320 set by the installer via the `setcap` utility.
 
-  This version of NQPTP uses Shared Memory Interface Version `smi9`. (You can 
check `nqptp` using `$ nqptp -V`.)
+## Version: 1.2
+* The protocol that Shairport Sync and NQPTP use to communicate with one 
another has been updated to reflect changes in NQPTP's operation. Please update 
both NQPTP and Shairport Sync so that they both use the same Shared Memory 
Interface Version. 
 
 **Enhancements**
 * Enable NQPTP to respond to information about the state of the player -- 
whether is is playing, stopped or paused. The "B" command is a message that the 
client -- which generates the clock -- is about to start playing. The "E" 
command signifies that the client has stopped playing and that the clock may 
shortly sleep. The "P" command signifies that play has paused (buffered audio 
only). The clock seems to stay running in this state.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/configure.ac new/nqptp-1.2.4/configure.ac
--- old/nqptp-1.2.1/configure.ac        2023-05-22 11:18:48.000000000 +0200
+++ new/nqptp-1.2.4/configure.ac        2023-09-16 19:51:55.000000000 +0200
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.68])
-AC_INIT([nqptp], [1.2.1], [4265913+mikebr...@users.noreply.github.com])
+AC_INIT([nqptp], [1.2.4], [4265913+mikebr...@users.noreply.github.com])
 AM_INIT_AUTOMAKE
 AC_CANONICAL_HOST
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/nqptp-clock-sources.c 
new/nqptp-1.2.4/nqptp-clock-sources.c
--- old/nqptp-1.2.1/nqptp-clock-sources.c       2023-05-22 11:18:48.000000000 
+0200
+++ new/nqptp-1.2.4/nqptp-clock-sources.c       2023-09-16 19:51:55.000000000 
+0200
@@ -80,8 +80,6 @@
           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));
         // create the named smi interface
@@ -125,23 +123,6 @@
         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
@@ -248,26 +229,21 @@
 
 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 clock: % " PRIx64 ", offset: %" PRIx64 
".",
-  // master_clock_id, local_to_master_offset);
-  int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
-  if (rc != 0)
-    warn("Can't acquire mutex to update master clock!");
-  shared_memory->master_clock_id = master_clock_id;
+  // to ensure that a full update has taken place, the
+  // reader must ensure that the main and secondary
+  // structures are identical
+
+  shared_memory->main.master_clock_id = master_clock_id;
   if (ip != NULL) {
-    strncpy((char *)&shared_memory->master_clock_ip, ip,
-            FIELD_SIZEOF(struct shm_structure, master_clock_ip) - 1);
-    shared_memory->master_clock_start_time = mastership_start_time;
-    shared_memory->local_time = local_time;
-    shared_memory->local_to_master_time_offset = local_to_master_offset;
+    shared_memory->main.master_clock_start_time = mastership_start_time;
+    shared_memory->main.local_time = local_time;
+    shared_memory->main.local_to_master_time_offset = local_to_master_offset;
   } else {
-    shared_memory->master_clock_ip[0] = '\0';
-    shared_memory->master_clock_start_time = 0;
-    shared_memory->local_time = 0;
-    shared_memory->local_to_master_time_offset = 0;
-  }
-  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");
+    shared_memory->main.master_clock_start_time = 0;
+    shared_memory->main.local_time = 0;
+    shared_memory->main.local_to_master_time_offset = 0;
+  }
+  __sync_synchronize();
+  shared_memory->secondary = shared_memory->main;
+  __sync_synchronize();
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/nqptp-message-handlers.c 
new/nqptp-1.2.4/nqptp-message-handlers.c
--- old/nqptp-1.2.1/nqptp-message-handlers.c    2023-05-22 11:18:48.000000000 
+0200
+++ new/nqptp-1.2.4/nqptp-message-handlers.c    2023-09-16 19:51:55.000000000 
+0200
@@ -51,133 +51,139 @@
                                   clock_source_private_data 
*clock_private_info,
                                   uint64_t reception_time) {
   if (recv_len != -1) {
-    buf[recv_len - 1] = 0; // make sure there's a null in it!
-    debug(2, "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) {
-      if (ip_list != NULL)
-        command = strsep(&ip_list, " ");
-
-      // "B" is for play begin/resume. Assumes a "T <ip>" already
-      // "E" is for play end/stop.
-      // "P" is for pause (currently Buffered Audio only).
-      //
-      // "T <ip>" is for the IP address of a timer.
-      // "T" means no active timer.
-      // clock_is_active is made true by Play and false by Pause or End.
-
-      if ((strcmp(command, "B") == 0) && (ip_list == NULL)) {
-        debug(2, "Play.");
-        // We want to avoid, as much as possible, resetting the clock 
smoothing.
-        // If we know the clock is already active or
-        // if it's only been a short time since we know it was last active
-        // then we will not reset the clock.
-        if (clock_is_active) {
-          debug(2, "clock is already active");
-        } else {
-          // Find out if the clock is active i.e. not sleeping.
-          // We know it is active between "B" and "E" commands.
-          // We also know it is active for brief periods after the "T" and "E" 
commands are
-          // received. If it is not definitely active, we will reset smoothing.
-          int will_ask_for_a_reset = 0;
-          if (clock_validity_expiration_time == 0) {
-            debug(1, "no clock_validity_expiration_time.");
-            will_ask_for_a_reset = 1;
+    if ((buf != NULL) && (recv_len > 0)) {
+      buf[recv_len - 1] = 0; // we know it's not empty, so make sure there's a 
null in it.
+      debug(2, "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) {
+        if (ip_list != NULL)
+          command = strsep(&ip_list, " ");
+
+        // "B" is for play begin/resume. Assumes a "T <ip>" already
+        // "E" is for play end/stop.
+        // "P" is for pause (currently Buffered Audio only).
+        //
+        // "T <ip>" is for the IP address of a timer.
+        // "T" means no active timer.
+        // clock_is_active is made true by Play and false by Pause or End.
+        if (command != NULL) {
+          if ((strcmp(command, "B") == 0) && (ip_list == NULL)) {
+            debug(2, "Play.");
+            // We want to avoid, as much as possible, resetting the clock 
smoothing.
+            // If we know the clock is already active or
+            // if it's only been a short time since we know it was last active
+            // then we will not reset the clock.
+            if (clock_is_active) {
+              debug(2, "clock is already active");
+            } else {
+              // Find out if the clock is active i.e. not sleeping.
+              // We know it is active between "B" and "E" commands.
+              // We also know it is active for brief periods after the "T" and 
"E" commands are
+              // received. If it is not definitely active, we will reset 
smoothing.
+              int will_ask_for_a_reset = 0;
+              if (clock_validity_expiration_time == 0) {
+                debug(1, "no clock_validity_expiration_time.");
+                will_ask_for_a_reset = 1;
+              } else {
+                int64_t time_to_clock_expiration = 
clock_validity_expiration_time - reception_time;
+                // timings obtained with an iPhone Xs Max on battery save
+
+                // around 30 seconds at a buffered audio pause on an iphone.
+                // around 1 second after a buffered audio stop on an iphone
+                // 10 seconds after a "T" from an iPhone that immediately 
sleeps
+                // more than a minute from "T" from a HomePod mini.
+
+                if (time_to_clock_expiration < 0) {
+                  debug(2, "Clock validity may have expired, so ask for a 
reset.");
+                  will_ask_for_a_reset = 1;
+                }
+              }
+              if (will_ask_for_a_reset != 0) {
+                debug(2, "Reset clock smoothing");
+                reset_clock_smoothing = 1;
+              }
+            }
+            clock_is_active = 1;
+            clock_validity_expiration_time = 0;
+          } else if ((strcmp(command, "E") == 0) && (ip_list == NULL)) {
+            debug(2, "Stop");
+            if (clock_is_active) {
+              debug(2, "reset clock_validity_expiration_time to 2.25 seconds 
in the future.");
+              clock_validity_expiration_time =
+                  reception_time + 2250000000; // expiration time can be very 
soon after an "E"
+              clock_is_active = 0;
+            } else {
+              debug(2, "clock is already inactive.");
+            }
+          } else if ((strcmp(command, "P") == 0) && (ip_list == NULL)) {
+            debug(2, "Pause");
+            // A pause always seems to turn into a Stop in now more than a few 
seconds, and the
+            // clock keeps going, it seems so there is nothing to do here.
+          } else if ((command == NULL) || ((strcmp(command, "T") == 0) && 
(ip_list == NULL))) {
+            debug(2, "Stop Timing");
+            clock_is_active = 0;
+            debug(2, "Clear timing peer group.");
+            // dirty experimental hack -- delete all the clocks
+            int gc;
+            for (gc = 0; gc < MAX_CLOCKS; gc++) {
+              memset(&clock_private_info[gc], 0, 
sizeof(clock_source_private_data));
+            }
+            update_master_clock_info(0, NULL, 0, 0, 0); // the SMI may have 
obsolete stuff in it
           } else {
-            int64_t time_to_clock_expiration = clock_validity_expiration_time 
- reception_time;
-            // timings obtained with an iPhone Xs Max on battery save
-
-            // around 30 seconds at a buffered audio pause on an iphone.
-            // around 1 second after a buffered audio stop on an iphone
-            // 10 seconds after a "T" from an iPhone that immediately sleeps
-            // more than a minute from "T" from a HomePod mini.
-
-            if (time_to_clock_expiration < 0) {
-              debug(2, "Clock validity may have expired, so ask for a reset.");
-              will_ask_for_a_reset = 1;
+            debug(2, "Start Timing");
+            // dirty experimental hack -- delete all the clocks
+            int gc;
+            for (gc = 0; gc < MAX_CLOCKS; gc++) {
+              memset(&clock_private_info[gc], 0, 
sizeof(clock_source_private_data));
             }
-          }
-          if (will_ask_for_a_reset != 0) {
-            debug(2, "Reset clock smoothing");
-            reset_clock_smoothing = 1;
-          }
-        }
-        clock_is_active = 1;
-        clock_validity_expiration_time = 0;
-      } else if ((strcmp(command, "E") == 0) && (ip_list == NULL)) {
-        debug(2, "Stop");
-        if (clock_is_active) {
-          debug(2, "reset clock_validity_expiration_time to 2.25 seconds in 
the future.");
-          clock_validity_expiration_time =
-              reception_time + 2250000000; // expiration time can be very soon 
after an "E"
-          clock_is_active = 0;
-        } else {
-          debug(2, "clock is already inactive.");
-        }
-      } else if ((strcmp(command, "P") == 0) && (ip_list == NULL)) {
-        debug(2, "Pause");
-        // A pause always seems to turn into a Stop in now more than a few 
seconds, and the clock
-        // keeps going, it seems so there is nothing to do here.
-      } else if ((command == NULL) || ((strcmp(command, "T") == 0) && (ip_list 
== NULL))) {
-        debug(2, "Stop Timing");
-        clock_is_active = 0;
-        debug(2, "Clear timing peer group.");
-        // dirty experimental hack -- delete all the clocks
-        int gc;
-        for (gc = 0; gc < MAX_CLOCKS; gc++) {
-          memset(&clock_private_info[gc], 0, 
sizeof(clock_source_private_data));
-        }
-        update_master_clock_info(0, NULL, 0, 0, 0); // the SMI may have 
obsolete stuff in it
-      } else {
-        debug(2, "Start Timing");
-        // dirty experimental hack -- delete all the clocks
-        int gc;
-        for (gc = 0; gc < MAX_CLOCKS; gc++) {
-          memset(&clock_private_info[gc], 0, 
sizeof(clock_source_private_data));
-        }
-        debug(2, "get or create new record for \"%s\".", smi_name);
-        //        client_id = get_client_id(smi_name); // create the record if 
it doesn't exist
-        //        if (client_id != -1) {
-        if (strcmp(command, "T") == 0) {
-          int i;
-          for (i = 0; i < MAX_CLOCKS; i++) {
-            clock_private_info[i].announcements_without_followups =
-                0; // to allow a possibly silent clock to be revisited when 
added to a timing
-                   // peer list
-            clock_private_info[i].follow_up_number = 0;
-          }
+            debug(2, "get or create new record for \"%s\".", smi_name);
+            //        client_id = get_client_id(smi_name); // create the 
record if it doesn't exist
+            //        if (client_id != -1) {
+            if (strcmp(command, "T") == 0) {
+              int i;
+              for (i = 0; i < MAX_CLOCKS; i++) {
+                clock_private_info[i].announcements_without_followups =
+                    0; // to allow a possibly silent clock to be revisited 
when added to a timing
+                       // peer list
+                clock_private_info[i].follow_up_number = 0;
+              }
 
-          // take the first ip and make it the master, permanently
+              // take the first ip and make it the master, permanently
 
-          if (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, okay
-                debug(2, "Monitor clock at %s.", new_ip);
+              if (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, okay
+                    debug(2, "Monitor clock at %s.", new_ip);
+                  }
+                  // otherwise, drop it
+                }
               }
-              // otherwise, drop it
+              // a new clock timing record will be started now
+              debug(2, "reset clock_validity_expiration_time to 5.0 seconds in 
the future.");
+              clock_validity_expiration_time =
+                  reception_time + 5000000000L; // clock can stop as soon as 6 
seconds after a "T"
+            } else {
+              warn("Unrecognised string on the control port.");
             }
+            //        } else {
+            //          warn("Could not find or create a record for SMI 
Interface \"%s\".",
+            //          smi_name);
+            //        }
           }
-          // a new clock timing record will be started now
-          debug(2, "reset clock_validity_expiration_time to 5.0 seconds in the 
future.");
-          clock_validity_expiration_time =
-              reception_time + 5000000000L; // clock can stop as soon as 6 
seconds after a "T"
-        } else {
-          warn("Unrecognised string on the control port.");
         }
-        //        } else {
-        //          warn("Could not find or create a record for SMI Interface 
\"%s\".", smi_name);
-        //        }
+      } else {
+        warn("SMI Interface Name not found on the control port.");
       }
     } else {
-      warn("SMI Interface Name not found on the control port.");
+      warn("Missing or empty packet on the control port.");
     }
   } else {
     warn("Bad packet on the control port.");
@@ -445,7 +451,7 @@
             smoothed_offset = clock_private_info->previous_offset;
             if (mastership_time > 1000000000)
               smoothed_offset += clamped_jitter / 256; // later, if jitter is 
negative
-          } else if (mastership_time < 1000000000) { // at the beginning
+          } else if (mastership_time < 1000000000) {   // at the beginning
             smoothed_offset =
                 clock_private_info->previous_offset +
                 jitter /
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/nqptp-shm-structures.h 
new/nqptp-1.2.4/nqptp-shm-structures.h
--- old/nqptp-1.2.1/nqptp-shm-structures.h      2023-05-22 11:18:48.000000000 
+0200
+++ new/nqptp-1.2.4/nqptp-shm-structures.h      2023-09-16 19:51:55.000000000 
+0200
@@ -1,6 +1,6 @@
 /*
  * This file is part of the nqptp distribution 
(https://github.com/mikebrady/nqptp).
- * Copyright (c) 2021--2022 Mike Brady.
+ * Copyright (c) 2021--2023 Mike Brady.
  *
  * 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
@@ -22,7 +22,7 @@
 
 #define NQPTP_INTERFACE_NAME "/nqptp"
 
-#define NQPTP_SHM_STRUCTURES_VERSION 9
+#define NQPTP_SHM_STRUCTURES_VERSION 10
 #define NQPTP_CONTROL_PORT 9000
 
 // The control port expects a UDP packet with the first character being a 
command letter
@@ -50,20 +50,29 @@
 // When the clock is inactive, it can stop running. This causes the offset to 
decrease.
 // NQPTP clock smoothing would treat this as a network delay, causing true 
sync to be lost.
 // To avoid this, when the clock goes from inactive to active,
-// NQPTP resets clock smoothing to the new offset. 
-
+// NQPTP resets clock smoothing to the new offset.
 
 #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
+typedef struct {
   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
   uint64_t local_to_master_time_offset; // add this to the local time to get 
master clock time
   uint64_t master_clock_start_time;     // this is when the master clock 
became master
+} shm_structure_set;
+
+// The actual interface comprises a shared memory region of type struct 
shm_structure.
+// This comprises two records of type shm_structure_set. 
+// The secondary record is written strictly after all writes to the main 
record are
+// complete. This is ensured using the __sync_synchronize() construct.
+// The reader should ensure that both copies match for a read to be valid.
+// For safety, the secondary record should be read strictly after the first.
+
+struct shm_structure {
+  uint16_t version; // check this is equal to NQPTP_SHM_STRUCTURES_VERSION
+  shm_structure_set main;
+  shm_structure_set secondary;
 };
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/nqptp-utilities.c 
new/nqptp-1.2.4/nqptp-utilities.c
--- old/nqptp-1.2.1/nqptp-utilities.c   2023-05-22 11:18:48.000000000 +0200
+++ new/nqptp-1.2.4/nqptp-utilities.c   2023-09-16 19:51:55.000000000 +0200
@@ -29,11 +29,11 @@
 #endif
 
 #ifdef CONFIG_FOR_FREEBSD
-#include <sys/types.h>
-#include <unistd.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
 #endif
 
 #include <netdb.h>  // getaddrinfo etc.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/nqptp.c new/nqptp-1.2.4/nqptp.c
--- old/nqptp-1.2.1/nqptp.c     2023-05-22 11:18:48.000000000 +0200
+++ new/nqptp-1.2.4/nqptp.c     2023-09-16 19:51:55.000000000 +0200
@@ -96,11 +96,13 @@
   // close off new smi
   // mmap cleanup
   if (munmap(shared_memory, sizeof(struct shm_structure)) != 0) {
-    debug(1, "error unmapping shared memory \"%s\": \"%s\".", 
NQPTP_INTERFACE_NAME, strerror(errno));
+    debug(1, "error unmapping shared memory \"%s\": \"%s\".", 
NQPTP_INTERFACE_NAME,
+          strerror(errno));
   }
   // shm_open cleanup
   if (shm_unlink(NQPTP_INTERFACE_NAME) == -1) {
-    debug(1, "error unlinking shared memory \"%s\": \"%s\".", 
NQPTP_INTERFACE_NAME, strerror(errno));
+    debug(1, "error unlinking shared memory \"%s\": \"%s\".", 
NQPTP_INTERFACE_NAME,
+          strerror(errno));
   }
 
   if (shm_fd != -1)
@@ -131,8 +133,8 @@
       if (strcmp(argv[i] + 1, "V") == 0) {
 #ifdef CONFIG_USE_GIT_VERSION_STRING
         if (git_version_string[0] != '\0')
-          fprintf(stdout, "Version: %s. Shared Memory Interface Version: 
smi%u.\n", git_version_string,
-                  NQPTP_SHM_STRUCTURES_VERSION);
+          fprintf(stdout, "Version: %s. Shared Memory Interface Version: 
smi%u.\n",
+                  git_version_string, NQPTP_SHM_STRUCTURES_VERSION);
         else
 #endif
 
@@ -191,13 +193,10 @@
 
   // open the SMI
 
-  pthread_mutexattr_t shared;
-  int err;
-
   shm_fd = -1;
 
   mode_t oldumask = umask(0);
-  shm_fd = shm_open(NQPTP_INTERFACE_NAME, O_RDWR | O_CREAT, 0666);
+  shm_fd = shm_open(NQPTP_INTERFACE_NAME, O_RDWR | O_CREAT, 0644);
   if (shm_fd == -1) {
     die("cannot open shared memory \"%s\".", NQPTP_INTERFACE_NAME);
   }
@@ -230,23 +229,6 @@
   memset(shared_memory, 0, sizeof(struct shm_structure));
   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 *)&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));
-  }
-
   ssize_t recv_len;
 
   char buf[BUFLEN];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nqptp-1.2.1/nqptp.service.in 
new/nqptp-1.2.4/nqptp.service.in
--- old/nqptp-1.2.1/nqptp.service.in    2023-05-22 11:18:48.000000000 +0200
+++ new/nqptp-1.2.4/nqptp.service.in    2023-09-16 19:51:55.000000000 +0200
@@ -6,8 +6,8 @@
 
 [Service]
 ExecStart=@prefix@/bin/nqptp
-User=root
-Group=root
+User=nqptp
+Group=nqptp
 
 [Install]
 WantedBy=multi-user.target

++++++ nqptp-user.conf ++++++
# Type Name ID GECOS [HOME]
g nqptp - -
u nqptp - "nqptp daemon" /  /sbin/nologin

Reply via email to