+ Start a Discussion
Tamás SomogyiTamás Somogyi 

CTI adapter: Http Send Request error with automatic proxy configuration

Hi,

I'm creating a CTI Adapter based on the Demo Adapter in CTI Toolkit 4.03 and noticed that it doesn't support automatic proxy configuration: the Softphone in IE/Chrome cannot even connect to the adapter!

To bypass this issue I call Chrome with explicit proxy settings (--proxy-server=x.x.x.x:x --proxy-bypass-list=localhost) and also added System.Net.WebProxy to Reference.cs\SforceService.
So now they can connect, but I'm still getting the below error in cti_connector.log:

05/20/2014 08:48:12: CCTIAppExchange::SetSessionInstanceAndSid: Error setting instance and SID.  Http Send Request
Win32Error::
The system cannot find message text for message number 0x%1 in the message file for %2.
05/20/2014 08:48:12: CCTIAppExchange::SetSessionInstanceAndSid: COM Error: Http Send Request
Win32Error::
The system cannot find message text for message number 0x%1 in the message file for %2.
05/20/2014 08:48:12: CCTIAppExchange::UpdateSid: Unable to get user ID.  Error message: Http Send Request
Win32Error::
The system cannot find message text for message number 0x%1 in the message file for %2.
.


and also

05/20/2014 11:31:24: CCTIAppExchange::SetSessionInstanceAndSid: Error setting instance and SID.  SFWinInet::Send::HttpSendRequestEx
Win32Error::
The operation timed out
05/20/2014 11:31:58: CCTIAppExchange::SetSessionInstanceAndSid: Error setting instance and SID.  SFWinInet::Send::HttpSendRequestEx
Win32Error::
The operation timed out


The exception occurs in CCTIAppExchange::SetSessionInstanceAndSid when calling pSession->SessionId=CCTIUtils::StringToBSTR(sSid).
It calls SF_MSApi4.dll that probably cannot cope with proxy script.
I've also tried to use pSession->SetProxyInfo but it didn't make any difference.

If I set the proxy server manually in Internet Options->Connections->LAN Settings, then everything works fine.
But in our production environment, the policy is to use automatic configuration script (PAC), so I'm not allowed
to manually set the proxy server.

Can you please suggest any solution or workaround?

Thanks in advance!
Tamás SomogyiTamás Somogyi
I've found a workaround by setting proxy server for LAN Settings programmatically.
In CCTIAppExchange::SetSessionInstanceAndSid, before setting pSession->SessionId:
1) auto-detect the proxy by ::WinHttpGetProxyForUrl
2) set the proxy for Internet Settings by ::InternetSetOption - this does the trick!
3) set the same proxy in pSession->SetProxyInfo

Would be nice to have a similar solution in the next version of CTI Toolkit as I feel this is a bug in CTIAppexchange.cpp and in CTIUtils.cpp.
JamesHoldcroftJamesHoldcroft
Tamás,

Thanks for posting your work-around.  What exactly were the changes that you made to CTIAppexchange.cpp?

James.
Tamás SomogyiTamás Somogyi

James, in CTIAppExchange:

void CCTIAppExchange::SetSessionInstanceAndSid(ISForceSession4Ptr pSession, std::wstring sInstance, std::wstring sSid)
{
 std::wstring sURL = sInstance+CCTIConstants::API_SUBPATH;

 try {
  std::wstring sCurrentUrl = CCTIUtils::BSTRToString(pSession->GetServerUrl());
  std::wstring sCurrentSid = CCTIUtils::BSTRToString(pSession->GetSessionId());

  if (sCurrentUrl!=sURL) {
   pSession->SetServerUrl(CCTIUtils::StringToBSTR(sURL));
   CCTILogger::Log(LOGLEVEL_MED,L"CCTIAppExchange::SetSessionInstanceAndSid: Setting URL to %s",sURL);
  }

  //Pseudo code -->
  //detect proxy
  if (DetectProxy(sURL, proxy, proxyBypass) && !proxy.empty()) {
   if (proxyBypass.empty())
    proxyBypass = L"local";

   //get current options
   InternetQueryOption(Option)

   //update internet options with detected proxy info
   Option[2].Value.dwValue |= PROXY_TYPE_PROXY;
   Option[3].Value.pszValue = proxyBypass;
   Option[4].Value.pszValue = proxy;

   InternetSetOption(Option)
  }
  //<--

  if (sCurrentSid!=sSid) {
   pSession->SessionId = CCTIUtils::StringToBSTR(sSid);
   CCTILogger::Log(LOGLEVEL_MED,L"CCTIAppExchange::SetSessionInstanceAndSid: Setting SID to %s",sSid);
  }

 } catch (_com_error& ce) {
  CCTILogger::Log(LOGLEVEL_MED,L"CCTIAppExchange::SetSessionInstanceAndSid: Error setting instance and SID.  %s",pSession->GetErrorMessage());    
 
        if (CCTIUtils::BSTRToString(pSession->GetErrorMessage()).find(L"API is not enabled for this Organization or Partner")!=std::wstring::npos) {
   throw ce;
  }
    }
}

Where DetectProxy is the same as CTIUtils::GetAutoProxySettings, except that I removed the call to WinHttpGetIEProxyConfigForCurrentUser from the beginning, so it doesn't check IEConfig.fAutoDetect either - i.e. it always detects the proxy even if auto-detection is not selected.

InternetQueryOption looks like this (see also MSDN):

INTERNET_PER_CONN_OPTION_LIST    List;
 INTERNET_PER_CONN_OPTION         Option[5];
 unsigned long                    nSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);

 Option[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
 Option[1].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS;
 Option[2].dwOption = INTERNET_PER_CONN_FLAGS;
 Option[3].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
 Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER;

 List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
 List.pszConnection = NULL;
 List.dwOptionCount = 5;
 List.dwOptionError = 0;
 List.pOptions = Option;

 //run the query
 ::InternetQueryOption(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize);
And finally, InternetSetOption updates the internet settings with the detected proxy configuration.
::InternetSetOption(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, nSize)
Note you need to add error handling, variable declaration, memory disposal, logging, etc. that I removed for better illustration of the logic.

Hope this helps,
Tamas