iPXE
peerdisc.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <ipxe/xfer.h>
32 #include <ipxe/iobuf.h>
33 #include <ipxe/open.h>
34 #include <ipxe/tcpip.h>
35 #include <ipxe/uuid.h>
36 #include <ipxe/base16.h>
37 #include <ipxe/netdevice.h>
38 #include <ipxe/timer.h>
39 #include <ipxe/fault.h>
40 #include <ipxe/settings.h>
41 #include <ipxe/pccrd.h>
42 #include <ipxe/peerdisc.h>
43 
44 /** @file
45  *
46  * Peer Content Caching and Retrieval (PeerDist) protocol peer discovery
47  *
48  */
49 
50 /** List of discovery segments */
51 static LIST_HEAD ( peerdisc_segments );
52 
53 /** Number of repeated discovery attempts */
54 #define PEERDISC_REPEAT_COUNT 2
55 
56 /** Time between repeated discovery attempts */
57 #define PEERDISC_REPEAT_TIMEOUT ( 1 * TICKS_PER_SEC )
58 
59 /** Default discovery timeout (in seconds) */
60 #define PEERDISC_DEFAULT_TIMEOUT_SECS 2
61 
62 /** Recommended discovery timeout (in seconds)
63  *
64  * We reduce the recommended discovery timeout whenever a segment
65  * fails to discover any peers, and restore the default value whenever
66  * a valid discovery reply is received. We continue to send discovery
67  * requests even if the recommended timeout is reduced to zero.
68  *
69  * This strategy is intended to minimise discovery delays when no
70  * peers are available on the network, while allowing downloads to
71  * quickly switch back to using PeerDist acceleration if new peers
72  * become available.
73  */
75 
76 /** Most recently discovered peer (for any block) */
77 static char *peerdisc_recent;
78 
79 /** Hosted cache server */
80 static char *peerhost;
81 
82 static struct peerdisc_segment * peerdisc_find ( const char *id );
83 static int peerdisc_discovered ( struct peerdisc_segment *segment,
84  const char *location );
85 
86 /******************************************************************************
87  *
88  * Statistics reporting
89  *
90  ******************************************************************************
91  */
92 
93 /**
94  * Report peer discovery statistics
95  *
96  * @v intf Interface
97  * @v peer Selected peer (or NULL)
98  * @v peers List of available peers
99  */
100 void peerdisc_stat ( struct interface *intf, struct peerdisc_peer *peer,
101  struct list_head *peers ) {
102  struct interface *dest;
103  peerdisc_stat_TYPE ( void * ) *op =
104  intf_get_dest_op ( intf, peerdisc_stat, &dest );
105  void *object = intf_object ( dest );
106 
107  if ( op ) {
108  op ( object, peer, peers );
109  } else {
110  /* Default is to do nothing */
111  }
112 
113  intf_put ( dest );
114 }
115 
116 /******************************************************************************
117  *
118  * Discovery sockets
119  *
120  ******************************************************************************
121  */
122 
123 /**
124  * Open all PeerDist discovery sockets
125  *
126  * @ret rc Return status code
127  */
128 static int peerdisc_socket_open ( void ) {
129  struct peerdisc_socket *socket;
130  int rc;
131 
132  /* Open each socket */
134  if ( ( rc = xfer_open_socket ( &socket->xfer, SOCK_DGRAM,
135  &socket->address.sa,
136  NULL ) ) != 0 ) {
137  DBGC ( socket, "PEERDISC %s could not open socket: "
138  "%s\n", socket->name, strerror ( rc ) );
139  goto err;
140  }
141  }
142 
143  return 0;
144 
145  err:
147  intf_restart ( &socket->xfer, rc );
148  return rc;
149 }
150 
151 /**
152  * Attempt to transmit PeerDist discovery requests on all sockets
153  *
154  * @v uuid Message UUID string
155  * @v id Segment identifier string
156  */
157 static void peerdisc_socket_tx ( const char *uuid, const char *id ) {
158  struct peerdisc_socket *socket;
159  struct net_device *netdev;
160  struct xfer_metadata meta;
161  union {
162  struct sockaddr sa;
163  struct sockaddr_tcpip st;
164  } address;
165  char *request;
166  size_t len;
167  int rc;
168 
169  /* Construct discovery request */
171  if ( ! request )
172  goto err_request;
173  len = strlen ( request );
174 
175  /* Initialise data transfer metadata */
176  memset ( &meta, 0, sizeof ( meta ) );
177  meta.dest = &address.sa;
178 
179  /* Send message on each socket */
181 
182  /* Initialise socket address */
183  memcpy ( &address.sa, &socket->address.sa,
184  sizeof ( address.sa ) );
185 
186  /* Send message on each open network device */
187  for_each_netdev ( netdev ) {
188 
189  /* Skip unopened network devices */
190  if ( ! netdev_is_open ( netdev ) )
191  continue;
192  address.st.st_scope_id = netdev->index;
193 
194  /* Discard request (for test purposes) if applicable */
195  if ( inject_fault ( PEERDISC_DISCARD_RATE ) )
196  continue;
197 
198  /* Transmit request */
199  if ( ( rc = xfer_deliver_raw_meta ( &socket->xfer,
200  request, len,
201  &meta ) ) != 0 ) {
202  DBGC ( socket, "PEERDISC %s could not transmit "
203  "via %s: %s\n", socket->name,
204  netdev->name, strerror ( rc ) );
205  /* Contine to try other net devices/sockets */
206  continue;
207  }
208  }
209  }
210 
211  free ( request );
212  err_request:
213  return;
214 }
215 
216 /**
217  * Handle received PeerDist discovery reply
218  *
219  * @v socket PeerDist discovery socket
220  * @v iobuf I/O buffer
221  * @v meta Data transfer metadata
222  * @ret rc Return status code
223  */
224 static int peerdisc_socket_rx ( struct peerdisc_socket *socket,
225  struct io_buffer *iobuf,
226  struct xfer_metadata *meta __unused ) {
227  struct peerdist_discovery_reply reply;
228  struct peerdisc_segment *segment;
229  char *id;
230  char *location;
231  int rc;
232 
233  /* Discard reply (for test purposes) if applicable */
234  if ( ( rc = inject_fault ( PEERDISC_DISCARD_RATE ) ) != 0 )
235  goto err;
236 
237  /* Parse reply */
238  if ( ( rc = peerdist_discovery_reply ( iobuf->data, iob_len ( iobuf ),
239  &reply ) ) != 0 ) {
240  DBGC ( socket, "PEERDISC %s could not parse reply: %s\n",
241  socket->name, strerror ( rc ) );
242  DBGC_HDA ( socket, 0, iobuf->data, iob_len ( iobuf ) );
243  goto err;
244  }
245 
246  /* Any kind of discovery reply indicates that there are active
247  * peers on a local network, so restore the recommended
248  * discovery timeout to its default value for future requests.
249  */
251  DBGC ( socket, "PEERDISC %s restoring timeout to %d seconds\n",
253  }
255 
256  /* Iterate over segment IDs */
257  for ( id = reply.ids ; *id ; id += ( strlen ( id ) + 1 /* NUL */ ) ) {
258 
259  /* Find corresponding segment */
260  segment = peerdisc_find ( id );
261  if ( ! segment ) {
262  DBGC ( socket, "PEERDISC %s ignoring reply for %s\n",
263  socket->name, id );
264  continue;
265  }
266 
267  /* Report all discovered peer locations */
268  for ( location = reply.locations ; *location ;
269  location += ( strlen ( location ) + 1 /* NUL */ ) ) {
270 
271  /* Report discovered peer location */
272  if ( ( rc = peerdisc_discovered ( segment,
273  location ) ) != 0 )
274  goto err;
275  }
276  }
277 
278  err:
279  free_iob ( iobuf );
280  return rc;
281 }
282 
283 /**
284  * Close all PeerDist discovery sockets
285  *
286  * @v rc Reason for close
287  */
288 static void peerdisc_socket_close ( int rc ) {
289  struct peerdisc_socket *socket;
290 
291  /* Close all sockets */
293  intf_restart ( &socket->xfer, rc );
294 }
295 
296 /** PeerDist discovery socket interface operations */
299 };
300 
301 /** PeerDist discovery socket interface descriptor */
304 
305 /** PeerDist discovery IPv4 socket */
306 struct peerdisc_socket peerdisc_socket_ipv4 __peerdisc_socket = {
307  .name = "IPv4",
308  .address = {
309  .sin = {
310  .sin_family = AF_INET,
311  .sin_port = htons ( PEERDIST_DISCOVERY_PORT ),
312  .sin_addr.s_addr = htonl ( PEERDIST_DISCOVERY_IPV4 ),
313  },
314  },
315  .xfer = INTF_INIT ( peerdisc_socket_desc ),
316 };
317 
318 /** PeerDist discovery IPv6 socket */
319 struct peerdisc_socket peerdisc_socket_ipv6 __peerdisc_socket = {
320  .name = "IPv6",
321  .address = {
322  .sin6 = {
323  .sin6_family = AF_INET6,
324  .sin6_port = htons ( PEERDIST_DISCOVERY_PORT ),
325  .sin6_addr.s6_addr = PEERDIST_DISCOVERY_IPV6,
326  },
327  },
328  .xfer = INTF_INIT ( peerdisc_socket_desc ),
329 };
330 
331 /******************************************************************************
332  *
333  * Discovery segments
334  *
335  ******************************************************************************
336  */
337 
338 /**
339  * Free PeerDist discovery segment
340  *
341  * @v refcnt Reference count
342  */
343 static void peerdisc_free ( struct refcnt *refcnt ) {
344  struct peerdisc_segment *segment =
346  struct peerdisc_peer *peer;
347  struct peerdisc_peer *tmp;
348 
349  /* Free all discovered peers */
350  list_for_each_entry_safe ( peer, tmp, &segment->peers, list ) {
351  list_del ( &peer->list );
352  free ( peer );
353  }
354 
355  /* Free segment */
356  free ( segment );
357 }
358 
359 /**
360  * Find PeerDist discovery segment
361  *
362  * @v id Segment ID
363  * @ret segment PeerDist discovery segment, or NULL if not found
364  */
365 static struct peerdisc_segment * peerdisc_find ( const char *id ) {
366  struct peerdisc_segment *segment;
367 
368  /* Look for a matching segment */
369  list_for_each_entry ( segment, &peerdisc_segments, list ) {
370  if ( strcmp ( id, segment->id ) == 0 )
371  return segment;
372  }
373 
374  return NULL;
375 }
376 
377 /**
378  * Add discovered PeerDist peer
379  *
380  * @v segment PeerDist discovery segment
381  * @v location Peer location
382  * @ret rc Return status code
383  */
385  const char *location ) {
386  struct peerdisc_peer *peer;
387  struct peerdisc_client *peerdisc;
388  struct peerdisc_client *tmp;
389  char *recent;
390 
391  /* Ignore duplicate peers */
392  list_for_each_entry ( peer, &segment->peers, list ) {
393  if ( strcmp ( peer->location, location ) == 0 ) {
394  DBGC2 ( segment, "PEERDISC %p duplicate %s\n",
395  segment, location );
396  return 0;
397  }
398  }
399  DBGC2 ( segment, "PEERDISC %p discovered %s\n", segment, location );
400 
401  /* Allocate and initialise structure */
402  peer = zalloc ( sizeof ( *peer ) + strlen ( location ) + 1 /* NUL */ );
403  if ( ! peer )
404  return -ENOMEM;
405  strcpy ( peer->location, location );
406 
407  /* Add to end of list of peers */
408  list_add_tail ( &peer->list, &segment->peers );
409 
410  /* Record as most recently discovered peer */
411  if ( location != peerdisc_recent ) {
412  recent = strdup ( location );
413  if ( recent ) {
414  free ( peerdisc_recent );
415  peerdisc_recent = recent;
416  }
417  }
418 
419  /* Notify all clients */
420  list_for_each_entry_safe ( peerdisc, tmp, &segment->clients, list )
421  peerdisc->op->discovered ( peerdisc );
422 
423  return 0;
424 }
425 
426 /**
427  * Handle discovery timer expiry
428  *
429  * @v timer Discovery timer
430  * @v over Failure indicator
431  */
432 static void peerdisc_expired ( struct retry_timer *timer, int over __unused ) {
433  struct peerdisc_segment *segment =
435 
436  /* Attempt to transmit discovery requests */
437  peerdisc_socket_tx ( segment->uuid, segment->id );
438 
439  /* Schedule next transmission, if applicable */
440  if ( timer->count < PEERDISC_REPEAT_COUNT )
442 }
443 
444 /**
445  * Create PeerDist discovery segment
446  *
447  * @v id Segment ID
448  * @ret segment PeerDist discovery segment, or NULL on error
449  */
450 static struct peerdisc_segment * peerdisc_create ( const char *id ) {
451  struct peerdisc_segment *segment;
452  union {
453  union uuid uuid;
454  uint32_t dword[ sizeof ( union uuid ) / sizeof ( uint32_t ) ];
455  } random_uuid;
456  size_t uuid_len;
457  size_t id_len;
458  const char *uuid;
459  char *uuid_copy;
460  char *id_copy;
461  unsigned int i;
462  int rc;
463 
464  /* Generate a random message UUID. This does not require high
465  * quality randomness.
466  */
467  for ( i = 0 ; i < ( sizeof ( random_uuid.dword ) /
468  sizeof ( random_uuid.dword[0] ) ) ; i++ )
469  random_uuid.dword[i] = random();
470  uuid = uuid_ntoa ( &random_uuid.uuid );
471 
472  /* Calculate string lengths */
473  id_len = ( strlen ( id ) + 1 /* NUL */ );
474  uuid_len = ( strlen ( uuid ) + 1 /* NUL */ );
475 
476  /* Allocate and initialise structure */
477  segment = zalloc ( sizeof ( *segment ) + id_len + uuid_len );
478  if ( ! segment )
479  goto err_alloc;
480  id_copy = ( ( ( void * ) segment ) + sizeof ( *segment ) );
481  memcpy ( id_copy, id, id_len );
482  uuid_copy = ( ( ( void * ) id_copy ) + id_len );
483  memcpy ( uuid_copy, uuid, uuid_len );
484  ref_init ( &segment->refcnt, peerdisc_free );
485  segment->id = id_copy;
486  segment->uuid = uuid_copy;
487  INIT_LIST_HEAD ( &segment->peers );
488  INIT_LIST_HEAD ( &segment->clients );
489  timer_init ( &segment->timer, peerdisc_expired, &segment->refcnt );
490 
491  /* Add hosted cache server or initiate discovery */
492  if ( peerhost ) {
493 
494  /* Add hosted cache server to list of peers */
495  if ( ( rc = peerdisc_discovered ( segment, peerhost ) ) != 0 )
496  goto err_peerhost;
497 
498  } else {
499 
500  /* Add most recently discovered peer to list of peers
501  *
502  * This is a performance optimisation: we assume that
503  * the most recently discovered peer for any block has
504  * a high probability of also having a copy of the
505  * next block that we attempt to discover.
506  */
507  if ( peerdisc_recent )
509 
510  /* Start discovery timer */
511  start_timer_nodelay ( &segment->timer );
512  DBGC2 ( segment, "PEERDISC %p discovering %s\n",
513  segment, segment->id );
514  }
515 
516  /* Add to list of segments, transfer reference to list, and return */
517  list_add_tail ( &segment->list, &peerdisc_segments );
518  return segment;
519 
520  err_peerhost:
521  ref_put ( &segment->refcnt );
522  err_alloc:
523  return NULL;
524 }
525 
526 /**
527  * Destroy PeerDist discovery segment
528  *
529  * @v segment PeerDist discovery segment
530  */
531 static void peerdisc_destroy ( struct peerdisc_segment *segment ) {
532 
533  /* Sanity check */
534  assert ( list_empty ( &segment->clients ) );
535 
536  /* Stop timer */
537  stop_timer ( &segment->timer );
538 
539  /* Remove from list of segments and drop list's reference */
540  list_del ( &segment->list );
541  ref_put ( &segment->refcnt );
542 }
543 
544 /******************************************************************************
545  *
546  * Discovery clients
547  *
548  ******************************************************************************
549  */
550 
551 /**
552  * Open PeerDist discovery client
553  *
554  * @v peerdisc PeerDist discovery client
555  * @v id Segment ID
556  * @v len Length of segment ID
557  * @ret rc Return status code
558  */
559 int peerdisc_open ( struct peerdisc_client *peerdisc, const void *id,
560  size_t len ) {
561  struct peerdisc_segment *segment;
562  char id_string[ base16_encoded_len ( len ) + 1 /* NUL */ ];
563  char *id_chr;
564  int rc;
565 
566  /* Construct ID string */
567  base16_encode ( id, len, id_string, sizeof ( id_string ) );
568  for ( id_chr = id_string ; *id_chr ; id_chr++ )
569  *id_chr = toupper ( *id_chr );
570 
571  /* Sanity check */
572  assert ( peerdisc->segment == NULL );
573 
574  /* Open socket if this is the first segment */
575  if ( list_empty ( &peerdisc_segments ) &&
576  ( ( rc = peerdisc_socket_open() ) != 0 ) )
577  return rc;
578 
579  /* Find or create segment */
580  if ( ! ( ( segment = peerdisc_find ( id_string ) ) ||
581  ( segment = peerdisc_create ( id_string ) ) ) )
582  return -ENOMEM;
583 
584  /* Add to list of clients */
585  ref_get ( &segment->refcnt );
586  peerdisc->segment = segment;
587  list_add_tail ( &peerdisc->list, &segment->clients );
588 
589  return 0;
590 }
591 
592 /**
593  * Close PeerDist discovery client
594  *
595  * @v peerdisc PeerDist discovery client
596  */
597 void peerdisc_close ( struct peerdisc_client *peerdisc ) {
598  struct peerdisc_segment *segment = peerdisc->segment;
599 
600  /* Ignore if discovery is already closed */
601  if ( ! segment )
602  return;
603 
604  /* If no peers were discovered, reduce the recommended
605  * discovery timeout to minimise delays on future requests.
606  */
607  if ( list_empty ( &segment->peers ) && peerdisc_timeout_secs ) {
609  DBGC ( segment, "PEERDISC %p reducing timeout to %d "
610  "seconds\n", peerdisc, peerdisc_timeout_secs );
611  }
612 
613  /* Remove from list of clients */
614  peerdisc->segment = NULL;
615  list_del ( &peerdisc->list );
616  ref_put ( &segment->refcnt );
617 
618  /* If this was the last clients, destroy the segment */
619  if ( list_empty ( &segment->clients ) )
621 
622  /* If there are no more segments, close the socket */
623  if ( list_empty ( &peerdisc_segments ) )
624  peerdisc_socket_close ( 0 );
625 }
626 
627 /******************************************************************************
628  *
629  * Settings
630  *
631  ******************************************************************************
632  */
633 
634 /** PeerDist hosted cache server setting */
635 const struct setting peerhost_setting __setting ( SETTING_MISC, peerhost ) = {
636  .name = "peerhost",
637  .description = "PeerDist hosted cache",
638  .type = &setting_type_string,
639 };
640 
641 /**
642  * Apply PeerDist discovery settings
643  *
644  * @ret rc Return status code
645  */
646 static int apply_peerdisc_settings ( void ) {
647 
648  /* Free any existing hosted cache server */
649  free ( peerhost );
650  peerhost = NULL;
651 
652  /* Fetch hosted cache server */
653  fetch_string_setting_copy ( NULL, &peerhost_setting, &peerhost );
654  if ( peerhost ) {
655  DBGC ( &peerhost, "PEERDISC using hosted cache %s\n",
656  peerhost );
657  }
658 
659  return 0;
660 }
661 
662 /** PeerDist discovery settings applicator */
663 struct settings_applicator peerdisc_applicator __settings_applicator = {
665 };
struct list_head peers
List of discovered peers.
Definition: peerdisc.h:63
An object interface operation.
Definition: interface.h:17
uint16_t segment
Code segment.
Definition: librm.h:252
TCP/IP socket address.
Definition: tcpip.h:75
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
Definition: interface.c:342
Data transfer metadata.
Definition: xfer.h:22
#define AF_INET6
IPv6 Internet addresses.
Definition: socket.h:64
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition: retry.h:99
int xfer_deliver_raw_meta(struct interface *intf, const void *data, size_t len, struct xfer_metadata *meta)
Deliver datagram as raw data.
Definition: xfer.c:267
static void peerdisc_socket_tx(const char *uuid, const char *id)
Attempt to transmit PeerDist discovery requests on all sockets.
Definition: peerdisc.c:157
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:64
Error codes.
A universally unique ID.
Definition: uuid.h:15
int xfer_open_socket(struct interface *intf, int semantics, struct sockaddr *peer, struct sockaddr *local)
Open socket.
Definition: open.c:142
static void peerdisc_socket_close(int rc)
Close all PeerDist discovery sockets.
Definition: peerdisc.c:288
A PeerDist discovery socket.
Definition: peerdisc.h:22
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:146
uint64_t address
Base address.
Definition: ena.h:24
#define INTF_INIT(descriptor)
Initialise a static object interface.
Definition: interface.h:204
#define SOCK_DGRAM
Definition: socket.h:29
A PeerDist discovery segment.
Definition: peerdisc.h:42
#define PEERDIST_DISCOVERY_IPV4
PeerDist discovery IPv4 address (239.255.255.250)
Definition: pccrd.h:16
#define DBGC(...)
Definition: compiler.h:505
A retry timer.
Definition: retry.h:21
const struct setting peerhost_setting __setting(SETTING_MISC, peerhost)
PeerDist hosted cache server setting.
Universally unique IDs.
A settings applicator.
Definition: settings.h:251
static struct interface_operation peerdisc_socket_operations[]
PeerDist discovery socket interface operations.
Definition: peerdisc.c:297
iPXE timers
#define SETTING_MISC
Miscellaneous settings.
Definition: settings.h:80
#define PEERDISC_SOCKETS
PeerDist discovery socket table.
Definition: peerdisc.h:36
static char * peerdisc_recent
Most recently discovered peer (for any block)
Definition: peerdisc.c:77
static void peerdisc_free(struct refcnt *refcnt)
Free PeerDist discovery segment.
Definition: peerdisc.c:343
struct list_head list
List of clients.
Definition: peerdisc.h:83
Character types.
Peer Content Caching and Retrieval (PeerDist) protocol peer discovery.
#define htonl(value)
Definition: byteswap.h:133
#define PEERDISC_DISCARD_RATE
Definition: fault.h:18
static struct peerdisc_segment * peerdisc_find(const char *id)
Find PeerDist discovery segment.
Definition: peerdisc.c:365
void * intf_object(struct interface *intf)
Get pointer to object containing object interface.
Definition: interface.c:159
A doubly-linked list entry (or list head)
Definition: list.h:18
Data transfer interfaces.
A reference counter.
Definition: refcnt.h:26
A timer.
Definition: timer.h:28
const char * name
Name.
Definition: settings.h:28
struct sockaddr_tcpip st
Definition: syslog.c:56
void peerdisc_stat(struct interface *intf, struct peerdisc_peer *peer, struct list_head *peers)
Report peer discovery statistics.
Definition: peerdisc.c:100
#define list_empty(list)
Test whether a list is empty.
Definition: list.h:136
static size_t base16_encoded_len(size_t raw_len)
Calculate length of base16-encoded data.
Definition: base16.h:21
static int toupper(int character)
Convert character to upper case.
Definition: ctype.h:109
struct interface xfer
Data transfer interface.
Definition: peerdisc.h:26
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
#define ENOMEM
Not enough space.
Definition: errno.h:534
void(* discovered)(struct peerdisc_client *peerdisc)
New peers have been discovered.
Definition: peerdisc.h:94
char * peerdist_discovery_request(const char *uuid, const char *id)
Construct discovery request.
Definition: pccrd.c:106
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int netdev_is_open(struct net_device *netdev)
Check whether or not network device is open.
Definition: netdevice.h:664
struct sockaddr sa
Definition: peerdisc.h:29
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
A PeerDist discovery client.
Definition: peerdisc.h:79
An object interface.
Definition: interface.h:124
int peerdisc_open(struct peerdisc_client *peerdisc, const void *id, size_t len)
Open PeerDist discovery client.
Definition: peerdisc.c:559
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:420
uint8_t uuid[16]
UUID.
Definition: smbios.h:22
#define DBGC_HDA(...)
Definition: compiler.h:506
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition: list.h:93
Peer Content Caching and Retrieval: Discovery Protocol [MS-PCCRD].
A PeerDist discovery reply.
Definition: pccrd.h:30
static struct net_device * netdev
Definition: gdbudp.c:52
struct sockaddr sa
Definition: syslog.c:55
Transport-network layer interface.
char * strcpy(char *dest, const char *src)
Copy string.
Definition: string.c:326
int fetch_string_setting_copy(struct settings *settings, const struct setting *setting, char **data)
Fetch value of string setting.
Definition: settings.c:873
char * locations
List of peer locations.
Definition: pccrd.h:40
static void * dest
Definition: strings.h:176
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition: list.h:447
uint8_t id
Request identifier.
Definition: ena.h:12
static char * peerhost
Hosted cache server.
Definition: peerdisc.c:80
int meta(WINDOW *, bool)
struct settings_applicator peerdisc_applicator __settings_applicator
PeerDist discovery settings applicator.
Definition: peerdisc.c:663
Configuration settings.
Generalized socket address structure.
Definition: socket.h:96
An object interface descriptor.
Definition: interface.h:55
uint8_t id_string[24]
ID string.
Definition: eltorito.h:24
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
char location[0]
Peer location.
Definition: peerdisc.h:75
#define for_each_netdev(netdev)
Iterate over all network devices.
Definition: netdevice.h:538
#define ref_get(refcnt)
Get additional reference to object.
Definition: refcnt.h:92
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:155
#define PEERDISC_REPEAT_TIMEOUT
Time between repeated discovery attempts.
Definition: peerdisc.c:57
#define PEERDIST_DISCOVERY_IPV6
PeerDist discovery IPv6 address (ff02::c)
Definition: pccrd.h:20
static int peerdisc_socket_rx(struct peerdisc_socket *socket, struct io_buffer *iobuf, struct xfer_metadata *meta __unused)
Handle received PeerDist discovery reply.
Definition: peerdisc.c:224
uint8_t * tmp
Definition: entropy.h:156
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:32
char * strdup(const char *src)
Duplicate string.
Definition: string.c:380
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:385
A network device.
Definition: netdevice.h:352
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:30
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:193
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
Data transfer interface opening.
static void peerdisc_expired(struct retry_timer *timer, int over __unused)
Handle discovery timer expiry.
Definition: peerdisc.c:432
char * ids
List of segment ID strings.
Definition: pccrd.h:35
unsigned int uint32_t
Definition: stdint.h:12
const char * uuid_ntoa(const union uuid *uuid)
Convert UUID to printable string.
Definition: uuid.c:43
struct peerdisc_segment * segment
Discovery segment.
Definition: peerdisc.h:81
static struct interface_descriptor peerdisc_socket_desc
PeerDist discovery socket interface descriptor.
Definition: peerdisc.c:302
static struct peerdisc_segment * peerdisc_create(const char *id)
Create PeerDist discovery segment.
Definition: peerdisc.c:450
A setting.
Definition: settings.h:23
union peerdisc_socket::@560 address
Socket address.
Network device management.
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition: retry.c:64
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
static LIST_HEAD(peerdisc_segments)
List of discovery segments.
static uint16_t struct vmbus_xfer_pages_operations * op
Definition: netvsc.h:327
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition: list.h:45
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:80
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition: retry.c:117
struct list_head list
List of segments.
Definition: peerdisc.h:46
#define PEERDISC_REPEAT_COUNT
Number of repeated discovery attempts.
Definition: peerdisc.c:54
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:362
uint32_t len
Length.
Definition: ena.h:14
unsigned int index
Index of this network device.
Definition: netdevice.h:360
#define peerdisc_stat_TYPE(object_type)
Definition: peerdisc.h:114
#define DBGC2(...)
Definition: compiler.h:522
static void peerdisc_destroy(struct peerdisc_segment *segment)
Destroy PeerDist discovery segment.
Definition: peerdisc.c:531
int strcmp(const char *first, const char *second)
Compare strings.
Definition: string.c:173
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void * data
Start of data.
Definition: iobuf.h:48
void intf_put(struct interface *intf)
Decrement reference count on an object interface.
Definition: interface.c:149
u8 request[0]
List of IEs requested.
Definition: ieee80211.h:16
static int peerdisc_discovered(struct peerdisc_segment *segment, const char *location)
Add discovered PeerDist peer.
Definition: peerdisc.c:384
struct peerdisc_socket peerdisc_socket_ipv4 __peerdisc_socket
PeerDist discovery IPv4 socket.
Definition: peerdisc.c:306
int(* apply)(void)
Apply updated settings.
Definition: settings.h:256
static int apply_peerdisc_settings(void)
Apply PeerDist discovery settings.
Definition: peerdisc.c:646
struct peerdisc_client_operations * op
Operations.
Definition: peerdisc.h:85
Fault injection.
const char * name
Name.
Definition: peerdisc.h:24
#define PEERDISC_DEFAULT_TIMEOUT_SECS
Default discovery timeout (in seconds)
Definition: peerdisc.c:60
struct list_head list
List of peers.
Definition: peerdisc.h:73
#define PEERDIST_DISCOVERY_PORT
PeerDist discovery port.
Definition: pccrd.h:13
#define for_each_table_entry_continue_reverse(pointer, table)
Iterate through all remaining entries within a linker table in reverse order.
Definition: tables.h:469
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
String functions.
static int peerdisc_socket_open(void)
Open all PeerDist discovery sockets.
Definition: peerdisc.c:128
#define htons(value)
Definition: byteswap.h:135
#define intf_get_dest_op(intf, type, dest)
Get object interface destination and operation method.
Definition: interface.h:231
unsigned long int dword
Definition: smc9000.h:40
#define AF_INET
IPv4 Internet addresses.
Definition: socket.h:63
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:106
void * memset(void *dest, int character, size_t len) __nonnull
void peerdisc_close(struct peerdisc_client *peerdisc)
Close PeerDist discovery client.
Definition: peerdisc.c:597
unsigned int peerdisc_timeout_secs
Recommended discovery timeout (in seconds)
Definition: peerdisc.c:74
Base16 encoding.
A persistent I/O buffer.
Definition: iobuf.h:33
A PeerDist discovery peer.
Definition: peerdisc.h:71