first commit
This commit is contained in:
100
wiringPiD/Makefile
Normal file
100
wiringPiD/Makefile
Normal file
@@ -0,0 +1,100 @@
|
||||
#
|
||||
# Makefile:
|
||||
# The wiringPiD utility:
|
||||
# https://projects.drogon.net/wiring-pi
|
||||
#
|
||||
# Copyright (c) 2012-2017 Gordon Henderson
|
||||
#################################################################################
|
||||
# This file is part of wiringPi:
|
||||
# A "wiring" library for the Raspberry Pi
|
||||
#
|
||||
# wiringPi is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# wiringPi is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
||||
#################################################################################
|
||||
|
||||
DESTDIR?=/usr
|
||||
PREFIX?=/local
|
||||
|
||||
ifneq ($V,1)
|
||||
Q ?= @
|
||||
endif
|
||||
|
||||
#DEBUG = -g -O0
|
||||
DEBUG = -O2
|
||||
CC = gcc
|
||||
INCLUDE = -I$(DESTDIR)$(PREFIX)/include
|
||||
CFLAGS = $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe
|
||||
|
||||
LDFLAGS = -L$(DESTDIR)$(PREFIX)/lib
|
||||
LIBS = -lwiringPi -lwiringPiDev -lpthread -lrt -lm -lcrypt
|
||||
|
||||
# May not need to alter anything below this line
|
||||
###############################################################################
|
||||
|
||||
SRC = wiringpid.c network.c runRemote.c daemonise.c
|
||||
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
all: wiringpid
|
||||
|
||||
wiringpid: $(OBJ)
|
||||
$Q echo [Link]
|
||||
$Q $(CC) -o $@ $(OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
||||
.c.o:
|
||||
$Q echo [Compile] $<
|
||||
$Q $(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$Q echo "[Clean]"
|
||||
$Q rm -f $(OBJ) wiringpid *~ core tags *.bak
|
||||
|
||||
.PHONY: tags
|
||||
tags: $(SRC)
|
||||
$Q echo [ctags]
|
||||
$Q ctags $(SRC)
|
||||
|
||||
.PHONY: install
|
||||
install: wiringpid
|
||||
$Q echo "[Install]"
|
||||
$Q mkdir -p $(DESTDIR)$(PREFIX)/sbin
|
||||
$Q cp wiringpid $(DESTDIR)$(PREFIX)/sbin/
|
||||
$Q chown root.root $(DESTDIR)$(PREFIX)/sbin/wiringpid
|
||||
|
||||
# $Q mkdir -p $(DESTDIR)$(PREFIX)/man/man8
|
||||
# $Q cp gpio.1 $(DESTDIR)$(PREFIX)/man/man8/
|
||||
|
||||
.PHONY: install-deb
|
||||
install-deb: gpio
|
||||
$Q echo "[Install: deb]"
|
||||
$Q install -m 0755 -d $(CURDIR)/../debian-template/wiringPi/usr/bin
|
||||
$Q install -m 0755 gpio $(CURDIR)/../debian-template/wiringPi/usr/bin
|
||||
$Q install -m 0755 -d $(CURDIR)/../debian-template/wiringPi/man/man1
|
||||
$Q install -m 0644 gpio.1 $(CURDIR)/../debian-template/wiringPi/man/man1
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
$Q echo "[UnInstall]"
|
||||
$Q rm -f $(DESTDIR)$(PREFIX)/sbin/wiringpid
|
||||
$Q rm -f $(DESTDIR)$(PREFIX)/man/man8/wiringpid.8
|
||||
|
||||
.PHONY: depend
|
||||
depend:
|
||||
makedepend -Y $(SRC)
|
||||
# DO NOT DELETE
|
||||
|
||||
wiringpid.o: drcNetCmd.h network.h runRemote.h daemonise.h
|
||||
network.o: network.h
|
||||
runRemote.o: drcNetCmd.h network.h runRemote.h
|
||||
daemonise.o: daemonise.h
|
82
wiringPiD/daemonise.c
Normal file
82
wiringPiD/daemonise.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* daemonise.c:
|
||||
* Fairly generic "Turn the current process into a daemon" code.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Gordon Henderson.
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "daemonise.h"
|
||||
|
||||
void daemonise (const char *pidFile)
|
||||
{
|
||||
pid_t pid ;
|
||||
int i ;
|
||||
FILE *fd ;
|
||||
|
||||
syslog (LOG_DAEMON | LOG_INFO, "Becoming daemon") ;
|
||||
|
||||
// Fork from the parent
|
||||
|
||||
if ((pid = fork ()) < 0)
|
||||
{
|
||||
syslog (LOG_DAEMON | LOG_ALERT, "Fork no. 1 failed: %m") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
if (pid > 0) // Parent - terminate
|
||||
exit (EXIT_SUCCESS) ;
|
||||
|
||||
// Now running on the child - become session leader
|
||||
|
||||
if (setsid() < 0)
|
||||
{
|
||||
syslog (LOG_DAEMON | LOG_ALERT, "setsid failed: %m") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
// Ignore a few signals
|
||||
|
||||
signal (SIGCHLD, SIG_IGN) ;
|
||||
signal (SIGHUP, SIG_IGN) ;
|
||||
|
||||
// Fork again
|
||||
|
||||
if ((pid = fork ()) < 0)
|
||||
{
|
||||
syslog (LOG_DAEMON | LOG_ALERT, "Fork no. 2 failed: %m") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
if (pid > 0) // parent - terminate
|
||||
exit (EXIT_SUCCESS) ;
|
||||
|
||||
// Tidying up - reset umask, change to / and close all files
|
||||
|
||||
umask (0) ;
|
||||
chdir ("/") ;
|
||||
|
||||
for (i = 0 ; i < sysconf (_SC_OPEN_MAX) ; ++i)
|
||||
close (i) ;
|
||||
|
||||
// Write PID into /var/run
|
||||
|
||||
if (pidFile != NULL)
|
||||
{
|
||||
if ((fd = fopen (pidFile, "w")) == NULL)
|
||||
{
|
||||
syslog (LOG_DAEMON | LOG_ALERT, "Unable to write PID file: %m") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
fprintf (fd, "%d\n", getpid ()) ;
|
||||
fclose (fd) ;
|
||||
}
|
||||
}
|
9
wiringPiD/daemonise.h
Normal file
9
wiringPiD/daemonise.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* daemonise.h:
|
||||
* Fairly generic "Turn the current process into a daemon" code.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Gordon Henderson.
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
extern void daemonise (const char *pidFile) ;
|
44
wiringPiD/drcNetCmd.h
Normal file
44
wiringPiD/drcNetCmd.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* drcNetCmd.c:
|
||||
* Copyright (c) 2012-2017 Gordon Henderson
|
||||
***********************************************************************
|
||||
* This file is part of wiringPi:
|
||||
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
||||
*
|
||||
* wiringPi is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wiringPi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#define DEFAULT_SERVER_PORT 6124
|
||||
|
||||
#define DRCN_PIN_MODE 1
|
||||
#define DRCN_PULL_UP_DN 2
|
||||
|
||||
#define DRCN_DIGITAL_WRITE 3
|
||||
#define DRCN_DIGITAL_WRITE8 4
|
||||
#define DRCN_ANALOG_WRITE 5
|
||||
#define DRCN_PWM_WRITE 6
|
||||
|
||||
#define DRCN_DIGITAL_READ 7
|
||||
#define DRCN_DIGITAL_READ8 8
|
||||
#define DRCN_ANALOG_READ 9
|
||||
|
||||
|
||||
struct drcNetComStruct
|
||||
{
|
||||
uint32_t pin ;
|
||||
uint32_t cmd ;
|
||||
uint32_t data ;
|
||||
};
|
||||
|
330
wiringPiD/network.c
Normal file
330
wiringPiD/network.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* network.c:
|
||||
* Part of wiringPiD
|
||||
* Copyright (c) 2012-2017 Gordon Henderson
|
||||
***********************************************************************
|
||||
* This file is part of wiringPi:
|
||||
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
||||
*
|
||||
* wiringPi is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wiringPi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <crypt.h>
|
||||
|
||||
#include "network.h"
|
||||
|
||||
#define TRUE (1==1)
|
||||
#define FALSE (!TRUE)
|
||||
|
||||
// Local data
|
||||
|
||||
#define SALT_LEN 16
|
||||
|
||||
static char salt [SALT_LEN + 1] ;
|
||||
static char *returnedHash = NULL ;
|
||||
static int serverFd = -1 ;
|
||||
|
||||
// Union for the server Socket Address
|
||||
|
||||
static union
|
||||
{
|
||||
struct sockaddr_in sin ;
|
||||
struct sockaddr_in6 sin6 ;
|
||||
} serverSockAddr ;
|
||||
|
||||
// and client address
|
||||
|
||||
static union
|
||||
{
|
||||
struct sockaddr_in sin ;
|
||||
struct sockaddr_in6 sin6 ;
|
||||
} clientSockAddr ;
|
||||
|
||||
|
||||
/*
|
||||
* getClientIP:
|
||||
* Returns a pointer to a static string containing the clients IP address
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
char *getClientIP (void)
|
||||
{
|
||||
char buf [INET6_ADDRSTRLEN] ;
|
||||
static char ipAddress [1024] ;
|
||||
|
||||
if (clientSockAddr.sin.sin_family == AF_INET) // IPv4
|
||||
{
|
||||
if (snprintf (ipAddress, 1024, "IPv4: %s",
|
||||
inet_ntop (clientSockAddr.sin.sin_family, (void *)&clientSockAddr.sin.sin_addr, buf, sizeof (buf))) == 1024)
|
||||
strcpy (ipAddress, "Too long") ;
|
||||
}
|
||||
else // IPv6
|
||||
{
|
||||
if (clientSockAddr.sin.sin_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&clientSockAddr.sin6.sin6_addr))
|
||||
{
|
||||
if (snprintf (ipAddress, 1024, "IPv4in6: %s",
|
||||
inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
|
||||
strcpy (ipAddress, "Too long") ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (snprintf (ipAddress, 1024, "IPv6: %s",
|
||||
inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
|
||||
strcpy (ipAddress, "Too long") ;
|
||||
}
|
||||
}
|
||||
|
||||
return ipAddress ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* clientPstr: clientPrintf:
|
||||
* Print over a network socket
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
static int clientPstr (int fd, char *s)
|
||||
{
|
||||
int len = strlen (s) ;
|
||||
return (write (fd, s, len) == len) ? 0 : -1 ;
|
||||
}
|
||||
|
||||
static int clientPrintf (const int fd, const char *message, ...)
|
||||
{
|
||||
va_list argp ;
|
||||
char buffer [1024] ;
|
||||
|
||||
va_start (argp, message) ;
|
||||
vsnprintf (buffer, 1023, message, argp) ;
|
||||
va_end (argp) ;
|
||||
|
||||
return clientPstr (fd, buffer) ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sendGreeting:
|
||||
* Send some text to the client device
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
int sendGreeting (int clientFd)
|
||||
{
|
||||
if (clientPrintf (clientFd, "200 Welcome to wiringPiD - http://wiringpi.com/\n") < 0)
|
||||
return -1 ;
|
||||
|
||||
return clientPrintf (clientFd, "200 Connecting from: %s\n", getClientIP ()) ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getSalt:
|
||||
* Create a random 'salt' value for the password encryption process
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
static int getSalt (char drySalt [])
|
||||
{
|
||||
static const char *seaDog = "abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789/." ;
|
||||
|
||||
unsigned char wetSalt [SALT_LEN] ;
|
||||
int i, fd ;
|
||||
|
||||
if ((fd = open ("/dev/urandom", O_RDONLY)) < 0)
|
||||
return fd ;
|
||||
|
||||
if (read (fd, wetSalt, SALT_LEN) != SALT_LEN)
|
||||
return -1 ;
|
||||
|
||||
close (fd) ;
|
||||
|
||||
for (i = 0 ; i < SALT_LEN ; ++i)
|
||||
drySalt [i] = seaDog [wetSalt [i] & 63] ;
|
||||
|
||||
drySalt [SALT_LEN] = 0 ;
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sendChallenge:
|
||||
* Create and send our salt (aka nonce) to the remote device
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
int sendChallenge (int clientFd)
|
||||
{
|
||||
if (getSalt (salt) < 0)
|
||||
return -1 ;
|
||||
|
||||
return clientPrintf (clientFd, "Challenge %s\n", salt) ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getResponse:
|
||||
* Read the encrypted password from the remote device.
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
int getResponse (int clientFd)
|
||||
{
|
||||
char reply [1024] ;
|
||||
int len ;
|
||||
|
||||
// Being sort of lazy about this. I'm expecting an SHA-512 hash back and these
|
||||
// are exactly 86 characters long, so no reason not to, I guess...
|
||||
|
||||
len = 86 ;
|
||||
|
||||
if (setsockopt (clientFd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0)
|
||||
return -1 ;
|
||||
|
||||
len = recv (clientFd, reply, 86, 0) ;
|
||||
if (len != 86)
|
||||
return -1 ;
|
||||
|
||||
reply [len] = 0 ;
|
||||
|
||||
if ((returnedHash = malloc (len + 1)) == NULL)
|
||||
return -1 ;
|
||||
|
||||
strcpy (returnedHash, reply) ;
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* passwordMatch:
|
||||
* See if there's a match. If not, we simply dump them.
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
int passwordMatch (const char *password)
|
||||
{
|
||||
char *encrypted ;
|
||||
char salted [1024] ;
|
||||
|
||||
sprintf (salted, "$6$%s$", salt) ;
|
||||
|
||||
encrypted = crypt (password, salted) ;
|
||||
|
||||
// 20: $6$ then 16 characters of salt, then $
|
||||
// 86 is the length of an SHA-512 hash
|
||||
|
||||
return strncmp (encrypted + 20, returnedHash, 86) == 0 ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setupServer:
|
||||
* Do what's needed to create a local server socket instance that can listen
|
||||
* on both IPv4 and IPv6 interfaces.
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
int setupServer (int serverPort)
|
||||
{
|
||||
socklen_t clientSockAddrSize = sizeof (clientSockAddr) ;
|
||||
|
||||
int on = 1 ;
|
||||
int family ;
|
||||
socklen_t serverSockAddrSize ;
|
||||
int clientFd ;
|
||||
|
||||
// Try to create an IPv6 socket
|
||||
|
||||
serverFd = socket (PF_INET6, SOCK_STREAM, 0) ;
|
||||
|
||||
// If it didn't work, then fall-back to IPv4.
|
||||
|
||||
if (serverFd < 0)
|
||||
{
|
||||
if ((serverFd = socket (PF_INET, SOCK_STREAM, 0)) < 0)
|
||||
return -1 ;
|
||||
|
||||
family = AF_INET ;
|
||||
serverSockAddrSize = sizeof (struct sockaddr_in) ;
|
||||
}
|
||||
else // We got an IPv6 socket
|
||||
{
|
||||
family = AF_INET6 ;
|
||||
serverSockAddrSize = sizeof (struct sockaddr_in6) ;
|
||||
}
|
||||
|
||||
if (setsockopt (serverFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
|
||||
return -1 ;
|
||||
|
||||
// Setup the servers socket address - cope with IPv4 and v6.
|
||||
|
||||
memset (&serverSockAddr, 0, sizeof (serverSockAddr)) ;
|
||||
switch (family)
|
||||
{
|
||||
case AF_INET:
|
||||
serverSockAddr.sin.sin_family = AF_INET ;
|
||||
serverSockAddr.sin.sin_addr.s_addr = htonl (INADDR_ANY) ;
|
||||
serverSockAddr.sin.sin_port = htons (serverPort) ;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
serverSockAddr.sin6.sin6_family = AF_INET6 ;
|
||||
serverSockAddr.sin6.sin6_addr = in6addr_any ;
|
||||
serverSockAddr.sin6.sin6_port = htons (serverPort) ;
|
||||
}
|
||||
|
||||
// Bind, listen and accept
|
||||
|
||||
if (bind (serverFd, (struct sockaddr *)&serverSockAddr, serverSockAddrSize) < 0)
|
||||
return -1 ;
|
||||
|
||||
if (listen (serverFd, 4) < 0) // Really only going to talk to one client at a time...
|
||||
return -1 ;
|
||||
|
||||
if ((clientFd = accept (serverFd, (struct sockaddr *)&clientSockAddr, &clientSockAddrSize)) < 0)
|
||||
return -1 ;
|
||||
|
||||
return clientFd ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* closeServer:
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
void closeServer (int clientFd)
|
||||
{
|
||||
if (serverFd != -1) close (serverFd) ;
|
||||
if (clientFd != -1) close (clientFd) ;
|
||||
serverFd = clientFd = -1 ;
|
||||
}
|
31
wiringPiD/network.h
Normal file
31
wiringPiD/network.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* network.h:
|
||||
* Part of wiringPiD
|
||||
* Copyright (c) 2012-2017 Gordon Henderson
|
||||
***********************************************************************
|
||||
* This file is part of wiringPi:
|
||||
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
||||
*
|
||||
* wiringPi is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wiringPi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
extern char *getClientIP (void) ;
|
||||
extern int getResponce (int clientFd) ;
|
||||
extern int setupServer (int serverPort) ;
|
||||
extern int sendGreeting (int clientFd) ;
|
||||
extern int sendChallenge (int clientFd) ;
|
||||
extern int getResponse (int clientFd) ;
|
||||
extern int passwordMatch (const char *password) ;
|
||||
extern void closeServer (int clientFd) ;
|
126
wiringPiD/runRemote.c
Normal file
126
wiringPiD/runRemote.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* runRemote.c:
|
||||
* Run the remote commands passed over the network link.
|
||||
*
|
||||
* Copyright (c) 2012-2017 Gordon Henderson
|
||||
***********************************************************************
|
||||
* This file is part of wiringPi:
|
||||
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
||||
*
|
||||
* wiringPi is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wiringPi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
//#include <stdarg.h>
|
||||
|
||||
#include <wiringPi.h>
|
||||
#include <wpiExtensions.h>
|
||||
|
||||
#include "drcNetCmd.h"
|
||||
#include "network.h"
|
||||
#include "runRemote.h"
|
||||
|
||||
|
||||
|
||||
int noLocalPins = FALSE ;
|
||||
|
||||
|
||||
void runRemoteCommands (int fd)
|
||||
{
|
||||
register uint32_t pin ;
|
||||
int len ;
|
||||
struct drcNetComStruct cmd ;
|
||||
|
||||
len = sizeof (struct drcNetComStruct) ;
|
||||
|
||||
if (setsockopt (fd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0)
|
||||
return ;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (recv (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) // Probably remote hangup
|
||||
return ;
|
||||
|
||||
pin = cmd.pin ;
|
||||
if (noLocalPins && ((pin & PI_GPIO_MASK) == 0))
|
||||
{
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
switch (cmd.cmd)
|
||||
{
|
||||
case DRCN_PIN_MODE:
|
||||
pinMode (pin, cmd.data) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
|
||||
case DRCN_PULL_UP_DN:
|
||||
pullUpDnControl (pin, cmd.data) ;
|
||||
break ;
|
||||
|
||||
case DRCN_PWM_WRITE:
|
||||
pwmWrite (pin, cmd.data) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
|
||||
case DRCN_DIGITAL_WRITE:
|
||||
digitalWrite (pin, cmd.data) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
|
||||
case DRCN_DIGITAL_WRITE8:
|
||||
//digitalWrite8 (pin, cmd.data) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
|
||||
case DRCN_DIGITAL_READ:
|
||||
cmd.data = digitalRead (pin) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
|
||||
case DRCN_DIGITAL_READ8:
|
||||
//cmd.data = digitalRead8 (pin) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
|
||||
case DRCN_ANALOG_WRITE:
|
||||
analogWrite (pin, cmd.data) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
|
||||
case DRCN_ANALOG_READ:
|
||||
cmd.data = analogRead (pin) ;
|
||||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd))
|
||||
return ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
29
wiringPiD/runRemote.h
Normal file
29
wiringPiD/runRemote.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* runRemote.h:
|
||||
* Run the remote commands passed over the network link.
|
||||
*
|
||||
* Copyright (c) 2012-2017 Gordon Henderson
|
||||
***********************************************************************
|
||||
* This file is part of wiringPi:
|
||||
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
||||
*
|
||||
* wiringPi is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wiringPi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
// Globals
|
||||
|
||||
extern int noLocalPins ;
|
||||
|
||||
extern void runRemoteCommands (int fd) ;
|
382
wiringPiD/wiringpid.c
Normal file
382
wiringPiD/wiringpid.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* wiringPiD.c:
|
||||
* Copyright (c) 2012-2017 Gordon Henderson
|
||||
***********************************************************************
|
||||
* This file is part of wiringPi:
|
||||
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
||||
*
|
||||
* wiringPi is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wiringPi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <wiringPi.h>
|
||||
#include <wpiExtensions.h>
|
||||
|
||||
#include "drcNetCmd.h"
|
||||
#include "network.h"
|
||||
#include "runRemote.h"
|
||||
#include "daemonise.h"
|
||||
|
||||
|
||||
#define PIDFILE "/var/run/wiringPiD.pid"
|
||||
|
||||
|
||||
// Globals
|
||||
|
||||
static const char *usage = "[-h] [-d] [-g | -1 | -z] [[-x extension:pin:params] ...] password" ;
|
||||
static int doDaemon = FALSE ;
|
||||
|
||||
//
|
||||
|
||||
static void logMsg (const char *message, ...)
|
||||
{
|
||||
va_list argp ;
|
||||
char buffer [1024] ;
|
||||
|
||||
va_start (argp, message) ;
|
||||
vsnprintf (buffer, 1023, message, argp) ;
|
||||
va_end (argp) ;
|
||||
|
||||
if (doDaemon)
|
||||
syslog (LOG_DAEMON | LOG_INFO, "%s", buffer) ;
|
||||
else
|
||||
printf ("%s\n", buffer) ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sigHandler:
|
||||
* setupSigHandler:
|
||||
* Somehing has happened that would normally terminate the program so try
|
||||
* to close down nicely.
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
void sigHandler (int sig)
|
||||
{
|
||||
logMsg ("Exiting on signal %d: %s", sig, strsignal (sig)) ;
|
||||
(void)unlink (PIDFILE) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
void setupSigHandler (void)
|
||||
{
|
||||
struct sigaction action ;
|
||||
|
||||
sigemptyset (&action.sa_mask) ;
|
||||
action.sa_flags = 0 ;
|
||||
|
||||
// Ignore what we can
|
||||
|
||||
action.sa_handler = SIG_IGN ;
|
||||
|
||||
sigaction (SIGHUP, &action, NULL) ;
|
||||
sigaction (SIGTTIN, &action, NULL) ;
|
||||
sigaction (SIGTTOU, &action, NULL) ;
|
||||
|
||||
// Trap what we can to exit gracefully
|
||||
|
||||
action.sa_handler = sigHandler ;
|
||||
|
||||
sigaction (SIGINT, &action, NULL) ;
|
||||
sigaction (SIGQUIT, &action, NULL) ;
|
||||
sigaction (SIGILL, &action, NULL) ;
|
||||
sigaction (SIGABRT, &action, NULL) ;
|
||||
sigaction (SIGFPE, &action, NULL) ;
|
||||
sigaction (SIGSEGV, &action, NULL) ;
|
||||
sigaction (SIGPIPE, &action, NULL) ;
|
||||
sigaction (SIGALRM, &action, NULL) ;
|
||||
sigaction (SIGTERM, &action, NULL) ;
|
||||
sigaction (SIGUSR1, &action, NULL) ;
|
||||
sigaction (SIGUSR2, &action, NULL) ;
|
||||
sigaction (SIGCHLD, &action, NULL) ;
|
||||
sigaction (SIGTSTP, &action, NULL) ;
|
||||
sigaction (SIGBUS, &action, NULL) ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The works...
|
||||
*********************************************************************************
|
||||
*/
|
||||
|
||||
int main (int argc, char *argv [])
|
||||
{
|
||||
int clientFd ;
|
||||
char *p, *password ;
|
||||
int i ;
|
||||
int port = DEFAULT_SERVER_PORT ;
|
||||
int wpiSetup = 0 ;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s %s\n", argv [0], usage) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
// Help?
|
||||
|
||||
if (strcasecmp (argv [1], "-h") == 0)
|
||||
{
|
||||
printf ("Usage: %s %s\n", argv [0], usage) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
// Daemonize?
|
||||
// Must come before the other args as e.g. some extensions
|
||||
// open files which get closed on daemonise...
|
||||
|
||||
if (strcasecmp (argv [1], "-d") == 0)
|
||||
{
|
||||
if (geteuid () != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: Must be root to run as a daemon.\n", argv [0]) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
doDaemon = TRUE ;
|
||||
daemonise (PIDFILE) ;
|
||||
|
||||
for (i = 2 ; i < argc ; ++i)
|
||||
argv [i - 1] = argv [i] ;
|
||||
--argc ;
|
||||
}
|
||||
|
||||
// Scan all other arguments
|
||||
|
||||
while (*argv [1] == '-')
|
||||
{
|
||||
|
||||
// Look for wiringPi setup arguments:
|
||||
// Same as the gpio command and rtb.
|
||||
|
||||
// -g - bcm_gpio
|
||||
|
||||
if (strcasecmp (argv [1], "-g") == 0)
|
||||
{
|
||||
if (wpiSetup == 0)
|
||||
{
|
||||
logMsg ("BCM_GPIO mode selected") ;
|
||||
wiringPiSetupGpio () ;
|
||||
}
|
||||
|
||||
for (i = 2 ; i < argc ; ++i)
|
||||
argv [i - 1] = argv [i] ;
|
||||
--argc ;
|
||||
++wpiSetup ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
// -1 - physical pins
|
||||
|
||||
if (strcasecmp (argv [1], "-1") == 0)
|
||||
{
|
||||
if (wpiSetup == 0)
|
||||
{
|
||||
logMsg ("GPIO-PHYS mode selected") ;
|
||||
wiringPiSetupPhys () ;
|
||||
}
|
||||
|
||||
for (i = 2 ; i < argc ; ++i)
|
||||
argv [i - 1] = argv [i] ;
|
||||
--argc ;
|
||||
++wpiSetup ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
// -z - no wiringPi - blocks remotes accessing local pins
|
||||
|
||||
if (strcasecmp (argv [1], "-z") == 0)
|
||||
{
|
||||
if (wpiSetup == 0)
|
||||
logMsg ("No GPIO mode selected") ;
|
||||
|
||||
for (i = 2 ; i < argc ; ++i)
|
||||
argv [i - 1] = argv [i] ;
|
||||
--argc ;
|
||||
noLocalPins = TRUE ;
|
||||
++wpiSetup ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
// -p to select the port
|
||||
|
||||
if (strcasecmp (argv [1], "-p") == 0)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
logMsg ("-p missing extension port") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
logMsg ("Setting port to: %s", argv [2]) ;
|
||||
|
||||
port = atoi (argv [2]) ;
|
||||
if ((port < 1) || (port > 65535))
|
||||
{
|
||||
logMsg ("Invalid server port: %d", port) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
// Shift args down by 2
|
||||
|
||||
for (i = 3 ; i < argc ; ++i)
|
||||
argv [i - 2] = argv [i] ;
|
||||
argc -= 2 ;
|
||||
|
||||
continue ;
|
||||
}
|
||||
|
||||
// Check for -x argument to load in a new extension
|
||||
// -x extension:base:args
|
||||
// Can load many modules to extend the daemon.
|
||||
|
||||
if (strcasecmp (argv [1], "-x") == 0)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
logMsg ("-x missing extension name:data:etc.") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
logMsg ("Loading extension: %s", argv [2]) ;
|
||||
|
||||
if (!loadWPiExtension (argv [0], argv [2], TRUE))
|
||||
{
|
||||
logMsg ("Extension load failed: %s", strerror (errno)) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
// Shift args down by 2
|
||||
|
||||
for (i = 3 ; i < argc ; ++i)
|
||||
argv [i - 2] = argv [i] ;
|
||||
argc -= 2 ;
|
||||
|
||||
continue ;
|
||||
}
|
||||
|
||||
logMsg ("Invalid parameter: %s", argv [1]) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
// Default to wiringPi mode
|
||||
|
||||
if (wpiSetup == 0)
|
||||
{
|
||||
logMsg ("WiringPi GPIO mode selected") ;
|
||||
wiringPiSetup () ;
|
||||
}
|
||||
|
||||
// Finally, should just be one arg left - the password...
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
logMsg ("No password supplied") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
if (strlen (argv [1]) < 6)
|
||||
{
|
||||
logMsg ("Password too short - at least 6 chars, not %d", strlen (argv [1])) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
if ((password = malloc (strlen (argv [1]) + 1)) == NULL)
|
||||
{
|
||||
logMsg ("Out of memory") ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
strcpy (password, argv [1]) ;
|
||||
|
||||
// Wipe out the password on the command-line in a vague attempt to try to
|
||||
// hide it from snoopers
|
||||
|
||||
for (p = argv [1] ; *p ; ++p)
|
||||
*p = ' ' ;
|
||||
|
||||
setupSigHandler () ;
|
||||
|
||||
// Enter our big loop
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
if (!doDaemon)
|
||||
printf ("-=-\nWaiting for a new connection...\n") ;
|
||||
|
||||
if ((clientFd = setupServer (port)) < 0)
|
||||
{
|
||||
logMsg ("Unable to setup server: %s", strerror (errno)) ;
|
||||
exit (EXIT_FAILURE) ;
|
||||
}
|
||||
|
||||
logMsg ("New connection from: %s.", getClientIP ()) ;
|
||||
|
||||
if (!doDaemon)
|
||||
printf ("Sending Greeting.\n") ;
|
||||
|
||||
if (sendGreeting (clientFd) < 0)
|
||||
{
|
||||
logMsg ("Unable to send greeting message: %s", strerror (errno)) ;
|
||||
closeServer (clientFd) ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
if (!doDaemon)
|
||||
printf ("Sending Challenge.\n") ;
|
||||
|
||||
if (sendChallenge (clientFd) < 0)
|
||||
{
|
||||
logMsg ("Unable to send challenge message: %s", strerror (errno)) ;
|
||||
closeServer (clientFd) ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
if (!doDaemon)
|
||||
printf ("Waiting for response.\n") ;
|
||||
|
||||
if (getResponse (clientFd) < 0)
|
||||
{
|
||||
logMsg ("Connection closed waiting for response: %s", strerror (errno)) ;
|
||||
closeServer (clientFd) ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
if (!passwordMatch (password))
|
||||
{
|
||||
logMsg ("Password failure") ;
|
||||
closeServer (clientFd) ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
logMsg ("Password OK - Starting") ;
|
||||
|
||||
runRemoteCommands (clientFd) ;
|
||||
closeServer (clientFd) ;
|
||||
}
|
||||
|
||||
return 0 ;
|
||||
}
|
Reference in New Issue
Block a user