Statistics
| Branch: | Revision:

ddr4s / fw / wiringPi / wiringPi / drcNet.c @ 32:cadb9025f1e0

History | View | Annotate | Download (9.83 KB)

1
/*
2
 * drcNet.h:
3
 *        Extend wiringPi with the DRC Network protocol (e.g. to another Pi)
4
 *        Copyright (c) 2016-2017 Gordon Henderson
5
 ***********************************************************************
6
 * This file is part of wiringPi:
7
 *        https://projects.drogon.net/raspberry-pi/wiringpi/
8
 *
9
 *    wiringPi is free software: you can redistribute it and/or modify
10
 *    it under the terms of the GNU Lesser General Public License as
11
 *    published by the Free Software Foundation, either version 3 of the
12
 *    License, or (at your option) any later version.
13
 *
14
 *    wiringPi is distributed in the hope that it will be useful,
15
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *    GNU Lesser General Public License for more details.
18
 *
19
 *    You should have received a copy of the GNU Lesser General Public
20
 *    License along with wiringPi.
21
 *    If not, see <http://www.gnu.org/licenses/>.
22
 ***********************************************************************
23
 */
24

    
25
#include <stdio.h>
26
#include <stdint.h>
27
#include <unistd.h>
28
#include <sys/types.h>
29
#include <sys/socket.h>
30
#include <arpa/inet.h>
31
#include <netdb.h>
32
#include <string.h>
33
#include <errno.h>
34
#include <crypt.h>
35

    
36

    
37
#include "wiringPi.h"
38
#include "drcNet.h"
39
#include "../wiringPiD/drcNetCmd.h"
40

    
41

    
42
/*
43
 * remoteReadline:
44
 *        Read in a line of data from the remote server, ending with a newline
45
 *        character which is not stored. Returns the length or < 0 on
46
 *        any sort of failure.
47
 *********************************************************************************
48
 */
49

    
50
static int remoteReadline (int fd, char *buf, int max)
51
{
52
  int  len = 0 ;
53
  char c ;
54

    
55
  for (;;)
56
  {
57
    if (read (fd, &c, 1) < 1)
58
      return -1 ;
59

    
60
    if (c == '\n')
61
      return len ;
62

    
63
    *buf++ = c ;
64
    if (++len == max)
65
      return len ;
66
  }
67
}
68

    
69

    
70
/*
71
 * getChallenge:
72
 *        Read in lines from the remote site until we get one identified
73
 *        as the challenge. This line contains the password salt.
74
 *********************************************************************************
75
 */
76

    
77
static char *getChallenge (int fd)
78
{
79
  static char buf [1024] ;
80
  int num ;
81

    
82
  for (;;)
83
  {
84
    if ((num = remoteReadline (fd, buf, 1023)) < 0)
85
      return NULL ;
86
    buf [num] = 0 ;
87

    
88
    if (strncmp (buf, "Challenge ", 10) == 0)
89
      return &buf [10] ;
90
  }
91
}
92

    
93

    
94
/*
95
 * authenticate:
96
 *        Read in the challenge from the server, use it to encrypt our password
97
 *        and send it back to the server. Wait for a reply back from the server
98
 *        to say that we're good to go.
99
 *        The server will simply disconnect on a bad response. No 3 chances here.
100
 *********************************************************************************
101
 */
102

    
103
static int authenticate (int fd, const char *pass)
104
{
105
  char *challenge ;
106
  char *encrypted ;
107
  char salted [1024] ;
108

    
109
  if ((challenge = getChallenge (fd)) == NULL)
110
    return -1 ;
111

    
112
  sprintf (salted, "$6$%s$", challenge) ;
113
  encrypted = crypt (pass, salted) ;
114
  
115
// This is an assertion, or sanity check on my part...
116
//        The '20' comes from the $6$ then the 16 characters of the salt,
117
//        then the terminating $.
118

    
119
  if (strncmp (encrypted, salted, 20) != 0)
120
  {
121
    errno = EBADE ;
122
    return -1 ;
123
  }
124

    
125
// 86 characters is the length of the SHA-256 hash
126

    
127
  if (write (fd, encrypted + 20, 86) == 86)
128
    return 0 ;
129
  else
130
    return -1 ;
131
}
132

    
133

    
134
/*
135
 * _drcSetupNet:
136
 *        Do the hard work of establishing a network connection and authenticating
137
 *        the password.
138
 *********************************************************************************
139
 */
140

    
141
int _drcSetupNet (const char *ipAddress, const char *port, const char *password)
142
{
143
  struct addrinfo hints;
144
  struct addrinfo *result, *rp ;
145
  struct in6_addr serveraddr ;
146
  int remoteFd ;
147

    
148
// Start by seeing if we've been given a (textual) numeric IP address
149
//        which will save lookups in getaddrinfo()
150

    
151
  memset (&hints, 0, sizeof (hints)) ;
152
  hints.ai_flags    = AI_NUMERICSERV ;
153
  hints.ai_family   = AF_UNSPEC ;
154
  hints.ai_socktype = SOCK_STREAM ;
155
  hints.ai_protocol = 0 ;
156

    
157
  if (inet_pton (AF_INET, ipAddress, &serveraddr) == 1)                // Valid IPv4
158
  {
159
    hints.ai_family = AF_INET ;
160
    hints.ai_flags |= AI_NUMERICHOST ;
161
  }
162
  else
163
  {
164
    if (inet_pton (AF_INET6, ipAddress, &serveraddr) == 1)        // Valid IPv6
165
    {
166
      hints.ai_family = AF_INET6 ;
167
      hints.ai_flags |= AI_NUMERICHOST ;
168
    }
169
  }
170

    
171
// Now use getaddrinfo() with the newly supplied hints
172

    
173
  if (getaddrinfo (ipAddress, port, &hints, &result) != 0)
174
    return -1 ;
175

    
176
// Now try each address in-turn until we get one that connects...
177

    
178
  for (rp = result; rp != NULL; rp = rp->ai_next)
179
  {
180
    if ((remoteFd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
181
      continue ;
182

    
183
    if (connect (remoteFd, rp->ai_addr, rp->ai_addrlen) < 0)
184
      continue ;
185

    
186
    if (authenticate (remoteFd, password) < 0)
187
    {
188
      close (remoteFd) ;
189
      errno = EACCES ;                // Permission denied
190
      return -1 ;
191
    }
192
    else
193
      return remoteFd ;
194
  }
195

    
196
  errno = EHOSTUNREACH ;        // Host unreachable - may not be right, but good enough
197
  return -1 ; // Nothing connected
198
}
199

    
200

    
201
/*
202
 * myPinMode:
203
 *        Change the pin mode on the remote DRC device
204
 *********************************************************************************
205
 */
206

    
207
static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode)
208
{
209
  struct drcNetComStruct cmd ;
210

    
211
  cmd.pin  = pin - node->pinBase ;
212
  cmd.cmd  = DRCN_PIN_MODE ;
213
  cmd.data = mode ;
214

    
215
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
216
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
217
}
218

    
219

    
220
/*
221
 * myPullUpDnControl:
222
 *********************************************************************************
223
 */
224

    
225
static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode)
226
{
227
  struct drcNetComStruct cmd ;
228

    
229
  cmd.pin  = pin - node->pinBase ;
230
  cmd.cmd  = DRCN_PULL_UP_DN ;
231
  cmd.data = mode ;
232

    
233
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
234
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
235
}
236

    
237

    
238
/*
239
 * myDigitalWrite:
240
 *********************************************************************************
241
 */
242

    
243
static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value)
244
{
245
  struct drcNetComStruct cmd ;
246

    
247
  cmd.pin  = pin - node->pinBase ;
248
  cmd.cmd  = DRCN_DIGITAL_WRITE ;
249
  cmd.data = value ;
250

    
251
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
252
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
253
}
254

    
255

    
256
/*
257
 * myDigitalWrite8:
258
 *********************************************************************************
259

260
static void myDigitalWrite8 (struct wiringPiNodeStruct *node, int pin, int value)
261
{
262
  struct drcNetComStruct cmd ;
263

264
  cmd.pin  = pin - node->pinBase ;
265
  cmd.cmd  = DRCN_DIGITAL_WRITE8 ;
266
  cmd.data = value ;
267

268
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
269
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
270
}
271
 */
272

    
273

    
274
/*
275
 * myAnalogWrite:
276
 *********************************************************************************
277
 */
278

    
279
static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value)
280
{
281
  struct drcNetComStruct cmd ;
282

    
283
  cmd.pin  = pin - node->pinBase ;
284
  cmd.cmd  = DRCN_ANALOG_WRITE ;
285
  cmd.data = value ;
286

    
287
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
288
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
289
}
290

    
291

    
292
/*
293
 * myPwmWrite:
294
 *********************************************************************************
295
 */
296

    
297
static void myPwmWrite (struct wiringPiNodeStruct *node, int pin, int value)
298
{
299
  struct drcNetComStruct cmd ;
300

    
301
  cmd.pin  = pin - node->pinBase ;
302
  cmd.cmd  = DRCN_PWM_WRITE ;
303
  cmd.data = value ;
304

    
305
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
306
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
307
}
308

    
309

    
310
/*
311
 * myAnalogRead:
312
 *********************************************************************************
313
 */
314

    
315
static int myAnalogRead (struct wiringPiNodeStruct *node, int pin)
316
{
317
  struct drcNetComStruct cmd ;
318

    
319
  cmd.pin  = pin - node->pinBase ;
320
  cmd.cmd  = DRCN_ANALOG_READ ;
321
  cmd.data = 0 ;
322

    
323
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
324
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
325

    
326
  return cmd.data ;
327
}
328

    
329

    
330
/*
331
 * myDigitalRead:
332
 *********************************************************************************
333
 */
334

    
335
static int myDigitalRead (struct wiringPiNodeStruct *node, int pin)
336
{
337
  struct drcNetComStruct cmd ;
338

    
339
  cmd.pin  = pin - node->pinBase ;
340
  cmd.cmd  = DRCN_DIGITAL_READ ;
341
  cmd.data = 0 ;
342

    
343
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
344
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
345

    
346
  return cmd.data ;
347
}
348

    
349

    
350
/*
351
 * myDigitalRead8:
352
 *********************************************************************************
353

354
static unsigned int myDigitalRead8 (struct wiringPiNodeStruct *node, int pin)
355
{
356
  struct drcNetComStruct cmd ;
357

358
  cmd.pin  = pin - node->pinBase ;
359
  cmd.cmd  = DRCN_DIGITAL_READ8 ;
360
  cmd.data = 0 ;
361

362
  (void)send (node->fd, &cmd, sizeof (cmd), 0) ;
363
  (void)recv (node->fd, &cmd, sizeof (cmd), 0) ;
364

365
  return cmd.data ;
366
}
367
 */
368

    
369

    
370
/*
371
 * drcNet:
372
 *        Create a new instance of an DRC GPIO interface.
373
 *        Could be a variable nunber of pins here - we might not know in advance.
374
 *********************************************************************************
375
 */
376

    
377
int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, const char *port, const char *password)
378
{
379
  int fd, len ;
380
  struct wiringPiNodeStruct *node ;
381

    
382
  if ((fd = _drcSetupNet (ipAddress, port, password)) < 0)
383
    return FALSE ;
384

    
385
  len = sizeof (struct drcNetComStruct) ;
386

    
387
  if (setsockopt (fd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0)
388
    return FALSE ;
389

    
390
  node = wiringPiNewNode (pinBase, numPins) ;
391

    
392
  node->fd               = fd ;
393
  node->pinMode          = myPinMode ;
394
  node->pullUpDnControl  = myPullUpDnControl ;
395
  node->analogRead       = myAnalogRead ;
396
  node->analogRead       = myAnalogRead ;
397
  node->analogWrite      = myAnalogWrite ;
398
  node->digitalRead      = myDigitalRead ;
399
  node->digitalWrite     = myDigitalWrite ;
400
//node->digitalRead8     = myDigitalRead8 ;
401
//node->digitalWrite8    = myDigitalWrite8 ;
402
  node->pwmWrite         = myPwmWrite ;
403

    
404
  return TRUE ;
405
}