mirror of
https://github.com/moparisthebest/xeps
synced 2024-11-24 18:22:24 -05:00
0.13
git-svn-id: file:///home/ksmith/gitmigration/svn/xmpp/trunk@1495 4b5297f7-1745-476d-ba37-a9c6900126ab
This commit is contained in:
parent
f5517dcd64
commit
0918cad5f2
240
xep-0176.xml
240
xep-0176.xml
@ -27,6 +27,12 @@
|
||||
&stpeter;
|
||||
&hildjj;
|
||||
&seanegan;
|
||||
<revision>
|
||||
<version>0.13</version>
|
||||
<date>2007-12-28</date>
|
||||
<initials>psa</initials>
|
||||
<remark><p>Added further details about connectivity checks; defined raddr and rport attributes for complete mapping to SDP.</p></remark>
|
||||
</revision>
|
||||
<revision>
|
||||
<version>0.12</version>
|
||||
<date>2007-11-28</date>
|
||||
@ -135,6 +141,49 @@
|
||||
</ol>
|
||||
</section1>
|
||||
<section1 topic='Protocol Description' anchor='protocol'>
|
||||
<section2 topic='Flow' anchor='protocol-flow'>
|
||||
<p>The overall protocol flow for negotiation of the Jingle ICE-UDP Transport Method is as follows (note: many of these events happen simultaneously, not in sequence). The examples follow the scenario described in Section 17 of &icecore;, except that we substitute the Shakespearean characters "Romeo" and "Juliet" for the generic entities "L" and "R".</p>
|
||||
<code><![CDATA[
|
||||
INITIATOR RESPONDER
|
||||
| |
|
||||
| Jingle session-initiate |
|
||||
|----------------------------------->|
|
||||
| Jingle ack (XMPP IQ-result) |
|
||||
|<-----------------------------------|
|
||||
| Jingle transport-info (candidate) |
|
||||
|----------------------------------->|
|
||||
| Jingle ack (XMPP IQ-result) |
|
||||
|<-----------------------------------|
|
||||
| Jingle transport-info (candidate) |
|
||||
|----------------------------------->|
|
||||
| Jingle ack (XMPP IQ-result) |
|
||||
|<-----------------------------------|
|
||||
| Jingle transport-info (candidate) |
|
||||
|<-----------------------------------|
|
||||
| Jingle ack (XMPP IQ-result) |
|
||||
|----------------------------------->|
|
||||
| STUN Binding Request |
|
||||
| (dropped) |
|
||||
| x---------------------------------|
|
||||
| STUN Binding Request |
|
||||
|----------------------------------->|
|
||||
| STUN Binding Result |
|
||||
|<-----------------------------------|
|
||||
| STUN Binding Request |
|
||||
|<-----------------------------------|
|
||||
| STUN Binding Result |
|
||||
|----------------------------------->|
|
||||
| Jingle content-accept |
|
||||
|<-----------------------------------|
|
||||
| Jingle ack (XMPP IQ-result) |
|
||||
|----------------------------------->|
|
||||
| Jingle session-accept |
|
||||
|<-----------------------------------|
|
||||
| Jingle ack (XMPP IQ-result) |
|
||||
|----------------------------------->|
|
||||
| |
|
||||
]]></code>
|
||||
</section2>
|
||||
<section2 topic='Transport Initiation' anchor='protocol-initiate'>
|
||||
<p>In order for the initiator in a Jingle exchange to start the negotiation, it MUST send a Jingle "session-initiate" stanza as described in <cite>XEP-0166</cite>. A content type MUST include one transport method. If the initiator wishes to negotiate the ice-udp transport method for an application format, it MUST include an empty &TRANSPORT; child element qualified by the 'http://www.xmpp.org/extensions/xep-0176.html#ns' namespace &NSNOTE;.</p>
|
||||
<example caption="Initiation"><![CDATA[
|
||||
@ -165,11 +214,11 @@
|
||||
type='result'/>
|
||||
]]></example>
|
||||
</section2>
|
||||
<section2 topic='ICE Negotiation' anchor='protocol-negotiate'>
|
||||
<section2 topic='Candidate Negotiation' anchor='protocol-candidates'>
|
||||
<p>Once the responder acknowledges receipt of the session initiation request as shown above, both initiator and responder MUST immediately negotiate connectivity over the ICE transport by exchanging XML-formatted candidate transports for the channel. This negotiation proceeds immediately in order to maximize the possibility that media can be exchanged as quickly as possible. <note>Concurrent with negotiation of the ICE candidates, it is possible for the initiator and responder to negotiate which content types the session will include, which transport methods will be tried for each content type, etc. Those negotiation flows are shown in other specifications, such as <cite>XEP-0166</cite>. This document specifies only negotiation of the ICE transport method.</note></p>
|
||||
<p>Note: In order to expedite session establishment, the initiator MAY send transport candidates immediately after sending the "session-initiate" message and before receiving acknowledgement from the responder (i.e., the initiator MUST consider the session to be live even before receiving acknowledgement). Given in-order delivery, the responder should receive such "transport-info" messages after receiving the "session-initiate" message; if not, it is appropriate for the responder to return <unknown-session/> errors since it according to its state machine the session does not exist. If either party receives an <unknown-session/> from the other party, it MUST terminate the negotiation and the session.</p>
|
||||
<p>The candidate syntax and negotiation flow are described below.</p>
|
||||
<section3 topic='Syntax of Candidate Element' anchor='protocol-negotiate-candidate'>
|
||||
<section3 topic='Syntax of Candidate Element' anchor='protocol-candidates-syntax'>
|
||||
<p>The following is an example of the candidate format:</p>
|
||||
<example caption="A candidate transport"><![CDATA[
|
||||
<candidate component='1'
|
||||
@ -178,7 +227,7 @@
|
||||
ip='10.0.1.1'
|
||||
network='0'
|
||||
port='8998'
|
||||
priority='2114978302'
|
||||
priority='2130706431'
|
||||
protocol='udp'
|
||||
pwd='asd88fgpdd777uzjYhagZg'
|
||||
type='host'
|
||||
@ -214,7 +263,7 @@
|
||||
<td>ip</td>
|
||||
<td>The Internet Protocol (IP) address for the candidate transport mechanism; this may be either an IPv4 address or an IPv6 address.</td>
|
||||
<td>IP Address value in a=candidate line</td>
|
||||
<td>10.0.1.1</td>
|
||||
<td>192.0.2.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>network</td>
|
||||
@ -226,7 +275,7 @@
|
||||
<td>port</td>
|
||||
<td>The port at the candidate IP address.</td>
|
||||
<td>Port value in a=candidate line</td>
|
||||
<td>8998</td>
|
||||
<td>45664</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>priority</td>
|
||||
@ -234,7 +283,7 @@
|
||||
<note>In accordance with the rules specified in Section 4.1.1 of &icecore;, the priority values shown in the examples within this document have been calculated as follows. The "type preference" for host candidates is stipulated to be "126" and for server reflexive candidates "100". The "local preference" for network 0 is stipulated to be "4096", for network 1 "2048", and for network 2 "1024".</note>
|
||||
</td>
|
||||
<td>Priority value in a=candidate line</td>
|
||||
<td>1678246398</td>
|
||||
<td>2130706431</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>protocol</td>
|
||||
@ -248,6 +297,18 @@
|
||||
<td>a=ice-pwd line</td>
|
||||
<td>asd88fgpdd777uzjYhagZg</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>raddr</td>
|
||||
<td>A related address as defined in &icecore;.</td>
|
||||
<td>Raddr value in a=candidate line</td>
|
||||
<td>10.0.1.1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>rport</td>
|
||||
<td>A related port as defined in &icecore;.</td>
|
||||
<td>Rport value in a=candidate line</td>
|
||||
<td>8998</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>type</td>
|
||||
<td>A Candidate Type as defined in &icecore;. The allowable values are "host" for host candidates, "prflx" for peer reflexive candidates, "relay" for relayed candidates, and "srflx" for server reflexive candidates.</td>
|
||||
@ -262,13 +323,12 @@
|
||||
</tr>
|
||||
</table>
|
||||
</section3>
|
||||
<section3 topic='Negotiation Flow' anchor='protocol-negotiate-flow'>
|
||||
<p>The first step in negotiating connectivity is for both parties to immediately begin sending transport candidates methods to the other client. <note>The fact that both parties send candidates means that Jingle requires each party to be a full implementation of ICE, not a "lite" implementation as specified in &icecore;.</note> These candidates SHOULD be gathered by following the procedure specified in Section 4.1.1 of &icecore; and prioritized by following the procedure specified in Section 4.1.2 of &icecore;. Each candidate MUST be sent in a &JINGLE; element with an action of "transport-info".</p>
|
||||
<section3 topic='Exchange of Candidates' anchor='protocol-candidates-exchange'>
|
||||
<p>The first step in negotiating connectivity is for each party to immediately begin sending transport candidates to the other party. <note>The fact that both parties send candidates means that Jingle requires each party to be a full implementation of ICE, not a lite implementation as specified in &icecore;.</note> These candidates SHOULD be gathered by following the procedure specified in Section 4.1.1 of &icecore; and prioritized by following the procedure specified in Section 4.1.2 of &icecore;. Each candidate MUST be sent in a &JINGLE; element with an action of "transport-info".</p>
|
||||
<p>If the responder receives and can successfully process a given candidate, it returns an IQ-result (if not, for example because the candidate data is improperly formatted, it returns an error). Note: The responder is only indicating receipt of the candidate, not telling the initiator that the candidate will be used.</p>
|
||||
<p>The initiator keeps sending candidates, one after the other (without stopping to receive an acknowledgement of receipt from the responder for each candidate) until it has exhausted its supply of possible or desirable candidate transports. (Because certain candidates may be more "expensive" in terms of bandwidth or processing power, the initiator may not want to advertise their existence unless necessary.) For each candidate, the responder acknowledges receipt.</p>
|
||||
<p>At the same time (i.e., immediately after acknowledging receipt of the session-initiate request, not waiting for the initiator to begin or finish sending candidates), the responder also begins sending potential candidates, in order of desirability according to the responder. As above, the initiator acknowledges receipt of the candidates.</p>
|
||||
<p>As the initiator and responder receive candidates, they probe the various candidate transports for connectivity. In performing these connectivity checks, a client SHOULD follow the procedure specified in Section 7 of &icecore;.</p>
|
||||
<example caption="Initiator sends a candidate"><![CDATA[
|
||||
<example caption="Initiator sends some candidates"><![CDATA[
|
||||
<iq from='romeo@montague.net/orchard'
|
||||
id='info1'
|
||||
to='juliet@capulet.com/balcony'
|
||||
@ -285,7 +345,7 @@
|
||||
ip='10.0.1.1'
|
||||
network='1'
|
||||
port='8998'
|
||||
priority='2114453759'
|
||||
priority='2130706431'
|
||||
protocol='udp'
|
||||
pwd='asd88fgpdd777uzjYhagZg'
|
||||
type='host'
|
||||
@ -294,8 +354,7 @@
|
||||
</content>
|
||||
</jingle>
|
||||
</iq>
|
||||
]]></example>
|
||||
<example caption="Initiator sends a second candidate"><![CDATA[
|
||||
|
||||
<iq from='romeo@montague.net/orchard'
|
||||
id='info2'
|
||||
to='juliet@capulet.com/balcony'
|
||||
@ -307,14 +366,16 @@
|
||||
<content creator='initiator' name='this-is-the-audio-content' profile='RTP/AVP'>
|
||||
<transport xmlns='http://www.xmpp.org/extensions/xep-0176.html#ns'>
|
||||
<candidate component='1'
|
||||
foundation='1'
|
||||
foundation='2'
|
||||
generation='0'
|
||||
ip='192.0.2.3'
|
||||
network='1'
|
||||
port='45664'
|
||||
priority='1678246398'
|
||||
priority='1694498815'
|
||||
protocol='udp'
|
||||
pwd='asd88fgpdd777uzjYhagZg'
|
||||
raddr='10.0.1.1'
|
||||
rport='8998'
|
||||
type='srflx'
|
||||
ufrag='8hhy'/>
|
||||
</transport>
|
||||
@ -322,34 +383,7 @@
|
||||
</jingle>
|
||||
</iq>
|
||||
]]></example>
|
||||
<example caption="Initiator sends a third candidate"><![CDATA[
|
||||
<iq from='romeo@montague.net/orchard'
|
||||
id='info3'
|
||||
to='juliet@capulet.com/balcony'
|
||||
type='set'>
|
||||
<jingle xmlns='http://www.xmpp.org/extensions/xep-0166.html#ns'
|
||||
action='transport-info'
|
||||
initiator='romeo@montague.net/orchard'
|
||||
sid='a73sjjvkla37jfea'>
|
||||
<content creator='initiator' name='this-is-the-audio-content' profile='RTP/AVP'>
|
||||
<transport xmlns='http://www.xmpp.org/extensions/xep-0176.html#ns'>
|
||||
<candidate component='1'
|
||||
foundation='1'
|
||||
generation='0'
|
||||
ip='208.245.212.67'
|
||||
network='2'
|
||||
port='53267'
|
||||
priority='1677984254'
|
||||
protocol='udp'
|
||||
pwd='asd88fgpdd777uzjYhagZg'
|
||||
type='srflx'
|
||||
ufrag='8hhy'/>
|
||||
</transport>
|
||||
</content>
|
||||
</jingle>
|
||||
</iq>
|
||||
]]></example>
|
||||
<p>For each candidate received, the other party MUST acknowledge receipt or return an error:</p>
|
||||
<p>For each candidate received, the other party (in this case the responder) MUST acknowledge receipt or return an error.</p>
|
||||
<example caption="Responder acknowledges receipt"><![CDATA[
|
||||
<iq from='juliet@capulet.com/balcony'
|
||||
id='info1'
|
||||
@ -360,16 +394,110 @@
|
||||
id='info2'
|
||||
to='romeo@montague.net/orchard'
|
||||
type='result'/>
|
||||
|
||||
<iq from='juliet@capulet.com/balcony'
|
||||
]]></example>
|
||||
<p>At the same time (i.e., immediately after acknowledging the session-initation request, not waiting for the initiator to begin or finish sending candidates), the responder also sends candidates that may work for it.</p>
|
||||
<example caption="Responder sends candidates"><![CDATA[
|
||||
<iq from='juliet@capulet.lit/balcony'
|
||||
to='romeo@montague.lit/orchard'
|
||||
id='info3'
|
||||
to='romeo@montague.net/orchard'
|
||||
type='set'>
|
||||
<jingle xmlns='http://www.xmpp.org/extensions/xep-0166.html#ns'
|
||||
action='transport-info'
|
||||
initiator='romeo@montague.lit/orchard'
|
||||
sid='a73sjjvkla37jfea'>
|
||||
<content creator='initiator' name='this-is-the-audio-content' profile='RTP/AVP'>
|
||||
<transport xmlns='http://www.xmpp.org/extensions/xep-0176.html#ns-udp'>
|
||||
<candidate component='1'
|
||||
foundation='1'
|
||||
generation='0'
|
||||
ip='192.0.2.1'
|
||||
network='0'
|
||||
port='3478'
|
||||
priority='2130706431'
|
||||
protocol='udp'
|
||||
pwd='YH75Fviy6338Vbrhrlp8Yh'
|
||||
type='host'
|
||||
ufrag='9uB6'/>
|
||||
</transport>
|
||||
</content>
|
||||
</jingle>
|
||||
</iq>
|
||||
]]></example>
|
||||
<p>As above for the candidates sent by the responder, here the initiator acknowledges receipt of the candidates sent by the responder.</p>
|
||||
<example caption="Initiator acknowledges receipt"><![CDATA[
|
||||
<iq from='romeo@montague.lit/orchard'
|
||||
id='info3'
|
||||
to='juliet@capulet.lit/balcony'
|
||||
type='result'/>
|
||||
]]></example>
|
||||
</section3>
|
||||
</section2>
|
||||
<section2 topic='Connectivity Checks' anchor='protocol-checks'>
|
||||
<p>As the initiator and responder receive candidates, they probe the various candidate transports for connectivity. In performing these connectivity checks, each party SHOULD follow the procedure specified in Section 7 of &icecore;. The following business rules apply:</p>
|
||||
<ol>
|
||||
<li>Each party sends a STUN Binding Request (see &rfc3489bis;) from each local candidate it generated to each remote candidate it received.</li>
|
||||
<li>In accordance with &icecore;, the STUN Binding Request MUST include the PRIORITY attribute (computed according to Section 7.1.1.1. of &icecore;).</li>
|
||||
<li>For the purposes of the Jingle ICE-UDP Transport Method, both parties are full ICE implementations and therefore the controlling role MUST be assumed by the initiator and the controlled role MUST be assumed by the responder.</li>
|
||||
<li>The STUN Binding Requests generated by the initiator MAY include the USE-CANDIDATE attribute to indicate that the initiator wishes to cease checks for this component.</li>
|
||||
<li>The STUN Binding Requests generated by the initiator MUST include the ICE-CONTROLLING attribute.</li>
|
||||
<li>The STUN Binding Requests generated by the responder MUST include the ICE-CONTROLLED attribute.</li>
|
||||
<li>The parties MUST use STUN short term credentials to authenticate requests and perform message integrity checks.</li>
|
||||
</ol>
|
||||
<p>When it receives a STUN Binding Request, each party MUST return a STUN Binding Response, which may indicate either an error case or the success case. As described in Section 7.1.2.2 of &icecore;, a connectivity check succeeds if the STUN transaction generated a success response, the source IP address and port of the response equals the destination IP address and port that the Binding Request was sent to, and the destination IP address and port of the response match the source IP address and port that the Binding Request was sent from.</p>
|
||||
<p>For the candidates exchanged in the previous section, the connectivity checks would be as follows. In particular, the parties send one STUN Binding Request from each of their local candidates to each of the remote candidates.</p>
|
||||
<code><![CDATA[
|
||||
INITIATOR NAT RESPONDER
|
||||
| | |
|
||||
| | STUN Binding Request |
|
||||
| | from 192.0.2.1:3478 |
|
||||
| | to 10.0.1.1:8998 |
|
||||
| | (dropped) |
|
||||
| | x--------------------|
|
||||
| STUN Binding Request | |
|
||||
| from 10.0.1.1:8998 | |
|
||||
| to 192.0.2.1:3478 | |
|
||||
| USE-CANDIDATE | |
|
||||
|---------------------->| |
|
||||
| | STUN Binding Request |
|
||||
| | from 192.0.2.3:45664 |
|
||||
| | to 192.0.2.1:3478 |
|
||||
| | USE-CANDIDATE |
|
||||
| |---------------------->|
|
||||
| | STUN Binding Response |
|
||||
| | from 192.0.2.1:3478 |
|
||||
| | to 192.0.2.3:45664 |
|
||||
| |<----------------------|
|
||||
| STUN Binding Response | |
|
||||
| from 192.0.2.1:3478 | |
|
||||
| to 10.0.1.1:8998 | |
|
||||
| map 192.0.2.3:45664 | |
|
||||
|<----------------------| |
|
||||
|================RTP now can flow==============>|
|
||||
| | STUN Binding Request |
|
||||
| | from 192.0.2.1:3478 |
|
||||
| | to 192.0.2.3:45664 |
|
||||
| |<----------------------|
|
||||
| STUN Binding Request | |
|
||||
| from 192.0.2.1:3478 | |
|
||||
| to 10.0.1.1:8998 | |
|
||||
|<----------------------| |
|
||||
| STUN Binding Response | |
|
||||
| from 10.0.1.1:8998 | |
|
||||
| to 192.0.2.1:3478 | |
|
||||
| map 192.0.2.1:3478 | |
|
||||
|---------------------->| |
|
||||
| | STUN Binding Response |
|
||||
| | from 192.0.2.3:45664 |
|
||||
| | to 192.0.2.1:3478 |
|
||||
| | map 192.0.2.1:3478 |
|
||||
| |---------------------->|
|
||||
|<===============RTP now can flow===============|
|
||||
| | |
|
||||
]]></code>
|
||||
<p>Note: The initiator (controlling agent) is using "aggressive nomination" as described in Section 8.1.1.2 of &icecore; and therefore includes the USE-CANDIDATE attribute in the STUN Binding Requests it sends.</p>
|
||||
</section2>
|
||||
<section2 topic='Acceptance of Successful Candidate' anchor='protocol-acceptance'>
|
||||
<p>If, based on STUN connectivity checks (see &rfc3489; and &rfc3489bis;), the responder determines that it will be able to establish a connection using a given candidate, it sends a &JINGLE; element with an action of 'content-accept' (or 'session-accept') to the initiator, specifying the candidate that succeeded:</p>
|
||||
<p>If, based on STUN connectivity checks, the parties determine that they will be able to exchange media a given candidate, the responder sends a &JINGLE; element with an action of 'content-accept' (or 'session-accept') to the initiator, specifying the candidate that succeeded.</p>
|
||||
<example caption="Responder definitively accepts the successful candidate"><![CDATA[
|
||||
<iq from='juliet@capulet.com/balcony'
|
||||
id='accept1'
|
||||
@ -391,9 +519,11 @@
|
||||
ip='192.0.2.3'
|
||||
network='1'
|
||||
port='45664'
|
||||
priority='1678246398'
|
||||
priority='1694498815'
|
||||
protocol='udp'
|
||||
pwd='asd88fgpdd777uzjYhagZg'
|
||||
raddr='10.0.1.1'
|
||||
rport='8998'
|
||||
type='srflx'
|
||||
ufrag='8hhy'/>
|
||||
</transport>
|
||||
@ -402,14 +532,14 @@
|
||||
</iq>
|
||||
]]></example>
|
||||
<p>The &JINGLE; element in the content-accept or session-accept stanza SHOULD possess a 'responder' attribute that explicitly specifies the full JID of the responding entity. If the 'responder' attribute is provided, all future commmunications SHOULD be sent to the JID provided in the 'responder' attribute.</p>
|
||||
<p>If the initiator can also send data over that candidate, then it acknowledges the responder's acceptance:</p>
|
||||
<p>Since according to the connectivity checks the initiator can also send data over that candidate, it acknowledges the responder's acceptance:</p>
|
||||
<example caption="Initiator acknowledges acceptance of successful candidate"><![CDATA[
|
||||
<iq from='romeo@montague.net/orchard'
|
||||
id='accept1'
|
||||
to='juliet@capulet.com/balcony'
|
||||
type='result'/>
|
||||
]]></example>
|
||||
<p>Now the initiator and responder can begin sending data over the negotiated connection.</p>
|
||||
<p>Now the initiator and responder can begin sending data over the negotiated connection (in fact, they could have sent data as soon as the connectivity checks succeeded, as shown in the preceding examples).</p>
|
||||
<p>If a candidate succeeded for the responder but the initiator cannot send data over that candidate, it MUST return a ¬acceptable; error in response to the responder's acceptance of the successful candidate:</p>
|
||||
<example caption="Initiator returns error in response to acceptance of successful candidate"><![CDATA[
|
||||
<iq from='romeo@montague.net/orchard'
|
||||
@ -440,10 +570,10 @@
|
||||
<candidate component='1'
|
||||
foundation='1'
|
||||
generation='1'
|
||||
ip='192.0.2.4'
|
||||
ip='192.0.2.3'
|
||||
network='1'
|
||||
port='45665'
|
||||
priority='1678246398'
|
||||
priority='1694498815'
|
||||
protocol='udp'
|
||||
pwd='asd88fgpdd777uzjYhagZg'
|
||||
type='srflx'
|
||||
@ -479,10 +609,10 @@
|
||||
<candidate component='1'
|
||||
foundation='1'
|
||||
generation='1'
|
||||
ip='192.0.2.4'
|
||||
ip='192.0.2.3'
|
||||
network='1'
|
||||
port='45665'
|
||||
priority='1678246398'
|
||||
priority='1694498815'
|
||||
protocol='udp'
|
||||
pwd='asd88fgpdd777uzjYhagZg'
|
||||
type='srflx'
|
||||
@ -684,6 +814,8 @@
|
||||
<xs:attribute name='priority' type='xs:positiveInteger' use='required'/>
|
||||
<xs:attribute name='protocol' type='xs:NCName' use='required'/>
|
||||
<xs:attribute name='pwd' type='xs:string' use='required'/>
|
||||
<xs:attribute name='raddr' type='xs:string' use='optional'/>
|
||||
<xs:attribute name='rport' type='xs:unsignedShort' use='optional'/>
|
||||
<xs:attribute name='type' use='required'>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base='xs:NCName'>
|
||||
|
Loading…
Reference in New Issue
Block a user