iPXE
Macros | Functions
pccrd.c File Reference

Peer Content Caching and Retrieval: Discovery Protocol [MS-PCCRD]. More...

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/pccrd.h>

Go to the source code of this file.

Macros

#define PEERDIST_DISCOVERY_REQUEST
 Discovery request format. More...
 

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
 FILE_SECBOOT (PERMITTED)
 
char * peerdist_discovery_request (const char *uuid, const char *id)
 Construct discovery request. More...
 
static char * peerdist_discovery_reply_tag (char *data, size_t len, const char *tag)
 Locate discovery reply tag. More...
 
static char * peerdist_discovery_reply_values (char *data, size_t len, const char *name)
 Locate discovery reply values. More...
 
int peerdist_discovery_reply (char *data, size_t len, struct peerdist_discovery_reply *reply)
 Parse discovery reply. More...
 

Detailed Description

Peer Content Caching and Retrieval: Discovery Protocol [MS-PCCRD].

This protocol manages to ingeniously combine the excessive verbosity of XML with a paucity of actual information. For example: even in version 2.0 of the protocol it is still not possible to discover which peers hold a specific block within a given segment.

For added bonus points, version 1.0 of the protocol is specified to use a case-sensitive string comparison (for SHA2 digest values) but nothing specifies whether the strings in question should be in upper or lower case. There are example strings given in the specification, but the author skilfully manages to leave the issue unresolved by using the somewhat implausible digest value of "0200000000000000000000000000000000000000000000000000000000000000".

Just in case you were thinking that the silver lining of the choice to use an XML-based protocol would be the ability to generate and process messages with standard tools, version 2.0 of the protocol places most of the critical information inside a Base64-encoded custom binary data structure. Within an XML element, naturally.

I hereby announce this specification to be the 2015 winner of the prestigious "UEFI HII API" award for incompetent design.

Definition in file pccrd.c.

Macro Definition Documentation

◆ PEERDIST_DISCOVERY_REQUEST

#define PEERDIST_DISCOVERY_REQUEST
Value:
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" \
"<soap:Envelope " \
"xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" " \
"xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" " \
"xmlns:wsd=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\" " \
"xmlns:PeerDist=\"http://schemas.microsoft.com/p2p/" \
"2007/09/PeerDistributionDiscovery\">" \
"<soap:Header>" \
"<wsa:To>" \
"urn:schemas-xmlsoap-org:ws:2005:04:discovery" \
"</wsa:To>" \
"<wsa:Action>" \
"http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe" \
"</wsa:Action>" \
"<wsa:MessageID>" \
"urn:uuid:%s" \
"</wsa:MessageID>" \
"</soap:Header>" \
"<soap:Body>" \
"<wsd:Probe>" \
"<wsd:Types>" \
"PeerDist:PeerDistData" \
"</wsd:Types>" \
"<wsd:Scopes MatchBy=\"http://schemas.xmlsoap.org/ws/" \
"2005/04/discovery/strcmp0\">" \
"%s" \
"</wsd:Scopes>" \
"</wsd:Probe>" \
"</soap:Body>" \
"</soap:Envelope>"

Discovery request format.

Definition at line 65 of file pccrd.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED  )

◆ peerdist_discovery_request()

char* peerdist_discovery_request ( const char *  uuid,
const char *  id 
)

Construct discovery request.

Parameters
uuidMessage UUID string
idSegment identifier string
Return values
requestDiscovery request, or NULL on failure

The request is dynamically allocated; the caller must eventually free() the request.

Definition at line 107 of file pccrd.c.

107  {
108  char *request;
109  int len;
110 
111  /* Construct request */
113  if ( len < 0 )
114  return NULL;
115 
116  return request;
117 }
#define PEERDIST_DISCOVERY_REQUEST
Discovery request format.
Definition: pccrd.c:65
A universally unique ID.
Definition: uuid.h:16
ring len
Length.
Definition: dwmac.h:231
int asprintf(char **strp, const char *fmt,...)
Write a formatted string to newly allocated memory.
Definition: asprintf.c:42
u8 request[0]
List of IEs requested.
Definition: ieee80211.h:16
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322

References asprintf(), len, NULL, PEERDIST_DISCOVERY_REQUEST, and request.

Referenced by peerdisc_socket_tx().

◆ peerdist_discovery_reply_tag()

static char* peerdist_discovery_reply_tag ( char *  data,
size_t  len,
const char *  tag 
)
static

Locate discovery reply tag.

Parameters
dataReply data (not NUL-terminated)
lenLength of reply data
tagXML tag
Return values
foundFound tag (or NULL if not found)

Definition at line 127 of file pccrd.c.

128  {
129  size_t tag_len = strlen ( tag );
130 
131  /* Search, allowing for the fact that the reply data is not
132  * cleanly NUL-terminated and may contain embedded NULs due to
133  * earlier parsing.
134  */
135  for ( ; len >= tag_len ; data++, len-- ) {
136  if ( strncmp ( data, tag, tag_len ) == 0 )
137  return data;
138  }
139  return NULL;
140 }
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
Definition: string.c:187
ring len
Length.
Definition: dwmac.h:231
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
uint8_t data[48]
Additional event data.
Definition: ena.h:22
uint64_t tag
Identity tag.
Definition: edd.h:31
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322

References data, len, NULL, strlen(), strncmp(), and tag.

Referenced by peerdist_discovery_reply_values().

◆ peerdist_discovery_reply_values()

static char* peerdist_discovery_reply_values ( char *  data,
size_t  len,
const char *  name 
)
static

Locate discovery reply values.

Parameters
dataReply data (not NUL-terminated, will be modified)
lenLength of reply data
nameXML tag name
Return values
valuesTag values (or NULL if not found)

The reply data is modified by adding NULs and moving characters as needed to produce a NUL-separated list of values, terminated with a zero-length string.

This is not supposed to be a full XML parser; it's supposed to include just enough functionality to allow PeerDist discovery to work with existing implementations.

Definition at line 158 of file pccrd.c.

159  {
160  char buf[ 2 /* "</" */ + strlen ( name ) + 1 /* ">" */ + 1 /* NUL */ ];
161  char *open;
162  char *close;
163  char *start;
164  char *end;
165  char *in;
166  char *out;
167  char c;
168 
169  /* Locate opening tag */
170  snprintf ( buf, sizeof ( buf ), "<%s>", name );
172  if ( ! open )
173  return NULL;
174  start = ( open + strlen ( buf ) );
175  len -= ( start - data );
176  data = start;
177 
178  /* Locate closing tag */
179  snprintf ( buf, sizeof ( buf ), "</%s>", name );
181  if ( ! close )
182  return NULL;
183  assert ( close >= open );
184  end = close;
185 
186  /* Strip initial whitespace, convert other whitespace
187  * sequences to single NULs, add terminating pair of NULs.
188  * This will probably overwrite part of the closing tag.
189  */
190  for ( in = start, out = start ; in < end ; in++ ) {
191  c = *in;
192  if ( isspace ( c ) ) {
193  if ( ( out > start ) && ( out[-1] != '\0' ) )
194  *(out++) = '\0';
195  } else {
196  *(out++) = c;
197  }
198  }
199  *(out++) = '\0';
200  *(out++) = '\0';
201  assert ( out < ( close + strlen ( buf ) ) );
202 
203  return start;
204 }
const char * name
Definition: ath9k_hw.c:1986
__be32 in[4]
Definition: CIB_PRM.h:35
__be32 out[4]
Definition: CIB_PRM.h:36
uint32_t start
Starting offset.
Definition: netvsc.h:12
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
ring len
Length.
Definition: dwmac.h:231
int isspace(int character)
Check to see if character is a space.
Definition: ctype.c:42
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
int open(const char *uri_string)
Open file.
Definition: posix_io.c:176
uint32_t end
Ending offset.
Definition: netvsc.h:18
uint8_t data[48]
Additional event data.
Definition: ena.h:22
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:383
static char * peerdist_discovery_reply_tag(char *data, size_t len, const char *tag)
Locate discovery reply tag.
Definition: pccrd.c:127
static struct evtchn_close * close
Definition: xenevent.h:24
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322

References assert(), close, data, end, in, isspace(), len, name, NULL, open(), out, peerdist_discovery_reply_tag(), snprintf(), start, and strlen().

Referenced by peerdist_discovery_reply().

◆ peerdist_discovery_reply()

int peerdist_discovery_reply ( char *  data,
size_t  len,
struct peerdist_discovery_reply reply 
)

Parse discovery reply.

Parameters
dataReply data (not NUL-terminated, will be modified)
lenLength of reply data
replyDiscovery reply to fill in
Return values
rcReturn status code

The discovery reply includes pointers to strings within the modified reply data.

Definition at line 217 of file pccrd.c.

218  {
219  static const struct peerdist_discovery_block_count zcount = {
220  .hex = "00000000",
221  };
223  unsigned int max;
224  unsigned int i;
225  char *scopes;
226  char *xaddrs;
227  char *blockcount;
228  char *in;
229  char *out;
230  size_t skip;
231 
232  /* Find <wsd:Scopes> tag */
233  scopes = peerdist_discovery_reply_values ( data, len, "wsd:Scopes" );
234  if ( ! scopes ) {
235  DBGC ( reply, "PCCRD %p missing <wsd:Scopes> tag\n", reply );
236  return -ENOENT;
237  }
238 
239  /* Find <wsd:XAddrs> tag */
240  xaddrs = peerdist_discovery_reply_values ( data, len, "wsd:XAddrs" );
241  if ( ! xaddrs ) {
242  DBGC ( reply, "PCCRD %p missing <wsd:XAddrs> tag\n", reply );
243  return -ENOENT;
244  }
245 
246  /* Find <PeerDist:BlockCount> tag */
247  blockcount = peerdist_discovery_reply_values ( data, len,
248  "PeerDist:BlockCount" );
249  if ( ! blockcount ) {
250  DBGC ( reply, "PCCRD %p missing <PeerDist:BlockCount> tag\n",
251  reply );
252  return -ENOENT;
253  }
254 
255  /* Determine maximum number of segments (according to number
256  * of entries in the block count list).
257  */
258  max = ( strlen ( blockcount ) / sizeof ( *count ) );
259  count = container_of ( blockcount,
260  struct peerdist_discovery_block_count, hex[0] );
261 
262  /* Eliminate any segments with a zero block count */
263  for ( i = 0, in = scopes, out = scopes ; *in ; i++, in += skip ) {
264 
265  /* Fail if we have overrun the maximum number of segments */
266  if ( i >= max ) {
267  DBGC ( reply, "PCCRD %p too many segment IDs\n",
268  reply );
269  return -EPROTO;
270  }
271 
272  /* Delete segment if block count is zero */
273  skip = ( strlen ( in ) + 1 /* NUL */ );
274  if ( memcmp ( count[i].hex, zcount.hex,
275  sizeof ( zcount.hex ) ) == 0 )
276  continue;
277  strcpy ( out, in );
278  out += skip;
279  }
280  out[0] = '\0'; /* Ensure list is terminated with a zero-length string */
281 
282  /* Fill in discovery reply */
283  reply->ids = scopes;
284  reply->locations = xaddrs;
285 
286  return 0;
287 }
A PeerDist discovery reply block count.
Definition: pccrd.h:25
#define max(x, y)
Definition: ath.h:41
__be32 in[4]
Definition: CIB_PRM.h:35
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:515
char hex[8]
Count (as an eight-digit hex value)
Definition: pccrd.h:13
__be32 out[4]
Definition: CIB_PRM.h:36
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
ring len
Length.
Definition: dwmac.h:231
static unsigned int count
Number of entries.
Definition: dwmac.h:225
char * strcpy(char *dest, const char *src)
Copy string.
Definition: string.c:347
char * locations
List of peer locations.
Definition: pccrd.h:41
#define EPROTO
Protocol error.
Definition: errno.h:625
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
char hex[8]
Count (as an eight-digit hex value)
Definition: pccrd.h:27
char * ids
List of segment ID strings.
Definition: pccrd.h:36
uint8_t data[48]
Additional event data.
Definition: ena.h:22
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:115
static char * peerdist_discovery_reply_values(char *data, size_t len, const char *name)
Locate discovery reply values.
Definition: pccrd.c:158

References container_of, count, data, DBGC, ENOENT, EPROTO, hex, peerdist_discovery_block_count::hex, peerdist_discovery_reply::ids, in, len, peerdist_discovery_reply::locations, max, memcmp(), out, peerdist_discovery_reply_values(), strcpy(), and strlen().