iPXE
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.

Functions

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

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.

65#define PEERDIST_DISCOVERY_REQUEST \
66 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \
67 "<soap:Envelope " \
68 "xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" " \
69 "xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" " \
70 "xmlns:wsd=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\" " \
71 "xmlns:PeerDist=\"http://schemas.microsoft.com/p2p/" \
72 "2007/09/PeerDistributionDiscovery\">" \
73 "<soap:Header>" \
74 "<wsa:To>" \
75 "urn:schemas-xmlsoap-org:ws:2005:04:discovery" \
76 "</wsa:To>" \
77 "<wsa:Action>" \
78 "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe" \
79 "</wsa:Action>" \
80 "<wsa:MessageID>" \
81 "urn:uuid:%s" \
82 "</wsa:MessageID>" \
83 "</soap:Header>" \
84 "<soap:Body>" \
85 "<wsd:Probe>" \
86 "<wsd:Types>" \
87 "PeerDist:PeerDistData" \
88 "</wsd:Types>" \
89 "<wsd:Scopes MatchBy=\"http://schemas.xmlsoap.org/ws/" \
90 "2005/04/discovery/strcmp0\">" \
91 "%s" \
92 "</wsd:Scopes>" \
93 "</wsd:Probe>" \
94 "</soap:Body>" \
95 "</soap:Envelope>"

Referenced by peerdist_discovery_request().

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 NULL
NULL pointer (VOID *)
Definition Base.h:322
int asprintf(char **strp, const char *fmt,...)
Write a formatted string to newly allocated memory.
Definition asprintf.c:42
ring len
Length.
Definition dwmac.h:226
u8 request[0]
List of IEs requested.
Definition ieee80211.h:2
#define PEERDIST_DISCOVERY_REQUEST
Discovery request format.
Definition pccrd.c:65
A universally unique ID.
Definition uuid.h:16

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

Referenced by peerdisc_socket_tx().

◆ peerdist_discovery_reply_tag()

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}
uint64_t tag
Identity tag.
Definition edd.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
Definition string.c:187
size_t strlen(const char *src)
Get length of string.
Definition string.c:244

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

Referenced by peerdist_discovery_reply_values().

◆ peerdist_discovery_reply_values()

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}
__be32 in[4]
Definition CIB_PRM.h:7
__be32 out[4]
Definition CIB_PRM.h:8
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
const char * name
Definition ath9k_hw.c:1986
int isspace(int character)
Check to see if character is a space.
Definition ctype.c:42
uint32_t start
Starting offset.
Definition netvsc.h:1
uint32_t end
Ending offset.
Definition netvsc.h:7
static char * peerdist_discovery_reply_tag(char *data, size_t len, const char *tag)
Locate discovery reply tag.
Definition pccrd.c:127
int open(const char *uri_string)
Open file.
Definition posix_io.c:176
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383
static struct evtchn_close * close
Definition xenevent.h:24

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 */
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,
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}
#define max(x, y)
Definition ath.h:41
#define DBGC(...)
Definition compiler.h:505
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define ENOENT
No such file or directory.
Definition errno.h:515
#define EPROTO
Protocol error.
Definition errno.h:625
static char * peerdist_discovery_reply_values(char *data, size_t len, const char *name)
Locate discovery reply values.
Definition pccrd.c:158
char hex[8]
Count (as an eight-digit hex value)
Definition pccrd.h:1
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
char * strcpy(char *dest, const char *src)
Copy string.
Definition string.c:347
A PeerDist discovery reply block count.
Definition pccrd.h:25
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
char * locations
List of peer locations.
Definition pccrd.h:41

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