diff --git a/DOC/src/html/sif.html b/DOC/src/html/sif.html
index 67b880b..b12eb97 100644
--- a/DOC/src/html/sif.html
+++ b/DOC/src/html/sif.html
@@ -25,6 +25,12 @@ default may be overridden when pigpio starts by the
+pigpio also listens for connections on "/var/run/pigpio.sock" by
+default. This default may be overridden when pigpio starts
+by the gpioCfgSocketPath
+function call. The pigpio daemon uses this function to provide an
+option to change the socket file name.
+
The pigs utility is an example of using the socket interface from
C.
Request
diff --git a/command.c b/command.c
index ffc3463..d17b522 100644
--- a/command.c
+++ b/command.c
@@ -567,6 +567,7 @@ static errInfo_t errInfo[]=
{PI_CMD_INTERRUPTED , "command interrupted, Python"},
{PI_NOT_ON_BCM2711 , "not available on BCM2711"},
{PI_ONLY_ON_BCM2711 , "only available on BCM2711"},
+ {PI_BAD_SOCKET_PATH , "socket path empty"},
};
diff --git a/pigpio.3 b/pigpio.3
index 783bc92..a5b7075 100644
--- a/pigpio.3
+++ b/pigpio.3
@@ -706,6 +706,8 @@ gpioCfgInterfaces Configure user interfaces
.br
gpioCfgSocketPort Configure socket port
.br
+gpioCfgSocketPath Configure socket path
+.br
gpioCfgMemAlloc Configure DMA memory allocation mode
.br
gpioCfgNetAddr Configure allowed network addresses
@@ -7802,6 +7804,30 @@ port: 1024-32000
.br
The default setting is to use port 8888.
+.IP "\fBint gpioCfgSocketPath(const char*)\fP"
+.IP "" 4
+Configures pigpio to use the specified Unix socket.
+
+.br
+
+.br
+This function is only effective if called before \fBgpioInitialise\fP.
+
+.br
+
+.br
+
+.EX
+path: path to the socket.
+.br
+
+.EE
+
+.br
+
+.br
+The default is "/var/run/pigpio.sock".
+
.IP "\fBint gpioCfgInterfaces(unsigned ifFlags)\fP"
.IP "" 4
Configures pigpio support of the fifo and socket interfaces.
@@ -8945,6 +8971,8 @@ These functions are only effective if called before \fBgpioInitialise\fP.
.br
\fBgpioCfgSocketPort\fP
.br
+\fBgpioCfgSocketPath\fP
+.br
\fBgpioCfgMemAlloc\fP
.br
@@ -11040,6 +11068,8 @@ A 16-bit word value.
.br
#define PI_ONLY_ON_BCM2711 -146 // only available on BCM2711
.br
+#define PI_BAD_SOCKET_PORT -147 // socket path empty
+.br
.br
#define PI_PIGIF_ERR_0 -2000
diff --git a/pigpio.c b/pigpio.c
index 97bfc54..5b83292 100644
--- a/pigpio.c
+++ b/pigpio.c
@@ -58,6 +58,7 @@ For more information, please refer to
#include
#include
#include
+#include
#include
#include
#include
@@ -1096,6 +1097,7 @@ typedef struct
unsigned DMAprimaryChannel;
unsigned DMAsecondaryChannel;
unsigned socketPort;
+ const char * socketPath;
unsigned ifFlags;
unsigned memAllocMode;
unsigned dbgLevel;
@@ -1292,6 +1294,7 @@ static volatile int runState = PI_STARTING;
static int pthAlertRunning = PI_THREAD_NONE;
static int pthFifoRunning = PI_THREAD_NONE;
static int pthSocketRunning = PI_THREAD_NONE;
+static int pthUnixRunning = PI_THREAD_NONE;
static gpioAlert_t gpioAlert [PI_MAX_USER_GPIO+1];
@@ -1328,6 +1331,7 @@ static FILE * outFifo = NULL;
static int fdLock = -1;
static int fdMem = -1;
static int fdSock = -1;
+static int fdUnix = -1;
static int fdPmap = -1;
static int fdMbox = -1;
@@ -1369,6 +1373,7 @@ static volatile gpioCfg_t gpioCfg =
PI_DEFAULT_DMA_NOT_SET, /* primary DMA */
PI_DEFAULT_DMA_NOT_SET, /* secondary DMA */
PI_DEFAULT_SOCKET_PORT,
+ PI_DEFAULT_SOCKET_PATH,
PI_DEFAULT_IF_FLAGS,
PI_DEFAULT_MEM_ALLOC_MODE,
0, /* dbgLevel */
@@ -1384,6 +1389,7 @@ static unsigned bufferCycles; /* number of cycles */
static pthread_t pthAlert;
static pthread_t pthFifo;
static pthread_t pthSocket;
+static pthread_t pthUnix;
static uint32_t spi_dummy;
@@ -7260,6 +7266,61 @@ static void * pthSocketThread(void *x)
return 0;
}
+static void * pthUnixThread(void *x)
+{
+ int fdC=0, c, *sock;
+ struct sockaddr_storage client;
+ pthread_attr_t attr;
+
+ if (pthread_attr_init(&attr))
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "pthread_attr_init failed (%m)");
+
+ if (pthread_attr_setstacksize(&attr, STACK_SIZE))
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "pthread_attr_setstacksize failed (%m)");
+
+ if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "pthread_attr_setdetachstate failed (%m)");
+
+ /* fdUnix opened in gpioInitialise so that we can treat
+ failure to bind as fatal. */
+
+ listen(fdUnix, 100);
+
+ c = sizeof(client);
+
+ /* don't start until DMA started */
+
+ spinWhileStarting();
+
+ while (fdC >= 0)
+ {
+ pthread_t thr;
+
+ fdC = accept(fdUnix, (struct sockaddr *)&client, (socklen_t*)&c);
+
+ closeOrphanedNotifications(-1, fdC);
+
+ DBG(DBG_USER, "Connection accepted on socket %d", fdC);
+
+ sock = malloc(sizeof(int));
+
+ *sock = fdC;
+
+ if (pthread_create
+ (&thr, &attr, pthSocketThreadHandler, (void*) sock) < 0)
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "socket pthread_create failed (%m)");
+ }
+
+ if (fdC < 0)
+ SOFT_ERROR((void*)PI_INIT_FAILED, "accept failed (%m)");
+
+ return 0;
+}
+
/* ======================================================================= */
static void initCheckLockFile(void)
@@ -7969,6 +8030,7 @@ static void initClearGlobals(void)
pthAlertRunning = PI_THREAD_NONE;
pthFifoRunning = PI_THREAD_NONE;
pthSocketRunning = PI_THREAD_NONE;
+ pthUnixRunning = PI_THREAD_NONE;
wfc[0] = 0;
wfc[1] = 0;
@@ -8051,6 +8113,7 @@ static void initClearGlobals(void)
fdLock = -1;
fdMem = -1;
fdSock = -1;
+ fdUnix = -1;
dmaMboxBlk = MAP_FAILED;
dmaPMapBlk = MAP_FAILED;
@@ -8120,6 +8183,13 @@ static void initReleaseResources(void)
pthSocketRunning = PI_THREAD_NONE;
}
+ if (pthUnixRunning != PI_THREAD_NONE)
+ {
+ pthread_cancel(pthUnix);
+ pthread_join(pthUnix, NULL);
+ pthUnixRunning = PI_THREAD_NONE;
+ }
+
/* release mmap'd memory */
if (auxReg != MAP_FAILED) munmap((void *)auxReg, AUX_LEN);
@@ -8224,6 +8294,12 @@ static void initReleaseResources(void)
fdSock = -1;
}
+ if (fdUnix != -1)
+ {
+ close(fdUnix);
+ fdUnix = -1;
+ }
+
if (fdPmap != -1)
{
close(fdPmap);
@@ -8248,7 +8324,9 @@ int initInitialise(void)
unsigned rev, model;
struct sockaddr_in server;
struct sockaddr_in6 server6;
+ struct sockaddr_un serverU;
char * portStr;
+ const char * sockStr;
unsigned port;
struct sched_param param;
pthread_attr_t pthAttr;
@@ -8368,6 +8446,29 @@ int initInitialise(void)
pthFifoRunning = PI_THREAD_STARTED;
}
+ if (!(gpioCfg.ifFlags & PI_DISABLE_UNIX_IF))
+ {
+ sockStr = getenv(PI_ENVSOCK);
+ if (! sockStr) sockStr = gpioCfg.socketPath;
+
+ fdUnix = socket(AF_UNIX, SOCK_STREAM , 0);
+
+ if (fdUnix != -1)
+ {
+ bzero((char *)&serverU, sizeof(serverU));
+ serverU.sun_family = AF_UNIX;
+ strncpy (serverU.sun_path, sockStr, sizeof (serverU.sun_path) - 1);
+
+ if (bind(fdUnix,(struct sockaddr *)&serverU, sizeof(serverU)) < 0)
+ SOFT_ERROR(PI_INIT_FAILED, "bind to socket '%s' failed (%m)", sockStr);
+ }
+
+ if (pthread_create(&pthUnix, &pthAttr, pthUnixThread, &i))
+ SOFT_ERROR(PI_INIT_FAILED, "pthread_create unix failed (%m)");
+
+ pthUnixRunning = PI_THREAD_STARTED;
+ }
+
if (!(gpioCfg.ifFlags & PI_DISABLE_SOCK_IF))
{
portStr = getenv(PI_ENVPORT);
@@ -13972,6 +14073,21 @@ int gpioCfgSocketPort(unsigned port)
}
+int gpioCfgSocketPath(const char *path)
+{
+ DBG(DBG_USER, "path=%s", path);
+
+ CHECK_NOT_INITED;
+
+ if (!path || !*path)
+ SOFT_ERROR(PI_BAD_SOCKET_PATH, "bad path");
+
+ gpioCfg.socketPath = path;
+
+ return 0;
+}
+
+
/* ----------------------------------------------------------------------- */
int gpioCfgMemAlloc(unsigned memAllocMode)
diff --git a/pigpio.h b/pigpio.h
index 1b8e51c..35e98c4 100644
--- a/pigpio.h
+++ b/pigpio.h
@@ -385,6 +385,7 @@ gpioCfgDMAchannels Configure the DMA channels
gpioCfgPermissions Configure the GPIO access permissions
gpioCfgInterfaces Configure user interfaces
gpioCfgSocketPort Configure socket port
+gpioCfgSocketPath Configure Unix socket path
gpioCfgMemAlloc Configure DMA memory allocation mode
gpioCfgNetAddr Configure allowed network addresses
@@ -415,6 +416,7 @@ OVERVIEW*/
#define PI_ENVPORT "PIGPIO_PORT"
#define PI_ENVADDR "PIGPIO_ADDR"
+#define PI_ENVSOCK "PIGPIO_SOCKET"
#define PI_LOCKFILE "/var/run/pigpio.pid"
@@ -890,6 +892,7 @@ typedef void *(gpioThreadFunc_t) (void *);
#define PI_DISABLE_SOCK_IF 2
#define PI_LOCALHOST_SOCK_IF 4
#define PI_DISABLE_ALERT 8
+#define PI_DISABLE_UNIX_IF 16
/* memAllocMode */
@@ -4919,6 +4922,21 @@ The default setting is to use port 8888.
D*/
+/*F*/
+int gpioCfgSocketPath(const char * path);
+/*D
+Configures pigpio to use the specified Unix socket.
+
+This function is only effective if called before [*gpioInitialise*].
+
+. .
+port: path to the socket file.
+. .
+
+The default is "/var/run/pigpio.sock".
+D*/
+
+
/*F*/
int gpioCfgInterfaces(unsigned ifFlags);
/*D
@@ -5538,6 +5556,7 @@ These functions are only effective if called before [*gpioInitialise*].
[*gpioCfgPermissions*]
[*gpioCfgInterfaces*]
[*gpioCfgSocketPort*]
+[*gpioCfgSocketPath*]
[*gpioCfgMemAlloc*]
gpioGetSamplesFunc_t::
@@ -6528,6 +6547,7 @@ after this command is issued.
#define PI_CMD_INTERRUPTED -144 // Used by Python
#define PI_NOT_ON_BCM2711 -145 // not available on BCM2711
#define PI_ONLY_ON_BCM2711 -146 // only available on BCM2711
+#define PI_BAD_SOCKET_PATH -147 // socket path empty
#define PI_PIGIF_ERR_0 -2000
#define PI_PIGIF_ERR_99 -2099
@@ -6550,6 +6570,7 @@ after this command is issued.
#define PI_DEFAULT_DMA_PRIMARY_CH_2711 7
#define PI_DEFAULT_DMA_SECONDARY_CH_2711 6
#define PI_DEFAULT_DMA_NOT_SET 15
+#define PI_DEFAULT_SOCKET_PATH "/var/run/pigpio.sock"
#define PI_DEFAULT_SOCKET_PORT 8888
#define PI_DEFAULT_SOCKET_PORT_STR "8888"
#define PI_DEFAULT_SOCKET_ADDR_STR "localhost"
diff --git a/pigpio.py b/pigpio.py
index 20d48e6..8d6e027 100644
--- a/pigpio.py
+++ b/pigpio.py
@@ -723,6 +723,7 @@ PI_BAD_EVENT_ID =-143
PI_CMD_INTERRUPTED =-144
PI_NOT_ON_BCM2711 =-145
PI_ONLY_ON_BCM2711 =-146
+_PI_BAD_SOCKET_PATH =-147
# pigpio error text
@@ -871,6 +872,7 @@ _errors=[
[PI_CMD_INTERRUPTED , "pigpio command interrupted"],
[PI_NOT_ON_BCM2711 , "not available on BCM2711"],
[PI_ONLY_ON_BCM2711 , "only available on BCM2711"],
+ [_PI_BAD_SOCKET_PATH , "socket path empty"],
]
_except_a = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n{}"
@@ -5177,6 +5179,7 @@ class pi():
def __init__(self,
host = os.getenv("PIGPIO_ADDR", 'localhost'),
port = os.getenv("PIGPIO_PORT", 8888),
+ sock = os.getenv("PIGPIO_SOCKET", None),
show_errors = True):
"""
Grants access to a Pi's GPIO.
@@ -5201,6 +5204,7 @@ class pi():
pi = pigio.pi() # use defaults
pi = pigpio.pi('mypi') # specify host, default port
pi = pigpio.pi('mypi', 7777) # specify host and port
+ pi = pigpio.pi(sock='/run/pigpio.sock') # specify a Unix socket
pi = pigpio.pi() # exit script if no connection
if not pi.connected:
@@ -5212,19 +5216,24 @@ class pi():
self.sl = _socklock()
self._notify = None
- port = int(port)
-
- if host == '':
- host = "localhost"
-
- self._host = host
- self._port = port
-
+ self._sock = sock
try:
- self.sl.s = socket.create_connection((host, port), None)
+ if sock:
+ self.sl.s = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM)
+ self.sl.s.connect(sock)
+ else:
+ port = int(port)
- # Disable the Nagle algorithm.
- self.sl.s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ if host == '':
+ host = "localhost"
+
+ self._host = host
+ self._port = port
+
+ self.sl.s = socket.create_connection((host, port), None)
+
+ # Disable the Nagle algorithm.
+ self.sl.s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self._notify = _callback_thread(self.sl, host, port)
@@ -5264,7 +5273,9 @@ class pi():
print(_except_z)
def __repr__(self):
- return "".format(self._host, self._port)
+ if self._sock is None:
+ return "".format(self._host, self._port)
+ return "".format(self._sock)
def stop(self):
"""Release pigpio resources.
diff --git a/pigpiod.c b/pigpiod.c
index 899ddf8..46d094f 100644
--- a/pigpiod.c
+++ b/pigpiod.c
@@ -59,6 +59,7 @@ static int foreground = PI_DEFAULT_FOREGROUND;
static unsigned DMAprimaryChannel = PI_DEFAULT_DMA_NOT_SET;
static unsigned DMAsecondaryChannel = PI_DEFAULT_DMA_NOT_SET;
static unsigned socketPort = PI_DEFAULT_SOCKET_PORT;
+static char * socketPath = PI_DEFAULT_SOCKET_PATH;
static unsigned memAllocMode = PI_DEFAULT_MEM_ALLOC_MODE;
static uint64_t updateMask = -1;
@@ -106,6 +107,7 @@ void usage()
" -n IP addr, allow address, name or dotted, default allow all\n" \
" -p value, socket port, 1024-32000, default 8888\n" \
" -s value, sample rate, 1, 2, 4, 5, 8, or 10, default 5\n" \
+ " -S path, Unix socket file, default /var/run/pigpio.sock\n" \
" -t value, clock peripheral, 0=PWM 1=PCM, default PCM\n" \
" -v, -V, display pigpio version and exit\n" \
" -x mask, GPIO which may be updated, default board GPIO\n" \
@@ -163,7 +165,7 @@ static void initOpts(int argc, char *argv[])
uint32_t addr;
int64_t mask;
- while ((opt = getopt(argc, argv, "a:b:c:d:e:fgkln:mp:s:t:x:vV")) != -1)
+ while ((opt = getopt(argc, argv, "a:b:c:d:e:fgkln:mp:s:S:t:x:vV")) != -1)
{
switch (opt)
{
@@ -256,6 +258,12 @@ static void initOpts(int argc, char *argv[])
}
break;
+ case 'S':
+ if (!*optarg)
+ fatal("invalid -S option (empty string)");
+ socketPath = optarg;
+ break;
+
case 't':
i = getNum(optarg, &err);
if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM))
@@ -358,6 +366,8 @@ int main(int argc, char **argv)
gpioCfgSocketPort(socketPort);
+ gpioCfgSocketPath(socketPath);
+
gpioCfgMemAlloc(memAllocMode);
if (updateMaskSet) gpioCfgPermissions(updateMask);