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)
 
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 64 of file pccrd.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ 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 106 of file pccrd.c.

106  {
107  char *request;
108  int len;
109 
110  /* Construct request */
112  if ( len < 0 )
113  return NULL;
114 
115  return request;
116 }
#define PEERDIST_DISCOVERY_REQUEST
Discovery request format.
Definition: pccrd.c:64
A universally unique ID.
Definition: uuid.h:15
int asprintf(char **strp, const char *fmt,...)
Write a formatted string to newly allocated memory.
Definition: asprintf.c:41
uint32_t len
Length.
Definition: ena.h:14
u8 request[0]
List of IEs requested.
Definition: ieee80211.h:16
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

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 126 of file pccrd.c.

127  {
128  size_t tag_len = strlen ( tag );
129 
130  /* Search, allowing for the fact that the reply data is not
131  * cleanly NUL-terminated and may contain embedded NULs due to
132  * earlier parsing.
133  */
134  for ( ; len >= tag_len ; data++, len-- ) {
135  if ( strncmp ( data, tag, tag_len ) == 0 )
136  return data;
137  }
138  return NULL;
139 }
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
Definition: string.c:170
size_t strlen(const char *src)
Get length of string.
Definition: string.c:213
uint32_t len
Length.
Definition: ena.h:14
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
uint64_t tag
Identity tag.
Definition: edd.h:30
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

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 157 of file pccrd.c.

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

References assert(), c, 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 216 of file pccrd.c.

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

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().