mirror of https://github.com/joan2937/pigpio
Add a Unix socket connection
Unix-domain sockets have less overhead than TCP.
This commit is contained in:
parent
c33738a320
commit
2bf2115ab5
|
@ -25,6 +25,12 @@ default may be overridden when pigpio starts by the <a href=
|
|||
call. The pigpio daemon uses this function to provide an
|
||||
option to change the port number.<br>
|
||||
<br>
|
||||
pigpio also listens for connections on "/var/run/pigpio.sock" by
|
||||
default. This default may be overridden when pigpio starts
|
||||
by the <a href= "cif.html#gpioCfgSocketPath">gpioCfgSocketPath</a>
|
||||
function call. The pigpio daemon uses this function to provide an
|
||||
option to change the socket file name.<br>
|
||||
<br>
|
||||
The pigs utility is an example of using the socket interface from
|
||||
C.<span style="font-weight: bold;"><br></span>
|
||||
<h3><a name="Request" id="Request"></a>Request</h3>
|
||||
|
|
|
@ -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"},
|
||||
|
||||
};
|
||||
|
||||
|
|
30
pigpio.3
30
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
|
||||
|
|
116
pigpio.c
116
pigpio.c
|
@ -58,6 +58,7 @@ For more information, please refer to <http://unlicense.org/>
|
|||
#include <sys/socket.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/un.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/select.h>
|
||||
#include <fnmatch.h>
|
||||
|
@ -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)
|
||||
|
|
21
pigpio.h
21
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"
|
||||
|
|
13
pigpio.py
13
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,6 +5216,12 @@ class pi():
|
|||
self.sl = _socklock()
|
||||
self._notify = None
|
||||
|
||||
self._sock = sock
|
||||
try:
|
||||
if sock:
|
||||
self.sl.s = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM)
|
||||
self.sl.s.connect(sock)
|
||||
else:
|
||||
port = int(port)
|
||||
|
||||
if host == '':
|
||||
|
@ -5220,7 +5230,6 @@ class pi():
|
|||
self._host = host
|
||||
self._port = port
|
||||
|
||||
try:
|
||||
self.sl.s = socket.create_connection((host, port), None)
|
||||
|
||||
# Disable the Nagle algorithm.
|
||||
|
@ -5264,7 +5273,9 @@ class pi():
|
|||
print(_except_z)
|
||||
|
||||
def __repr__(self):
|
||||
if self._sock is None:
|
||||
return "<pipio.pi host={} port={}>".format(self._host, self._port)
|
||||
return "<pipio.pi sock={}>".format(self._sock)
|
||||
|
||||
def stop(self):
|
||||
"""Release pigpio resources.
|
||||
|
|
12
pigpiod.c
12
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);
|
||||
|
|
Loading…
Reference in New Issue