Пример #1
0
HRESULT CNodeApplication::Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx)
{
	HRESULT hr;

	CheckNull(ctx);
	CheckNull(context);
	CheckNull(pProvider);

	ErrorIf(NULL == (*ctx = new CNodeHttpStoredContext(this, context)), ERROR_NOT_ENOUGH_MEMORY);	
	IHttpModuleContextContainer* moduleContextContainer = context->GetModuleContextContainer();
	moduleContextContainer->SetModuleContext(*ctx, this->GetApplicationManager()->GetModuleId());

	// increase the pending async opertation count; corresponding decrease happens in
	// CProtocolBridge::FinalizeResponseCore, possibly after several context switches
	(*ctx)->IncreasePendingAsyncOperationCount(); 

	CheckError(this->processManager->Dispatch(*ctx));

	return S_OK;

Error:	

	// on error, nodeContext need not be freed here as it will be deallocated through IHttpStoredContext when the request is finished

	return hr;
}
Пример #2
0
bool cCardClientRadegast::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
{
  cMutexLock lock(this);
  if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
  so.Flush();
  int len=SCT_LEN(source);
  int keynr=-1;
  switch(ecm->caId>>8) {
    case 0x01: // Seca
      keynr=cParseSeca::KeyNr(source)&0x0F; break;
    case 0x05: // Viaccess
      keynr=cParseViaccess::KeyNr(source); break;
    case 0x18: // Nagra2
      if(ecm->caId>=0x1801) keynr=(source[7]&0x10) | 0x86;
      break;
    }
  unsigned char buff[512], tmp[10];
  StartMsg(buff,1);			// CMD_ECM_KEY_ASK
  AddNano(buff,2,1,ecm->caId>>8);       // ECM_NANO_CAID_INDEX (old)
  AddNano(buff,10,2,ecm->caId);		// ECM_NANO_CAID
  sprintf((char *)tmp,"%08X",ecm->provId);
  AddNano(buff,6,8,tmp);		// ECM_NANO_PROVIDER
  if(keynr>=0) {
    sprintf((char *)tmp,"%04X",keynr);
    AddNano(buff,7,4,tmp);		// ECM_NANO_KEYNO
    }
  if(!CheckLength(buff,len)) return false;
  AddNano(buff,3,len,source);		// ECM_NANO_PACKET

  if(!Send(buff) || (len=Recv(buff,sizeof(buff)))<0) return false;
  if(buff[0]==2) {
    for(int l=GetNanoStart(buff); l<len; l+=buff[l+1]+2) {
      switch(buff[l]) {
        case 0x05:
          if(buff[l+1]==16) {
            // check for zero cw, as someone may not send both cw's every time
            if(!CheckNull(buff+l+ 2,8)) memcpy(cw+0,buff+l+ 2,8);
            if(!CheckNull(buff+l+10,8)) memcpy(cw+8,buff+l+10,8);
            return true;
            }
          else PRINTF(L_CC_RDGD,"wrong cw length %d from server",buff[l+1]);
          break;
        case 0x04:
          PRINTF(L_CC_ECM,"%s: key not available from server",name);
          break;
        default:
          PRINTF(L_CC_RDGD,"unknown nano %02x in ECM response",buff[l]);
          break;
        }
      }
    }
  else PRINTF(L_CC_RDGD,"bad ECM response from server %02x != 02",buff[0]);
  return false;
}
Пример #3
0
  void StarSystemSimulation::Simulate(Entity *simulationParent, float deltaT) 
  {
    base::Simulate(simulationParent, deltaT);

    CheckNull(simulationParent);
    ObejctState *simulationState = simulationParent->GetSimulationState();
    CheckNull(simulationState);

    Matrix4 translateToPosition;
    translateToPosition.SetIdentityMatrix();
    translateToPosition.SetPosition(GGame->GetCamera()->GetPosition());

    simulationState->_frame = translateToPosition;
  }
HRESULT CModuleConfiguration::Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId)	
{
	HRESULT hr;

	CheckNull(server);
	CheckNull(moduleId);

	CModuleConfiguration::server = server;
	CModuleConfiguration::moduleId = moduleId;

	return S_OK;
Error:
	return hr;
}
Пример #5
0
festring& festring::operator=(cchar* CStr)
{DBGEXEC(bugTrackInvalidChars(CStr,strlen(CStr)));
  CheckNull(CStr);

  sizetype NewSize = strlen(CStr);

  if(OwnsData)
  {
    if(!REFS(Data) && NewSize <= Reserved)
    {
      memcpy(Data, CStr, NewSize);
      Size = NewSize;
      return *this;
    }

    if(!REFS(Data)--)
      delete [] &REFS(Data);
  }

  if(NewSize)
    CreateOwnData(CStr, NewSize);
  else
    Empty();

  return *this;
}
Пример #6
0
HRESULT CNodeApplication::Initialize(PCWSTR scriptName, IHttpContext* context)
{
	HRESULT hr;

	CheckNull(scriptName);

	DWORD len = wcslen(scriptName) + 1;
	ErrorIf(NULL == (this->scriptName = new WCHAR[len]), ERROR_NOT_ENOUGH_MEMORY);
	wcscpy(this->scriptName, scriptName);

	ErrorIf(NULL == (this->processManager = new	CNodeProcessManager(this, context)), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(this->processManager->Initialize(context));

	CheckError(this->GetApplicationManager()->GetFileWatcher()->WatchFiles(
		scriptName, 
		CModuleConfiguration::GetWatchedFiles(context),
		CNodeApplicationManager::OnScriptModified, 
		this->GetApplicationManager(), 
		this));

	this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode initialized a new node.js application", WINEVENT_LEVEL_INFO);

	return S_OK;
Error:

	this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode failed to initialize a new node.js application", WINEVENT_LEVEL_ERROR);

	this->Cleanup();

	return hr;
}
Пример #7
0
festring& festring::operator=(staticstring SStr)
{DBGEXEC(bugTrackInvalidChars(SStr.Data,SStr.Size));
  CheckNull(SStr.Data);

  cchar* CStr = SStr.Data;
  sizetype NewSize = SStr.Size;

  if(OwnsData)
  {
    if(!REFS(Data) && NewSize <= Reserved)
    {
      memcpy(Data, CStr, NewSize);
      Size = NewSize;
      return *this;
    }

    if(!REFS(Data)--)
      delete [] &REFS(Data);
  }

  Size = NewSize;
  Data = const_cast<char*>(CStr);
  OwnsData = false;
  return *this;
}
Пример #8
0
HRESULT CActiveRequestPool::Remove(CNodeHttpStoredContext* context)
{
	HRESULT hr;
	BOOL signal = FALSE;

	CheckNull(context);

	ENTER_CS(this->syncRoot)

	this->requests.remove(context);

	if (NULL != this->drainHandle && this->requests.empty())
	{
		signal = TRUE;
	}

	LEAVE_CS(this->syncRoot)

	if (signal)
	{
		SetEvent(this->drainHandle);
	}

	return S_OK;
Error:
	return hr;
}
HRESULT CModuleConfiguration::GetDWORD(IAppHostElement* section, LPCWSTR propertyName, DWORD* value)
{
	HRESULT hr = S_OK;
    BSTR sysPropertyName = NULL;
    IAppHostProperty* prop = NULL;
	VARIANT var;

	CheckNull(value);
	*value = 0;
	VariantInit(&var);
	ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(section->GetPropertyByName(sysPropertyName, &prop));
	CheckError(prop->get_Value(&var));
	CheckError(VariantChangeType(&var, &var, 0, VT_UI4));
	*value = var.ulVal;

Error:

	VariantClear(&var);

    if ( sysPropertyName )
    {
        SysFreeString(sysPropertyName);
        sysPropertyName = NULL;
    }

    if (prop)
    {
        prop->Release();
        prop = NULL;
    }

    return hr;
}
HRESULT CModuleConfiguration::GetConfigSection(IHttpContext* context, IAppHostElement** section, OLECHAR* configElement)
{
	HRESULT hr = S_OK;
    BSTR path = NULL;
    BSTR elementName = NULL;

	CheckNull(section);
	*section = NULL;
	ErrorIf(NULL == (path = SysAllocString(context->GetMetadata()->GetMetaPath())), ERROR_NOT_ENOUGH_MEMORY);
    ErrorIf(NULL == (elementName = SysAllocString(configElement)), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(server->GetAdminManager()->GetAdminSection(elementName, path, section));

Error:

    if (NULL != elementName)
    {
        SysFreeString(elementName);
        elementName = NULL;
    }

    if (NULL != path)
    {
        SysFreeString(path);
        path = NULL;
    }

    return hr;
}
HRESULT CModuleConfiguration::GetDebugPortRange(IHttpContext* ctx, DWORD* start, DWORD* end)
{
	HRESULT hr;

	CheckNull(start);
	CheckNull(end);

	CModuleConfiguration* c = NULL; 
	GetConfig(ctx, &c); 

	if (0 == c->debugPortStart)
	{
		CheckNull(c->debugPortRange);
		LPWSTR dash = c->debugPortRange;
		while (*dash != L'\0' && *dash != L'-')
			dash++;
		ErrorIf(dash == c->debugPortRange, ERROR_INVALID_PARAMETER);
		c->debugPortStart = _wtoi(c->debugPortRange);
		ErrorIf(c->debugPortStart < 1025, ERROR_INVALID_PARAMETER);
		if (*dash != L'\0')
		{
			c->debugPortEnd = _wtoi(dash + 1);
			ErrorIf(c->debugPortEnd < c->debugPortStart || c->debugPortEnd > 65535, ERROR_INVALID_PARAMETER);
		}
		else
		{
			c->debugPortEnd = c->debugPortStart;
		}
	}

	*start = c->debugPortStart;
	*end = c->debugPortEnd;

	return S_OK;
Error:

	if (c)
	{
		c->debugPortStart = c->debugPortEnd = 0;
	}

	return hr;
}
Пример #12
0
OSStatus		AUCarbonViewBase::ComponentEntryDispatch(ComponentParameters *p, AUCarbonViewBase *This)
{
	if (This == NULL) return paramErr;

	OSStatus result = noErr;

	switch (p->what) {
	case kAudioUnitCarbonViewCreateSelect:
		{
			AudioUnitCarbonViewCreateGluePB *pb = (AudioUnitCarbonViewCreateGluePB *)p;
			CheckNull(pb->inAudioUnit);
			CheckNull(pb->inWindow);
			CheckNull(pb->inParentControl);
			CheckNull(pb->inSize);
			CheckNull(pb->inLocation);
			CheckNull(pb->outControl);
			result = This->CreateCarbonView(pb->inAudioUnit, pb->inWindow, pb->inParentControl,
					*pb->inLocation, *pb->inSize, *pb->outControl);
		}
		break;
#if !__LP64__
	case kAudioUnitCarbonViewSetEventListenerSelect:
		{
			AudioUnitCarbonViewSetEventListenerGluePB *pb = (AudioUnitCarbonViewSetEventListenerGluePB *)p;
			This->SetEventListener(pb->inCallback, pb->inUserData);
		}
		break;
#endif

	default:
		result = ComponentBase::ComponentEntryDispatch(p, This);
		break;
	}
	return result;
}
Пример #13
0
bool cDeCSA::SetDescr(ca_descr_t *ca_descr, bool initial)
{
  cMutexLock lock(&mutex);

  int idx=ca_descr->index;
  if(idx<MAX_CSA_IDX && GetKeyStruct(idx)) {
    if(!initial && ca_descr->parity==(even_odd[idx]&0x40)>>6) {
      if(flags[idx] & (ca_descr->parity?FL_ODD_GOOD:FL_EVEN_GOOD)) {
        printf("adapter%d/demux%d idx %d: %s key in use (%d ms)", adapter, demux ,idx,ca_descr->parity?"odd":"even",MAX_REL_WAIT);
        if(wait.TimedWait(mutex,MAX_REL_WAIT))
          printf("adapter%d/demux%d idx %d: successfully waited for release\n", adapter, demux, idx);
        else
          printf("adapter%d/demux%d idx %d: timed out. setting anyways\n", adapter, demux, idx);
      }
      else
        printf("adapter%d/demux%d idx %d: late key set...\n", adapter, demux, idx);
    }
    if(ca_descr->parity==0) {
      dvbcsa_bs_key_set(ca_descr->cw, csa_bs_key_even[idx]);

      if(!CheckNull(ca_descr->cw,8))
        flags[idx] |= FL_EVEN_GOOD|FL_ACTIVITY;
      else
        printf("adapter%d/demux%d idx %d: zero even CW\n", adapter, demux, idx);
      wait.Broadcast();
    } else {
      dvbcsa_bs_key_set(ca_descr->cw, csa_bs_key_odd[idx]);

      if(!CheckNull(ca_descr->cw,8))
        flags[idx] |= FL_ODD_GOOD|FL_ACTIVITY;
      else
        printf("adapter%d/demux%d idx%d: zero odd CW\n", adapter, demux, idx);
      wait.Broadcast();
    }
  }

  return true;
}
Пример #14
0
HRESULT CActiveRequestPool::Add(CNodeHttpStoredContext* context)
{
	HRESULT hr;

	CheckNull(context);

	ENTER_CS(this->syncRoot)

	ErrorIf(this->requests.size() >= CModuleConfiguration::GetMaxConcurrentRequestsPerProcess(context->GetHttpContext()), ERROR_NOT_ENOUGH_QUOTA);
	this->requests.push_back(context);

	LEAVE_CS(this->syncRoot)

	return S_OK;
Error:
	return hr;
}
Пример #15
0
HRESULT CPendingRequestQueue::Push(CNodeHttpStoredContext* context)
{
	HRESULT hr;

	CheckNull(context);

	ENTER_CS(this->syncRoot)

	ErrorIf(this->requests.size() >= CModuleConfiguration::GetMaxPendingRequestsPerApplication(context->GetHttpContext()), ERROR_NOT_ENOUGH_QUOTA);
	this->requests.push(context);

	LEAVE_CS(this->syncRoot)

	return S_OK;
Error:
	return hr;
}
HRESULT CNodeApplicationManager::Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx)
{
	HRESULT hr;
	CNodeApplication* application;
	NodeDebugCommand debugCommand;

	CheckNull(ctx);
	*ctx = NULL;

	CheckError(CNodeDebugger::GetDebugCommand(context, this->GetEventProvider(), &debugCommand));

	if (ND_KILL == debugCommand)
	{
		ENTER_CS(this->syncRoot)

		CheckError(this->EnsureDebuggedApplicationKilled(context, ctx));

		LEAVE_CS(this->syncRoot)
	}
HRESULT CModuleConfiguration::GetString(IAppHostElement* section, LPCWSTR propertyName, LPWSTR* value)
{
	HRESULT hr = S_OK;
    BSTR sysPropertyName = NULL;
    BSTR sysPropertyValue = NULL;
    IAppHostProperty* prop = NULL;

	CheckNull(value);
	*value = NULL;
	ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(section->GetPropertyByName(sysPropertyName, &prop));
	CheckError(prop->get_StringValue(&sysPropertyValue));
	ErrorIf(NULL == (*value = new WCHAR[wcslen(sysPropertyValue) + 1]), ERROR_NOT_ENOUGH_MEMORY);
	wcscpy(*value, sysPropertyValue);

Error:

    if ( sysPropertyName )
    {
        SysFreeString(sysPropertyName);
        sysPropertyName = NULL;
    }

    if ( sysPropertyValue )
    {
        SysFreeString(sysPropertyValue);
        sysPropertyValue = NULL;
    }

    if (prop)
    {
        prop->Release();
        prop = NULL;
    }

    return hr;
}
Пример #18
0
HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void** result, DWORD* resultSize, DWORD* resultLength)
{
	HRESULT hr;
	PCSTR originalUrl = NULL;
	USHORT originalUrlLength;	

	CheckNull(ctx);
	CheckNull(result);
	CheckNull(resultSize);
	CheckNull(resultLength);

	IHttpContext* context = ctx->GetHttpContext();

	DWORD bufferLength = CModuleConfiguration::GetInitialRequestBufferSize(context);
	DWORD offset = 0;
	IHttpRequest* request = context->GetRequest();
	HTTP_REQUEST* raw = request->GetRawHttpRequest();
	USHORT major, minor;
	char tmp[256];
	PCSTR method = request->GetHttpMethod();
	
	ErrorIf(NULL == (*result = context->AllocateRequestMemory(bufferLength)), ERROR_NOT_ENOUGH_MEMORY);	

	// Determine whether response entity body is to be expected

	if (method && 0 == strcmpi("HEAD", method))
	{
		// HEAD requests do not have response entity body
		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4

		ctx->SetExpectResponseBody(FALSE);
	}
	
	// Request-Line

	CheckError(CHttpProtocol::Append(context, method, 0, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, " ", 1, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, ctx->GetTargetUrl(), ctx->GetTargetUrlLength(), result, &bufferLength, &offset));
	request->GetHttpVersion(&major, &minor);
	if (1 == major && 1 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.1\r\n", 11, result, &bufferLength, &offset));
	}
	else if (1 == major && 0 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.0\r\n", 11, result, &bufferLength, &offset));
	}
	else
	{
		sprintf(tmp, " HTTP/%d.%d\r\n", major, minor);
		CheckError(CHttpProtocol::Append(context, tmp, 0, result, &bufferLength, &offset));
	}

	// Known headers

	for (int i = 0; i < HttpHeaderRequestMaximum; i++)
	{
		if (raw->Headers.KnownHeaders[i].RawValueLength > 0)
		{
			CheckError(CHttpProtocol::Append(context, CHttpProtocol::httpRequestHeaders[i], 0, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, raw->Headers.KnownHeaders[i].pRawValue, raw->Headers.KnownHeaders[i].RawValueLength, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
		}
	}

	// Unknown headers

	for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++)
	{
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pName, raw->Headers.pUnknownHeaders[i].NameLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pRawValue, raw->Headers.pUnknownHeaders[i].RawValueLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
	}

	// CRLF

	CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));

	*resultSize = bufferLength;
	*resultLength = offset;

	return S_OK;
Error:
	
	if (NULL != result)
	{
		*result = NULL;
	}
	if (NULL != resultLength)
	{
		*resultLength = 0;
	}
	if (NULL != resultSize)
	{
		*resultSize = 0;
	}

	return hr;
}
Пример #19
0
HRESULT CFileWatcher::WatchFiles(PCWSTR mainFileName, PCWSTR watchedFiles, FileModifiedCallback callback, CNodeApplicationManager* manager, CNodeApplication* application)
{
	HRESULT hr;
	WCHAR fileOnly[_MAX_FNAME];
	WCHAR ext[_MAX_EXT];
	WCHAR* directoryName = NULL;
	DWORD fileNameLength;
	DWORD fileNameOnlyLength;
	DWORD directoryLength;	
	BOOL unc;
	BOOL wildcard;
	PWSTR startSubdirectory;
	PWSTR startFile;
	PWSTR endFile;
	WatchedDirectory* directory;
	WatchedFile* file;

	CheckNull(mainFileName);
	CheckNull(watchedFiles);

	// create and normalize a copy of directory name, determine if it is UNC share

	fileNameLength = wcslen(mainFileName);
	ErrorIf(0 != _wsplitpath_s(mainFileName, NULL, 0, NULL, 0, fileOnly, _MAX_FNAME, ext, _MAX_EXT), ERROR_INVALID_PARAMETER);	
	fileNameOnlyLength = wcslen(fileOnly) + wcslen(ext);	
	directoryLength = fileNameLength - fileNameOnlyLength; 
	ErrorIf(NULL == (directoryName = new WCHAR[directoryLength + 8]), ERROR_NOT_ENOUGH_MEMORY); // pessimistic length after normalization with prefix \\?\UNC\ 

	if (fileNameLength > 8 && 0 == memcmp(mainFileName, L"\\\\?\\UNC\\", 8 * sizeof WCHAR))
	{
		// normalized UNC path
		unc = TRUE;
		memcpy(directoryName, mainFileName, directoryLength * sizeof WCHAR);
		directoryName[directoryLength] = L'\0';
	}
	else if (fileNameLength > 4 && 0 == memcmp(mainFileName, L"\\\\?\\", 4 * sizeof WCHAR))
	{
		// normalized local file
		unc = FALSE;
		memcpy(directoryName, mainFileName, directoryLength * sizeof WCHAR);
		directoryName[directoryLength] = L'\0';
	}
	else if (fileNameLength > 2 && 0 == memcmp(mainFileName, L"\\\\", 2 * sizeof(WCHAR)))
	{
		// not normalized UNC path
		unc = TRUE;
		wcscpy(directoryName, L"\\\\?\\UNC\\");
		memcpy(directoryName + 8, mainFileName + 2, (directoryLength - 2) * sizeof WCHAR);
		directoryName[8 + directoryLength - 2] = L'\0';
	}
	else
	{
		// not normalized local file
		unc = FALSE;
		wcscpy(directoryName, L"\\\\?\\");
		memcpy(directoryName + 4, mainFileName, directoryLength * sizeof WCHAR);
		directoryName[4 + directoryLength] = L'\0';	
	}

	directoryLength = wcslen(directoryName);

	ENTER_CS(this->syncRoot)

	// parse watchedFiles and create a file listener for each of the files

	startFile = (PWSTR)watchedFiles;
	do {
		endFile = startSubdirectory = startFile;
		wildcard = FALSE;
		while (*endFile && *endFile != L';')
		{
			wildcard |= *endFile == L'*' || *endFile == L'?';
			if (*endFile == L'\\')
			{
				startFile = endFile + 1;
			}

			endFile++;
		}

		if (startFile != endFile)
		{
			hr = this->WatchFile(directoryName, directoryLength, unc, startSubdirectory, startFile, endFile, wildcard);

			// ignore files and directories that do not exist instead of failing

			if (S_OK != hr && ERROR_FILE_NOT_FOUND != hr)
			{
				// still under lock remove file watch entries that were just created, then do regular cleanup

				this->RemoveWatch(NULL);
				CheckError(hr);
			}
		}

		startFile = endFile + 1;

	} while(*endFile);

	// update temporary entries with application and callback pointers

	directory = this->directories;
	while (NULL != directory)
	{
		file = directory->files;
		while (NULL != file)
		{
			if (NULL == file->application)
			{
				file->application = application;
				file->manager = manager;
				file->callback = callback;
			}

			file = file->next;
		}

		directory = directory->next;
	}

	LEAVE_CS(this->syncRoot)

	delete [] directoryName;

	return S_OK;

Error:

	if (NULL != directoryName)
	{
		delete [] directoryName;
		directoryName = NULL;
	}


	return hr;
}
Пример #20
0
HRESULT CHttpProtocol::SerializeRequestHeaders(IHttpContext* context, void** result, DWORD* resultSize, DWORD* resultLength)
{
	HRESULT hr;

	CheckNull(context);
	CheckNull(result);
	CheckNull(resultSize);
	CheckNull(resultLength);

	DWORD bufferLength = CModuleConfiguration::GetInitialRequestBufferSize(context);
	DWORD offset = 0;
	IHttpRequest* request = context->GetRequest();
	HTTP_REQUEST* raw = request->GetRawHttpRequest();
	USHORT major, minor;
	char tmp[256];
	
	ErrorIf(NULL == (*result = context->AllocateRequestMemory(bufferLength)), ERROR_NOT_ENOUGH_MEMORY);	
	
	// Request-Line

	CheckError(CHttpProtocol::Append(context, request->GetHttpMethod(), 0, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, " ", 1, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, raw->pRawUrl, raw->RawUrlLength, result, &bufferLength, &offset));
	request->GetHttpVersion(&major, &minor);
	sprintf(tmp, " HTTP/%d.%d\r\n", major, minor);
	CheckError(CHttpProtocol::Append(context, tmp, 0, result, &bufferLength, &offset));

	// Known headers

	for (int i = 0; i < HttpHeaderRequestMaximum; i++)
	{
		if (raw->Headers.KnownHeaders[i].RawValueLength > 0)
		{
			CheckError(CHttpProtocol::Append(context, CHttpProtocol::httpRequestHeaders[i], 0, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, raw->Headers.KnownHeaders[i].pRawValue, raw->Headers.KnownHeaders[i].RawValueLength, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
		}
	}

	// Unknown headers

	for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++)
	{
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pName, raw->Headers.pUnknownHeaders[i].NameLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pRawValue, raw->Headers.pUnknownHeaders[i].RawValueLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
	}

	// CRLF

	CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));

	*resultSize = bufferLength;
	*resultLength = offset;

	return S_OK;
Error:
	
	if (NULL != result)
	{
		*result = NULL;
	}
	if (NULL != resultLength)
	{
		*resultLength = 0;
	}
	if (NULL != resultSize)
	{
		*resultSize = 0;
	}

	return hr;
}
Пример #21
0
HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void** result, DWORD* resultSize, DWORD* resultLength)
{
	HRESULT hr;
	PCSTR originalUrl = NULL;
	USHORT originalUrlLength;
	DWORD remoteHostSize = INET6_ADDRSTRLEN + 1;
	char remoteHost[INET6_ADDRSTRLEN + 1];
	BOOL addXFF;
	char** serverVars;
	int serverVarCount;

	CheckNull(ctx);
	CheckNull(result);
	CheckNull(resultSize);
	CheckNull(resultLength);

	IHttpContext* context = ctx->GetHttpContext();

	DWORD bufferLength = CModuleConfiguration::GetInitialRequestBufferSize(context);
	DWORD offset = 0;
	IHttpRequest* request = context->GetRequest();
	HTTP_REQUEST* raw = request->GetRawHttpRequest();
	USHORT major, minor;
	const int tmpSize = 256;
	char tmp[tmpSize];
	PCSTR method = request->GetHttpMethod();
	
	ErrorIf(NULL == (*result = context->AllocateRequestMemory(bufferLength)), ERROR_NOT_ENOUGH_MEMORY);	

	// Determine whether response entity body is to be expected

	if (method && 0 == strcmpi("HEAD", method))
	{
		// HEAD requests do not have response entity body
		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4

		ctx->SetExpectResponseBody(FALSE);
	}
	
	// Request-Line

	CheckError(CHttpProtocol::Append(context, method, 0, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, " ", 1, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, ctx->GetTargetUrl(), ctx->GetTargetUrlLength(), result, &bufferLength, &offset));
	request->GetHttpVersion(&major, &minor);
	if (1 == major && 1 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.1\r\n", 11, result, &bufferLength, &offset));
	}
	else if (1 == major && 0 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.0\r\n", 11, result, &bufferLength, &offset));
	}
	else
	{
		sprintf(tmp, " HTTP/%d.%d\r\n", major, minor);
		CheckError(CHttpProtocol::Append(context, tmp, 0, result, &bufferLength, &offset));
	}

	// Known headers

	for (int i = 0; i < HttpHeaderRequestMaximum; i++)
	{
		if (raw->Headers.KnownHeaders[i].RawValueLength > 0)
		{
			CheckError(CHttpProtocol::Append(context, CHttpProtocol::httpRequestHeaders[i], 0, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, raw->Headers.KnownHeaders[i].pRawValue, raw->Headers.KnownHeaders[i].RawValueLength, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
		}
	}

	// Unknown headers

	if (TRUE == (addXFF = CModuleConfiguration::GetEnableXFF(context)))
	{
		PSOCKADDR addr = request->GetRemoteAddress();
		DWORD addrSize = addr->sa_family == AF_INET ? sizeof SOCKADDR_IN : sizeof SOCKADDR_IN6;
		ErrorIf(0 != WSAAddressToString(addr, addrSize, NULL, remoteHost, &remoteHostSize), GetLastError());
	}

	for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++)
	{
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pName, raw->Headers.pUnknownHeaders[i].NameLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pRawValue, raw->Headers.pUnknownHeaders[i].RawValueLength, result, &bufferLength, &offset));

		if (addXFF && 15 == raw->Headers.pUnknownHeaders[i].NameLength && 0 == strcmpi("X-Forwarded-For", raw->Headers.pUnknownHeaders[i].pName))
		{
			// augment existing X-Forwarded-For header

			CheckError(CHttpProtocol::Append(context, ", ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, remoteHost, remoteHostSize - 1, result, &bufferLength, &offset));

			addXFF = FALSE;
		}

		CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
	}

	if (addXFF)
	{
		// add a new X-Forwarded-For header

		CheckError(CHttpProtocol::Append(context, "X-Forwarded-For: ", 17, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, remoteHost, remoteHostSize - 1, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
	}

	// promote server variables

	CheckError(CModuleConfiguration::GetPromoteServerVars(context, &serverVars, &serverVarCount));
	while (serverVarCount)
	{
		serverVarCount--;
		PCSTR varValue;
		DWORD varValueLength;
		if (S_OK == context->GetServerVariable(serverVars[serverVarCount], &varValue, &varValueLength))
		{
			CheckError(CHttpProtocol::Append(context, "X-iisnode-", 10, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, serverVars[serverVarCount], 0, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, varValue, varValueLength, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
		}
	}

	// CRLF

	CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));

	*resultSize = bufferLength;
	*resultLength = offset;

	return S_OK;
Error:
	
	if (NULL != result)
	{
		*result = NULL;
	}
	if (NULL != resultLength)
	{
		*resultLength = 0;
	}
	if (NULL != resultSize)
	{
		*resultSize = 0;
	}

	return hr;
}
HRESULT CModuleConfiguration::CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH* env)
{
	HRESULT hr;
	LPCH currentEnvironment = NULL;
	LPCH tmpStart, tmpIndex = NULL;
	DWORD tmpSize;
	DWORD environmentSize;
	IAppHostElement* section = NULL;
	IAppHostElementCollection* appSettings = NULL;
	IAppHostElement* entry = NULL;
	IAppHostPropertyCollection* properties = NULL;
	IAppHostProperty* prop = NULL;
	BSTR keyPropertyName = NULL;
	BSTR valuePropertyName = NULL;
	VARIANT vKeyPropertyName;
	VARIANT vValuePropertyName;
	DWORD count;
	BSTR propertyValue;
	int propertySize;

	CheckNull(env);
	*env = NULL;

	// this is a zero terminated list of zero terminated strings of the form <var>=<value>

	// calculate size of current environment

	ErrorIf(NULL == (currentEnvironment = GetEnvironmentStrings()), GetLastError());
	environmentSize = 0;
	do {
		while (*(currentEnvironment + environmentSize++) != 0);
	} while (*(currentEnvironment + environmentSize++) != 0);

	// allocate memory for new environment variables

	tmpSize = 32767 - environmentSize;
	ErrorIf(NULL == (tmpIndex = tmpStart = new char[tmpSize]), ERROR_NOT_ENOUGH_MEMORY);
	RtlZeroMemory(tmpIndex, tmpSize);

	// set PORT and IISNODE_VERSION variables

	ErrorIf(tmpSize < (strlen(namedPipe) + strlen(IISNODE_VERSION) + 6 + 17), ERROR_NOT_ENOUGH_MEMORY);
	sprintf(tmpIndex, "PORT=%s", namedPipe);
	tmpIndex += strlen(namedPipe) + 6;
	sprintf(tmpIndex, "IISNODE_VERSION=%s", IISNODE_VERSION);
	tmpIndex += strlen(IISNODE_VERSION) + 17;

	// set DEBUGPORT environment variable if requested (used by node-inspector)

	if (debugPort > 0)
	{
		char debugPortS[64];
		sprintf(debugPortS, "%d", debugPort);
		ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(debugPortS) + 11), ERROR_NOT_ENOUGH_MEMORY);
		sprintf(tmpIndex, "DEBUGPORT=%s", debugPortS);
		tmpIndex += strlen(debugPortS) + 11;
	}
		
	// add environment variables from the appSettings section of config

	ErrorIf(NULL == (keyPropertyName = SysAllocString(L"key")), ERROR_NOT_ENOUGH_MEMORY);
	vKeyPropertyName.vt = VT_BSTR;
	vKeyPropertyName.bstrVal = keyPropertyName;
	ErrorIf(NULL == (valuePropertyName = SysAllocString(L"value")), ERROR_NOT_ENOUGH_MEMORY);
	vValuePropertyName.vt = VT_BSTR;
	vValuePropertyName.bstrVal = valuePropertyName;
	CheckError(GetConfigSection(ctx, &section, L"appSettings"));
	CheckError(section->get_Collection(&appSettings));
	CheckError(appSettings->get_Count(&count));

	for (USHORT i = 0; i < count; i++)
	{
		VARIANT index;
		index.vt = VT_I2;
		index.iVal = i;		

		CheckError(appSettings->get_Item(index, &entry));
		CheckError(entry->get_Properties(&properties));
		
		CheckError(properties->get_Item(vKeyPropertyName, &prop));
		CheckError(prop->get_StringValue(&propertyValue));
		ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL);
		ErrorIf((propertySize + 2) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY);
		ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL);
		tmpIndex[propertySize] = '=';
		tmpIndex += propertySize + 1;
		SysFreeString(propertyValue);
		propertyValue = NULL;
		prop->Release();
		prop = NULL;

		CheckError(properties->get_Item(vValuePropertyName, &prop));
		CheckError(prop->get_StringValue(&propertyValue));
		ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL);
		ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY);
		ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL);
		tmpIndex += propertySize + 1;
		SysFreeString(propertyValue);
		propertyValue = NULL;
		prop->Release();
		prop = NULL;

		properties->Release();
		properties = NULL;
		entry->Release();
		entry = NULL;
	}

	// concatenate new environment variables with the current environment block

	ErrorIf(NULL == (*env = (LPCH)new char[environmentSize + (tmpIndex - tmpStart)]), ERROR_NOT_ENOUGH_MEMORY);	
	memcpy(*env, tmpStart, (tmpIndex - tmpStart));
	memcpy(*env + (tmpIndex - tmpStart), currentEnvironment, environmentSize);

	// cleanup

	FreeEnvironmentStrings(currentEnvironment);
	section->Release();
	appSettings->Release();
	SysFreeString(keyPropertyName);
	SysFreeString(valuePropertyName);
	delete [] tmpStart;

	return S_OK;
Error:

	if (currentEnvironment)
	{
		FreeEnvironmentStrings(currentEnvironment);
		currentEnvironment = NULL;
	}

	if (section)
	{
		section->Release();
		section = NULL;
	}

	if (appSettings)
	{
		appSettings->Release();
		appSettings = NULL;
	}

	if (keyPropertyName)
	{
		SysFreeString(keyPropertyName);
		keyPropertyName = NULL;
	}

	if (valuePropertyName)
	{
		SysFreeString(valuePropertyName);
		valuePropertyName = NULL;
	}

	if (entry)
	{
		entry->Release();
		entry = NULL;
	}

	if (properties)
	{
		properties->Release();
		properties = NULL;
	}

	if (prop)
	{
		prop->Release();
		prop = NULL;
	}

	if (propertyValue)
	{
		SysFreeString(propertyValue);
		propertyValue = NULL;
	}

	if (tmpStart)
	{
		delete [] tmpStart;
		tmpStart = NULL;
	}

	return hr;
}
HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfiguration** config)
{
	HRESULT hr;
	CModuleConfiguration* c = NULL;
	IAppHostElement* section = NULL;
	LPWSTR commandLine = NULL;
	size_t i;

	CheckNull(config);

	*config = (CModuleConfiguration*)context->GetMetadata()->GetModuleContextContainer()->GetModuleContext(moduleId);

	if (NULL == *config)
	{
		ErrorIf(NULL == (c = new CModuleConfiguration()), ERROR_NOT_ENOUGH_MEMORY);
		
		CheckError(GetConfigSection(context, &section));		
		CheckError(GetDWORD(section, L"maxPendingRequestsPerApplication", &c->maxPendingRequestsPerApplication));
		CheckError(GetDWORD(section, L"asyncCompletionThreadCount", &c->asyncCompletionThreadCount));
		CheckError(GetDWORD(section, L"maxProcessCountPerApplication", &c->maxProcessCountPerApplication));
		CheckError(GetDWORD(section, L"maxConcurrentRequestsPerProcess", &c->maxConcurrentRequestsPerProcess));
		CheckError(GetDWORD(section, L"maxNamedPipeConnectionRetry", &c->maxNamedPipeConnectionRetry));
		CheckError(GetDWORD(section, L"namedPipeConnectionRetryDelay", &c->namedPipeConnectionRetryDelay));
		CheckError(GetDWORD(section, L"initialRequestBufferSize", &c->initialRequestBufferSize));
		CheckError(GetDWORD(section, L"maxRequestBufferSize", &c->maxRequestBufferSize));
		CheckError(GetDWORD(section, L"uncFileChangesPollingInterval", &c->uncFileChangesPollingInterval));
		CheckError(GetDWORD(section, L"gracefulShutdownTimeout", &c->gracefulShutdownTimeout));
		CheckError(GetDWORD(section, L"logFileFlushInterval", &c->logFileFlushInterval));
		CheckError(GetDWORD(section, L"maxLogFileSizeInKB", &c->maxLogFileSizeInKB));
		CheckError(GetBOOL(section, L"loggingEnabled", &c->loggingEnabled));
		CheckError(GetBOOL(section, L"appendToExistingLog", &c->appendToExistingLog));
		CheckError(GetString(section, L"logDirectoryNameSuffix", &c->logDirectoryNameSuffix));
		CheckError(GetString(section, L"debuggerPortRange", &c->debugPortRange));
		CheckError(GetString(section, L"debuggerPathSegment", &c->debuggerPathSegment));
		c->debuggerPathSegmentLength = wcslen(c->debuggerPathSegment);
		CheckError(GetString(section, L"nodeProcessCommandLine", &commandLine));
		ErrorIf(NULL == (c->nodeProcessCommandLine = new char[MAX_PATH]), ERROR_NOT_ENOUGH_MEMORY);
		ErrorIf(0 != wcstombs_s(&i, c->nodeProcessCommandLine, (size_t)MAX_PATH, commandLine, _TRUNCATE), ERROR_INVALID_PARAMETER);
		delete [] commandLine;
		commandLine = NULL;
		
		section->Release();
		section = NULL;
		
		// CR: check for ERROR_ALREADY_ASSIGNED to detect a race in creation of this section 
		// CR: refcounting may be needed if synchronous code paths proove too long (race with config changes)
		context->GetMetadata()->GetModuleContextContainer()->SetModuleContext(c, moduleId);
		*config = c;
		c = NULL;
	}

	return S_OK;
Error:

	if (NULL != section)
	{
		section->Release();
		section = NULL;
	}

	if (NULL != commandLine)
	{
		delete [] commandLine;
		commandLine = NULL;
	}

	if (NULL != c)
	{
		delete c;
		c = NULL;
	}

	return hr;
}
Пример #24
0
HRESULT CFileWatcher::WatchFile(PCWSTR fileName, FileModifiedCallback callback, void* data)
{
	HRESULT hr;
	WatchedFile* file;
	WatchedDirectory* directory;
	WatchedDirectory* newDirectory;
	WCHAR fileOnly[_MAX_FNAME];
	WCHAR ext[_MAX_EXT];
	WCHAR* directoryName = NULL;
	DWORD fileNameLength;
	DWORD fileNameOnlyLength;
	DWORD directoryLength;	
	WIN32_FILE_ATTRIBUTE_DATA attributes;

	CheckNull(callback);
	CheckNull(fileName);
	fileNameLength = wcslen(fileName);

	// allocate new WatchedFile, get snapshot of the last write time

	ErrorIf(NULL == (file = new WatchedFile), ERROR_NOT_ENOUGH_MEMORY);
	RtlZeroMemory(file, sizeof WatchedFile);
	file->callback = callback;
	file->data = data;
	ErrorIf(!GetFileAttributesExW(fileName, GetFileExInfoStandard, &attributes), GetLastError());
	memcpy(&file->lastWrite, &attributes.ftLastWriteTime, sizeof attributes.ftLastWriteTime);

	// create and normalize a copy of directory name and file name

	ErrorIf(0 != _wsplitpath_s(fileName, NULL, 0, NULL, 0, fileOnly, _MAX_FNAME, ext, _MAX_EXT), ERROR_INVALID_PARAMETER);	
	fileNameOnlyLength = wcslen(fileOnly) + wcslen(ext);	
	directoryLength = fileNameLength - fileNameOnlyLength; 
	ErrorIf(NULL == (directoryName = new WCHAR[directoryLength + 8]), ERROR_NOT_ENOUGH_MEMORY); // pessimistic length after normalization with prefix \\?\UNC\ 
	ErrorIf(NULL == (file->fileName = new WCHAR[fileNameLength + 1]), ERROR_NOT_ENOUGH_MEMORY);
	wcscpy(file->fileName, fileName);

	if (fileNameLength > 8 && 0 == memcmp(fileName, L"\\\\?\\UNC\\", 8 * sizeof WCHAR))
	{
		// normalized UNC path
		file->unc = TRUE;
		memcpy(directoryName, fileName, directoryLength * sizeof WCHAR);
		directoryName[directoryLength] = L'\0';
	}
	else if (fileNameLength > 4 && 0 == memcmp(fileName, L"\\\\?\\", 4 * sizeof WCHAR))
	{
		// normalized local file
		file->unc = FALSE;
		memcpy(directoryName, fileName, directoryLength * sizeof WCHAR);
		directoryName[directoryLength] = L'\0';
	}
	else if (fileNameLength > 2 && 0 == memcmp(fileName, L"\\\\", 2 * sizeof(WCHAR)))
	{
		// not normalized UNC path
		file->unc = TRUE;
		wcscpy(directoryName, L"\\\\?\\UNC\\");
		memcpy(directoryName + 8, fileName + 2, (directoryLength - 2) * sizeof WCHAR);
		directoryName[8 + directoryLength - 2] = L'\0';
	}
	else
	{
		// not normalized local file
		file->unc = FALSE;
		wcscpy(directoryName, L"\\\\?\\");
		memcpy(directoryName + 4, fileName, directoryLength * sizeof WCHAR);
		directoryName[4 + directoryLength] = L'\0';	
	}

	// find matching directory watcher entry

	directory = this->directories;
	while (NULL != directory)
	{
		if (0 == wcscmp(directory->directoryName, directoryName))
		{
			delete [] directoryName;
			directoryName = NULL;
			break;
		}

		directory = directory->next;
	}

	// if directory watcher not found, create one

	if (NULL == directory)
	{
		ErrorIf(NULL == (newDirectory = new WatchedDirectory), ERROR_NOT_ENOUGH_MEMORY);	
		RtlZeroMemory(newDirectory, sizeof WatchedDirectory);
		newDirectory->directoryName = directoryName;
		directoryName = NULL;
		newDirectory->files = file;

		ErrorIf(INVALID_HANDLE_VALUE == (newDirectory->watchHandle = CreateFileW(
			newDirectory->directoryName,           
			FILE_LIST_DIRECTORY,    
			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
			NULL, 
			OPEN_EXISTING,         
			FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
			NULL)),
			GetLastError());

		ErrorIf(NULL == CreateIoCompletionPort(newDirectory->watchHandle, this->completionPort, (ULONG_PTR)newDirectory, 0), 
			GetLastError());

		ErrorIf(0 == ReadDirectoryChangesW(
			newDirectory->watchHandle,
			&newDirectory->info,
			sizeof newDirectory->info,
			FALSE,
			FILE_NOTIFY_CHANGE_LAST_WRITE,
			NULL,
			&newDirectory->overlapped,
			NULL),
			GetLastError());

		if (NULL == this->directories)
		{
			// no watchers exist yet, start the watcher thread

			ErrorIf(NULL == (this->worker = (HANDLE)_beginthreadex(
				NULL, 
				4096, 
				CFileWatcher::Worker, 
				this, 
				0, 
				NULL)), 
				ERROR_NOT_ENOUGH_MEMORY);
		}

		newDirectory->next = this->directories;
		this->directories = newDirectory;
		newDirectory = NULL;
	}
	else
	{
		file->next = directory->files;
		directory->files = file;
		file = NULL;
	}

	return S_OK;
Error:

	if (NULL != newDirectory)
	{
		if (NULL != newDirectory->directoryName)
		{
			delete [] newDirectory->directoryName;
		}

		if (NULL != newDirectory->watchHandle)
		{
			CloseHandle(newDirectory->watchHandle);
		}

		delete newDirectory;
	}

	if (NULL != file)
	{
		delete [] file->fileName;
		delete file;
	}

	if (NULL != directoryName)
	{
		delete [] directoryName;
	}

	return hr;
}