Skip to content

Commit

Permalink
Add a Unix socket connection
Browse files Browse the repository at this point in the history
Unix-domain sockets have less overhead than TCP.
  • Loading branch information
smurfix authored and root committed Dec 5, 2023
1 parent c33738a commit 2bf2115
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 11 deletions.
6 changes: 6 additions & 0 deletions DOC/src/html/sif.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
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.&nbsp; This default may be overridden when pigpio starts
by the <a href= "cif.html#gpioCfgSocketPath">gpioCfgSocketPath</a>
function call.&nbsp; 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>
Expand Down
1 change: 1 addition & 0 deletions command.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"},

};

Expand Down
30 changes: 30 additions & 0 deletions pigpio.3
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -8945,6 +8971,8 @@ These functions are only effective if called before \fBgpioInitialise\fP.
.br
\fBgpioCfgSocketPort\fP
.br
\fBgpioCfgSocketPath\fP
.br
\fBgpioCfgMemAlloc\fP

.br
Expand Down Expand Up @@ -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
Expand Down
116 changes: 116 additions & 0 deletions pigpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -1096,6 +1097,7 @@ typedef struct
unsigned DMAprimaryChannel;
unsigned DMAsecondaryChannel;
unsigned socketPort;
const char * socketPath;
unsigned ifFlags;
unsigned memAllocMode;
unsigned dbgLevel;
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 */
Expand All @@ -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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -8051,6 +8113,7 @@ static void initClearGlobals(void)
fdLock = -1;
fdMem = -1;
fdSock = -1;
fdUnix = -1;

dmaMboxBlk = MAP_FAILED;
dmaPMapBlk = MAP_FAILED;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -8224,6 +8294,12 @@ static void initReleaseResources(void)
fdSock = -1;
}

if (fdUnix != -1)
{
close(fdUnix);
fdUnix = -1;
}

if (fdPmap != -1)
{
close(fdPmap);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
21 changes: 21 additions & 0 deletions pigpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -5538,6 +5556,7 @@ These functions are only effective if called before [*gpioInitialise*].
[*gpioCfgPermissions*]
[*gpioCfgInterfaces*]
[*gpioCfgSocketPort*]
[*gpioCfgSocketPath*]
[*gpioCfgMemAlloc*]
gpioGetSamplesFunc_t::
Expand Down Expand Up @@ -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
Expand All @@ -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"
Expand Down
Loading

0 comments on commit 2bf2115

Please sign in to comment.