Introduction
I bet you see this quite often: Error code: 0xFFF00XXX blah, blah, blah if it does not help please contact your system administrator or, in case of Windows Media Player (WMP), your content provider. But what if you are that system administrator or content provider people should contact. What do you do then? You "Google" the error code and few things come up. You dismiss those search results that say to contact you and … nothing is left. It happened to me when I worked on DRM license acquisition for WMP. In this article, I would like to share my research about specific DRM error codes.
Background
Recently, as I already mentioned, I have been working with Microsoft DRM. My task was to deliver a license to a user’s desktop from a license server. Only one license was allowed per media file. If a user is not eligible to receive anymore licenses the license server would send an HTTP response with 403 status code and nicely crafted error massage in its context. Please note that DRM license acquisition utilizes HTTP.
I thought I could just simply display the error message that came with the HTTP response to the user. It would provide a pleasant experience to the user by explaining nicely and clearly about the encountered problem. It will also make me happy, as I'll able to make a simple and elegant solution. "Not so fast cowboy" – stated the WMP API – "I will give you only an error code, no access to HTTP header or/and context whatsoever, gee, and now try to figure out what those error codes mean". I can still hear its giggling.
WMP errors
I decided to conduct a simple experiment. On every license request from a user’s desktop I would send a response from an HTTP server with different HTTP status code and see what error code WMP returns.
Here is the C code that I used to request DRM licenses:
#define CLEANLICOBJ pLicense->Release(); \
CoUninitialize()
HRESULT GetLicenses()
{
CoInitialize(NULL);
IRMGetLicense* pLicense = NULL;
HRESULT hr = CoCreateInstance(
__uuidof(RMGetLicense),
NULL, CLSCTX_INPROC_SERVER,
__uuidof(IRMGetLicense),
(void**)&pLicense);
if(FAILED(hr))
{
return hr;
}
CComBSTR bstrXMLDoc, bstrDRMVersion, bstrURL;
hr = pLicense->raw_GetDRMVersion(&bstrDRMVersion);
if(FAILED(hr))
{
CLEANLICOBJ;
return hr;
}
hr = pLicense->raw_GetSystemInfo(&bstrXMLDoc);
if(FAILED(hr))
{
CLEANLICOBJ;
return hr;
}
char url[1024];
for( int i = 0; i < STATUSCODESMAX; i++ )
{
sprintf(url,
"http://localhost/HttpErrorProducer/default.aspx?statuscode=%d",
httpStatusCode[i].StatusCode);
bstrURL.Append(url);
hr = pLicense->raw_GetLicenseFromURL(bstrXMLDoc, bstrURL);
printf("\n0x%X\t\t%d\t%s", hr,
httpStatusCode[i].StatusCode,
httpStatusCode[i].ReasonPhrase);
bstrURL.Empty();
}
CLEANLICOBJ;
return S_OK;
}
Here is an excerpt of ASP.NET server side code:
protected void Page_Load(object sender, EventArgs e)
{
int code = Convert.ToInt32(Request["statuscode"]);
HttpStatusCode statusCode =
HttpStatusCode.GetStatus(code);
Response.StatusCode = statusCode.StatusCode;
Response.Write(statusCode.ReasonPhrase);
}
Now this is the time for the error codes:
Error Code | HTTP Status Code | HTTP Reason Phrase |
0xC00D2712 | 200 | OK |
0xC00D275E | 201 | Created |
0xC00D275E | 202 | Accepted |
0xC00D275E | 203 | Non-Authoritative Information |
0xC00D275E | 204 | No Content |
0xC00D275E | 205 | Reset Content |
0xC00D275E | 206 | Partial Content |
0xC00D275E | 300 | Multiple Choices |
0x80072F76 | 301 | Moved Permanently |
0x80072F76 | 302 | Moved Temporarily |
0xC00D275E | 303 | See Other |
0xC00D275E | 304 | Not Modified |
0xC00D275E | 305 | Use Proxy |
0xC00D275E | 400 | Bad Request |
0xC00D2EFB | 401 | Unauthorized |
0xC00D275E | 402 | Payment Required |
0xC00D2EFB | 403 | Forbidden |
0xC00D2EE6 | 404 | Not Found |
0xC00D2EE3 | 405 | Method Not Allowed |
0xC00D275E | 406 | Not Acceptable |
0xC00D2EF6 | 407 | Proxy Authentication Required |
0xC00D2EE6 | 408 | Request Time-out |
0xC00D275E | 409 | Conflict |
0xC00D275E | 410 | Gone |
0xC00D275E | 411 | Length Required |
0xC00D275E | 412 | Precondition Failed |
0xC00D275E | 413 | Request Entity Too Large |
0xC00D275E | 414 | Request-URI Too Large |
0xC00D275E | 415 | Unsupported Media Type |
0xC00D2EE2 | 500 | Internal Server Error |
0xC00D275E | 501 | Not Implemented |
0xC00D2EE4 | 502 | Bad Gateway |
0xC00D2EE6 | 503 | Service Unavailable |
0xC00D2EE5 | 504 | Gateway Time-out |
0xC00D275E | 505 | HTTP Version not supported |
HTTP Status code 100 – "Continue" and 101 - "Switching Protocols" are not included as they would hang HTTP communication as they are suppose to.
The following error codes are worth noticing:
- 0xC00D2712: WMP has not received a license blob.
- 0xC00D2EFB: WMP likely has no credentials required to access to the server.
- 0xC00D2EE6: more likely to occur when WMP hits a wrong URL.
- 0xC00D2EE2: it is definitely time to contact the content provider!.
- 0xC00D275E: just very popular ;~).
Conclusion
I hope this article sheds some light on WMP error codes. Also you can find a sample of C code to request a license from a DRM server.
References
Please check these useful links for Windows Media Player error codes:
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.