Beispiel #1
0
/* ****************************************************************************
*
* getIPv6Port -
*/
bool getIPv6Port(std::string in, std::string& outIp, std::string& outPort)
{
   size_t pos; 
   std::string partip;
   std::string resu;
   std::string staux = in; 
   
   // Split IP and port
   pos = staux.find(":");  
   while (pos != std::string::npos)
   {
      partip = staux.substr(0, pos+1);
      resu += partip;
      partip = staux.substr(pos+1);
      staux = partip;
      pos = staux.find(":");
   }


   if (resu.empty())
      return false;

   outIp = resu.substr(0, resu.length() -1 );
   outPort = staux;

   return isIPv6(resu);
}
Beispiel #2
0
/* ****************************************************************************
*
* restInit - 
*
* FIXME P5: add vector of the accepted content-types, instead of the bool
*           See Issue #256
*/
void restInit
(
  RestService*        _restServiceV,
  IpVersion           _ipVersion,
  const char*         _bindAddress,
  unsigned short      _port,
  bool                _multitenant,
  unsigned int        _connectionMemory,
  unsigned int        _maxConnections,
  unsigned int        _mhdThreadPoolSize,
  const std::string&  _rushHost,
  unsigned short      _rushPort,
  const char*         _allowedOrigin,
  const char*         _httpsKey,
  const char*         _httpsCertificate,
  RestServeFunction   _serveFunction
)
{
  const char* key  = _httpsKey;
  const char* cert = _httpsCertificate;

  port             = _port;
  restServiceV     = _restServiceV;
  ipVersionUsed    = _ipVersion;
  serveFunction    = (_serveFunction != NULL)? _serveFunction : serve;  
  multitenant      = _multitenant;
  connMemory       = _connectionMemory;
  maxConns         = _maxConnections;
  threadPoolSize   = _mhdThreadPoolSize;
  rushHost         = _rushHost;
  rushPort         = _rushPort;

  strncpy(restAllowedOrigin, _allowedOrigin, sizeof(restAllowedOrigin));

  strncpy(bindIp, LOCAL_IP_V4, MAX_LEN_IP - 1);
  strncpy(bindIPv6, LOCAL_IP_V6, MAX_LEN_IP - 1);

  if (isIPv6(std::string(_bindAddress)))
  {
    strncpy(bindIPv6, _bindAddress, MAX_LEN_IP - 1);
  }
  else
  {
    strncpy(bindIp, _bindAddress, MAX_LEN_IP - 1);
  }

  // Starting REST interface
  int r;
  if ((r = restStart(_ipVersion, key, cert)) != 0)
  {
    fprintf(stderr, "restStart: error %d\n", r);
    orionExitFunction(1, "restStart: error");
  }
}
Beispiel #3
0
/* ****************************************************************************
*
* restInit - 
*
* FIXME P5: add vector of the accepted content-types, instead of the bool
*           argument _acceptTextXml that was added for iotAgent only.
*           See Issue #256
*/
void restInit
(
  RestService*        _restServiceV,
  IpVersion           _ipVersion,
  const char*         _bindAddress,
  unsigned short      _port,
  bool                _multitenant,
  const std::string&  _rushHost,
  unsigned short      _rushPort,
  const char*         _allowedOrigin,
  const char*         _httpsKey,
  const char*         _httpsCertificate,
  RestServeFunction   _serveFunction,
  bool                _acceptTextXml
)
{
  const char* key  = _httpsKey;
  const char* cert = _httpsCertificate;

  port          = _port;
  restServiceV  = _restServiceV;
  ipVersionUsed = _ipVersion;
  serveFunction = (_serveFunction != NULL)? _serveFunction : serve;
  acceptTextXml = _acceptTextXml;
  multitenant   = _multitenant;
  rushHost      = _rushHost;
  rushPort      = _rushPort;

  strncpy(restAllowedOrigin, _allowedOrigin, sizeof(restAllowedOrigin));

  strncpy(bindIp, LOCAL_IP_V4, MAX_LEN_IP - 1);
  strncpy(bindIPv6, LOCAL_IP_V6, MAX_LEN_IP - 1);

  if (isIPv6(std::string(_bindAddress)))
    strncpy(bindIPv6, _bindAddress, MAX_LEN_IP - 1);
  else
    strncpy(bindIp, _bindAddress, MAX_LEN_IP - 1);

  if ((_ipVersion == IPV4) || (_ipVersion == IPDUAL))
     strncpy(bindIp, bindIp, MAX_LEN_IP - 1);

  if ((_ipVersion == IPV6) || (_ipVersion == IPDUAL))
     strncpy(bindIPv6, bindIPv6, MAX_LEN_IP - 1);

  // Starting REST interface
  int r;
  if ((r = restStart(_ipVersion, key, cert)) != 0)
  {
    fprintf(stderr, "restStart: error %d\n", r);
    orionExitFunction(1, "restStart: error");
  }
}
Beispiel #4
0
QString KviIrcServer::ircUri()
{
	QString szUri("irc");
	if(useSSL())
		szUri += "s";
	if(isIPv6())
		szUri += "6";
	szUri += "://";
	szUri += m_szHostname;

	if(m_uPort != 6667)
	{
		szUri += ":";
		QString szNum;
		szNum.setNum(m_uPort);
		szUri += szNum;
	}
	return szUri;
}
Beispiel #5
0
result_t net_base::isIP(exlib::string ip, int32_t& retVal)
{
    retVal = 0;
    bool is = false;

    isIPv4(ip, is);

    if (is) {
        retVal = 4;
        return 0;
    }

    isIPv6(ip, is);

    if (is)
        retVal = 6;

    return 0;
}
/* ****************************************************************************
*
* httpRequestSendWithCurl -
*
* The waitForResponse arguments specifies if the method has to wait for response
* before return. If this argument is false, the return string is ""
*
* NOTE
* We are using a hybrid approach, consisting in a static thread-local buffer of a
* small size that copes with most notifications to avoid expensive
* calloc/free syscalls if the notification payload is not very large.
*
* RETURN VALUES
*   httpRequestSendWithCurl returns 0 on success and a negative number on failure:
*     -1: Invalid port
*     -2: Invalid IP
*     -3: Invalid verb
*     -4: Invalid resource
*     -5: No Content-Type BUT content present
*     -6: Content-Type present but there is no content
*     -7: Total outgoing message size is too big
*     -9: Error making HTTP request
*/
int httpRequestSendWithCurl
(
   CURL                   *curl,
   const std::string&     _ip,
   unsigned short         port,
   const std::string&     protocol,
   const std::string&     verb,
   const std::string&     tenant,
   const std::string&     servicePath,
   const std::string&     xauthToken,
   const std::string&     resource,
   const std::string&     orig_content_type,
   const std::string&     content,
   const std::string&     fiwareCorrelation,
   const std::string&     ngisv2AttrFormat,
   bool                   useRush,
   bool                   waitForResponse,
   std::string*           outP,
   const std::string&     acceptFormat,
   long                   timeoutInMilliseconds
)
{
  char                       portAsString[STRING_SIZE_FOR_INT];
  static unsigned long long  callNo             = 0;
  std::string                result;
  std::string                ip                 = _ip;
  struct curl_slist*         headers            = NULL;
  MemoryStruct*              httpResponse       = NULL;
  CURLcode                   res;
  int                        outgoingMsgSize       = 0;
  std::string                content_type(orig_content_type);

  ++callNo;

  // For content-type application/json we add charset=utf-8
  if (orig_content_type == "application/json")
  {
    content_type += "; charset=utf-8";
  }

  if (timeoutInMilliseconds == -1)
  {
    timeoutInMilliseconds = defaultTimeout;
  }

  lmTransactionStart("to", ip.c_str(), port, resource.c_str());

  // Preconditions check
  if (port == 0)
  {
    LM_E(("Runtime Error (port is ZERO)"));
    lmTransactionEnd();

    *outP = "error";
    return -1;
  }

  if (ip.empty())
  {
    LM_E(("Runtime Error (ip is empty)"));
    lmTransactionEnd();

    *outP = "error";
    return -2;
  }

  if (verb.empty())
  {
    LM_E(("Runtime Error (verb is empty)"));
    lmTransactionEnd();

    *outP = "error";
    return -3;
  }

  if (resource.empty())
  {
    LM_E(("Runtime Error (resource is empty)"));
    lmTransactionEnd();

    *outP = "error";
    return -4;
  }

  if ((content_type.empty()) && (!content.empty()))
  {
    LM_E(("Runtime Error (Content-Type is empty but there is actual content)"));
    lmTransactionEnd();

    *outP = "error";
    return -5;
  }

  if ((!content_type.empty()) && (content.empty()))
  {
    LM_E(("Runtime Error (Content-Type non-empty but there is no content)"));
    lmTransactionEnd();

    *outP = "error";
    return -6;
  }



  // Allocate to hold HTTP response
  httpResponse = new MemoryStruct;
  httpResponse->memory = (char*) malloc(1); // will grow as needed
  httpResponse->size = 0; // no data at this point

  //
  // Rush
  // Every call to httpRequestSend specifies whether RUSH should be used or not.
  // But, this depends also on how the broker was started, so here the 'useRush'
  // parameter is cancelled in case the broker was started without rush.
  //
  // If rush is to be used, the IP/port is stored in rushHeaderIP/rushHeaderPort and
  // after that, the host and port of rush is set as ip/port for the message, that is
  // now sent to rush instead of to its final destination.
  // Also, a few HTTP headers for rush must be setup.
  //
  if ((rushPort == 0) || (rushHost == ""))
  {
    useRush = false;
  }

  if (useRush)
  {
    char         rushHeaderPortAsString[STRING_SIZE_FOR_INT];
    uint16_t     rushHeaderPort     = port;
    std::string  rushHeaderIP       = ip;
    std::string  headerRushHttp;

    ip    = rushHost;
    port  = rushPort;

    snprintf(rushHeaderPortAsString, sizeof(rushHeaderPortAsString), "%d", rushHeaderPort);
    headerRushHttp = "X-relayer-host: " + rushHeaderIP + ":" + rushHeaderPortAsString;
    LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerRushHttp.c_str()));
    headers = curl_slist_append(headers, headerRushHttp.c_str());
    outgoingMsgSize += headerRushHttp.size();

    if (protocol == "https:")
    {
      headerRushHttp = "X-relayer-protocol: https";
      LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerRushHttp.c_str()));
      headers = curl_slist_append(headers, headerRushHttp.c_str());
      outgoingMsgSize += headerRushHttp.size();
    }
  }

  snprintf(portAsString, sizeof(portAsString), "%u", port);

  // ----- User Agent
  char cvBuf[CURL_VERSION_MAX_LENGTH];
  char headerUserAgent[HTTP_HEADER_USER_AGENT_MAX_LENGTH];

  snprintf(headerUserAgent, sizeof(headerUserAgent), "User-Agent: orion/%s libcurl/%s", versionGet(), curlVersionGet(cvBuf, sizeof(cvBuf)));
  LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerUserAgent));
  headers = curl_slist_append(headers, headerUserAgent);
  outgoingMsgSize += strlen(headerUserAgent) + 1;

  // ----- Host
  char headerHost[HTTP_HEADER_HOST_MAX_LENGTH];

  snprintf(headerHost, sizeof(headerHost), "Host: %s:%d", ip.c_str(), (int) port);
  LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerHost));
  headers = curl_slist_append(headers, headerHost);
  outgoingMsgSize += strlen(headerHost) + 1;

  // ----- Tenant
  if (tenant != "")
  {
    headers = curl_slist_append(headers, ("fiware-service: " + tenant).c_str());
    outgoingMsgSize += tenant.size() + 16; // "fiware-service: "
  }

  // ----- Service-Path
  if (servicePath != "")
  {
    headers = curl_slist_append(headers, ("Fiware-ServicePath: " + servicePath).c_str());
    outgoingMsgSize += servicePath.size() + strlen("Fiware-ServicePath: ");
  }

  // ----- X-Auth-Token
  if (xauthToken != "")
  {
    headers = curl_slist_append(headers, ("X-Auth-Token: " + xauthToken).c_str());
    outgoingMsgSize += xauthToken.size() + strlen("X-Auth-Token: ");
  }

  // ----- Accept
  std::string acceptedFormats = "application/json";
  if (acceptFormat != "")
  {
    acceptedFormats = acceptFormat;
  }

  std::string acceptString = "Accept: " + acceptedFormats;
  headers = curl_slist_append(headers, acceptString.c_str());
  outgoingMsgSize += acceptString.size();

  // ----- Expect
  headers = curl_slist_append(headers, "Expect: ");
  outgoingMsgSize += 8; // from "Expect: "

  // ----- Content-length
  std::stringstream contentLengthStringStream;
  contentLengthStringStream << content.size();
  std::string headerContentLength = "Content-length: " + contentLengthStringStream.str();
  LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerContentLength.c_str()));
  headers = curl_slist_append(headers, headerContentLength.c_str());
  outgoingMsgSize += contentLengthStringStream.str().size() + 16; // from "Content-length: "
  outgoingMsgSize += content.size();

  // ----- Content-type
  headers = curl_slist_append(headers, ("Content-type: " + content_type).c_str());
  outgoingMsgSize += content_type.size() + 14; // from "Content-type: "

  // Fiware-Correlator
  std::string correlation = "Fiware-Correlator: " + fiwareCorrelation;
  headers = curl_slist_append(headers, correlation.c_str());
  outgoingMsgSize += correlation.size();

  // Notify Format
  if ((ngisv2AttrFormat != "") && (ngisv2AttrFormat != "JSON") && (ngisv2AttrFormat != "legacy"))
  {
    std::string nFormat = "X-Ngsiv2-AttrsFormat: " + ngisv2AttrFormat;
    headers = curl_slist_append(headers, nFormat.c_str());
    outgoingMsgSize += nFormat.size();
  }

  // Check if total outgoing message size is too big
  if (outgoingMsgSize > MAX_DYN_MSG_SIZE)
  {
    LM_E(("Runtime Error (HTTP request to send is too large: %d bytes)", outgoingMsgSize));

    curl_slist_free_all(headers);

    free(httpResponse->memory);
    delete httpResponse;

    lmTransactionEnd();
    *outP = "error";
    return -7;
  }

  // Contents
  const char* payload = content.c_str();
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (u_int8_t*) payload);

  // Set up URL
  std::string url;
  if (isIPv6(ip))
    url = "[" + ip + "]";
  else
    url = ip;
  url = url + ":" + portAsString + (resource.at(0) == '/'? "" : "/") + resource;

  // Prepare CURL handle with obtained options
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb.c_str()); // Set HTTP verb
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Allow redirection (?)
  curl_easy_setopt(curl, CURLOPT_HEADER, 1); // Activate include the header in the body output
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Put headers in place
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeMemoryCallback); // Send data here
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*) httpResponse); // Custom data for response handling

  //
  // There is a known problem in libcurl (see http://stackoverflow.com/questions/9191668/error-longjmp-causes-uninitialized-stack-frame)
  // which is solved using CURLOPT_NOSIGNAL. If we update some day from libcurl 7.19 (the one that comes with CentOS 6.x) to a newer version
  // (there are some reports about the bug is no longer in libcurl 7.32), using CURLOPT_NOSIGNAL could be not necessary and this be removed).
  // See issue #1016 for more details.
  //
  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

  //
  // Timeout 
  //
  // The parameter timeoutInMilliseconds holds the timeout time in milliseconds.
  // If the timeout time requested is 0, then no timeuot is used.
  //
  if (timeoutInMilliseconds != 0) 
  {
    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeoutInMilliseconds);
  }


  // Synchronous HTTP request
  // This was previously a LM_T trace, but we have "promoted" it to INFO due to it is needed to check logs in a .test case (case 000 notification_different_sizes.test)
  LM_I(("Sending message %lu to HTTP server: sending message of %d bytes to HTTP server", callNo, outgoingMsgSize));
  res = curl_easy_perform(curl);

  if (res != CURLE_OK)
  {
    //
    // NOTE: This log line is used by the functional tests in cases/880_timeout_for_forward_and_notifications/
    //       So, this line should not be removed/altered, at least not without also modifying the functests.
    //    
    alarmMgr.notificationError(url, "(curl_easy_perform failed: " + std::string(curl_easy_strerror(res)) + ")");
    *outP = "notification failure";
  }
  else
  {
    // The Response is here
    LM_I(("Notification Successfully Sent to %s", url.c_str()));
    outP->assign(httpResponse->memory, httpResponse->size);
  }

  // Cleanup curl environment

  curl_slist_free_all(headers);

  free(httpResponse->memory);
  delete httpResponse;

  lmTransactionEnd();

  return res == CURLE_OK ? 0 : -9;
}
Beispiel #7
0
 //---------------------------------------------------------------------------
 // IP V6 clear is '::' (all 128 bits zeroed)
 // IP V4 clear is 0000 0000 0000 0000 00000 FFFF 0000 0000 ( '::FFFF:0:0' )
 bool IPAddress::isAddrAny() const
 {
   if (isIPv6()) return isAddressEqual(anyV6());
   return isAddressEqualIgnoringIPv4Format(anyV4());
 }
Beispiel #8
0
void KviIrcServer::save(KviConfigurationFile * pCfg, const QString & szPrefix)
{
	QString szTmp;
	szTmp = QString("%1Hostname").arg(szPrefix);
	pCfg->writeEntry(szTmp,m_szHostname);
	szTmp = QString("%1Id").arg(szPrefix);
	pCfg->writeEntry(szTmp,m_szId);
	if(!m_szIp.isEmpty())
	{
		szTmp = QString("%1Ip").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szIp);
	}
	if(!m_szDescription.isEmpty())
	{
		szTmp = QString("%1Description").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szDescription);
	}
	if(!m_szUser.isEmpty())
	{
		szTmp = QString("%1User").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szUser);
	}
	if(!m_szPass.isEmpty())
	{
		szTmp = QString("%1Pass").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szPass);
	}
	if(!m_szNick.isEmpty())
	{
		szTmp = QString("%1Nick").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szNick);
	}
	if(!m_szAlternativeNick.isEmpty())
	{
		szTmp = QString("%1AlternativeNick").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szAlternativeNick);
	}
	if(!m_szSaslPass.isEmpty())
	{
		szTmp = QString("%1SaslPass").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szSaslPass);
	}
	if(!m_szSaslNick.isEmpty())
	{
		szTmp = QString("%1SaslNick").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szSaslNick);
	}
	if(!m_szRealName.isEmpty())
	{
		szTmp = QString("%1RealName").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szRealName);
	}
	if(!m_szInitUMode.isEmpty())
	{
		szTmp = QString("%1InitUMode").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szInitUMode);
	}
	if(autoJoinChannelList())
	{
		szTmp = QString("%1AutoJoinChannels").arg(szPrefix);
		pCfg->writeEntry(szTmp,*(autoJoinChannelList()));
	}
	if(autoConnect()) // otherwise it defaults to false anyway
	{
		szTmp = QString("%1AutoConnect").arg(szPrefix);
		pCfg->writeEntry(szTmp,autoConnect());
	}
	if(!m_szEncoding.isEmpty())
	{
		szTmp = QString("%1Encoding").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szEncoding);
	}
	if(!m_szTextEncoding.isEmpty())
	{
		szTmp = QString("%1TextEncoding").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szTextEncoding);
	}
	if(!m_szOnConnectCommand.isEmpty())
	{
		szTmp = QString("%1OnConnectCommand").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szOnConnectCommand);
	}
	if(!m_szOnLoginCommand.isEmpty())
	{
		szTmp = QString("%1OnLoginCommand").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szOnLoginCommand);
	}
	if(!m_szLinkFilter.isEmpty())
	{
		szTmp = QString("%1LinkFilter").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szLinkFilter);
	}
	if(m_uPort != 6667)
	{
		szTmp = QString("%1Port").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_uPort);
	}
	if(isIPv6())
	{
		szTmp = QString("%1IPv6").arg(szPrefix);
		pCfg->writeEntry(szTmp,isIPv6());
	}
	if(cacheIp())
	{
		szTmp = QString("%1CacheIp").arg(szPrefix);
		pCfg->writeEntry(szTmp,cacheIp());
	}
	if(useSSL())
	{
		szTmp = QString("%1SSL").arg(szPrefix);
		pCfg->writeEntry(szTmp,useSSL());
	}
	if(!enabledCAP())
	{
		szTmp = QString("%1EnabledCAP").arg(szPrefix);
		pCfg->writeEntry(szTmp,enabledCAP());
	}
	if(!enabledSTARTTLS())
	{
		szTmp = QString("%1EnabledSTARTTLS").arg(szPrefix);
		pCfg->writeEntry(szTmp,enabledSTARTTLS());
	}
	if(enabledSASL())
	{
		szTmp = QString("%1EnabledSASL").arg(szPrefix);
		pCfg->writeEntry(szTmp,enabledSASL());
	}
	if(proxy()!=-2)
	{
		szTmp = QString("%1Proxy").arg(szPrefix);
		pCfg->writeEntry(szTmp,proxy());
	}
	if(!m_szUserIdentityId.isEmpty())
	{
		szTmp = QString("%1UserIdentityId").arg(szPrefix);
		pCfg->writeEntry(szTmp,m_szUserIdentityId);
	}
	if(favorite())
	{
		szTmp = QString("%1Favorite").arg(szPrefix);
		pCfg->writeEntry(szTmp,favorite());
	}
}
/* ****************************************************************************
*
* httpRequestSend -
*/
std::string httpRequestSend
(
   const std::string&     _ip,
   unsigned short         port,
   const std::string&     protocol,
   const std::string&     verb,
   const std::string&     tenant,
   const std::string&     servicePath,
   const std::string&     xauthToken,
   const std::string&     resource,
   const std::string&     content_type,
   const std::string&     content,
   bool                   useRush,
   bool                   waitForResponse,
   const std::string&     acceptFormat,
   long                   timeoutInMilliseconds
)
{
  char                       portAsString[16];
  static unsigned long long  callNo             = 0;
  std::string                result;
  std::string                ip                 = _ip;
  struct curl_slist*         headers            = NULL;
  MemoryStruct*              httpResponse       = NULL;
  CURLcode                   res;
  int                        outgoingMsgSize       = 0;
  CURL*                      curl;

  ++callNo;

  if (timeoutInMilliseconds == -1)
  {
    timeoutInMilliseconds = defaultTimeout;
  }

  LM_TRANSACTION_START("to", ip.c_str(), port, resource.c_str());

  // Preconditions check
  if (port == 0)
  {
    LM_E(("Runtime Error (port is ZERO)"));
    LM_TRANSACTION_END();
    return "error";
  }

  if (ip.empty())
  {
    LM_E(("Runtime Error (ip is empty)"));
    LM_TRANSACTION_END();
    return "error";
  }

  if (verb.empty())
  {
    LM_E(("Runtime Error (verb is empty)"));
    LM_TRANSACTION_END();
    return "error";
  }

  if (resource.empty())
  {
    LM_E(("Runtime Error (resource is empty)"));
    LM_TRANSACTION_END();
    return "error";
  }

  if ((content_type.empty()) && (!content.empty()))
  {
    LM_E(("Runtime Error (Content-Type is empty but there is actual content)"));
    LM_TRANSACTION_END();
    return "error";
  }

  if ((!content_type.empty()) && (content.empty()))
  {
    LM_E(("Runtime Error (Content-Type non-empty but there is no content)"));
    LM_TRANSACTION_END();
    return "error";
  }

  if ((curl = curl_easy_init()) == NULL)
  {
    LM_E(("Runtime Error (could not init libcurl)"));
    LM_TRANSACTION_END();
    return "error";
  }


  // Allocate to hold HTTP response
  httpResponse = new MemoryStruct;
  httpResponse->memory = (char*) malloc(1); // will grow as needed
  httpResponse->size = 0; // no data at this point

  //
  // Rush
  // Every call to httpRequestSend specifies whether RUSH should be used or not.
  // But, this depends also on how the broker was started, so here the 'useRush'
  // parameter is cancelled in case the broker was started without rush.
  //
  // If rush is to be used, the IP/port is stored in rushHeaderIP/rushHeaderPort and
  // after that, the host and port of rush is set as ip/port for the message, that is
  // now sent to rush instead of to its final destination.
  // Also, a few HTTP headers for rush must be setup.
  //
  if ((rushPort == 0) || (rushHost == ""))
    useRush = false;

  if (useRush)
  {
    char         rushHeaderPortAsString[16];
    uint16_t     rushHeaderPort     = 0;
    std::string  rushHeaderIP       = "";
    std::string  headerRushHttp     = "";

    rushHeaderIP   = ip;
    rushHeaderPort = port;
    ip             = rushHost;
    port           = rushPort;

    snprintf(rushHeaderPortAsString, sizeof(rushHeaderPortAsString), "%d", rushHeaderPort);
    headerRushHttp = "X-relayer-host: " + rushHeaderIP + ":" + rushHeaderPortAsString;
    LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerRushHttp.c_str()));
    headers = curl_slist_append(headers, headerRushHttp.c_str());
    outgoingMsgSize += headerRushHttp.size();

    if (protocol == "https:")
    {
      headerRushHttp = "X-relayer-protocol: https";
      LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerRushHttp.c_str()));
      headers = curl_slist_append(headers, headerRushHttp.c_str());
      outgoingMsgSize += headerRushHttp.size();
    }
  }

  snprintf(portAsString, sizeof(portAsString), "%d", port);

  // ----- User Agent
  char cvBuf[CURL_VERSION_MAX_LENGTH];
  char headerUserAgent[HTTP_HEADER_USER_AGENT_MAX_LENGTH];

  snprintf(headerUserAgent, sizeof(headerUserAgent), "User-Agent: orion/%s libcurl/%s", versionGet(), curlVersionGet(cvBuf, sizeof(cvBuf)));
  LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerUserAgent));
  headers = curl_slist_append(headers, headerUserAgent);
  outgoingMsgSize += strlen(headerUserAgent) + 1;

  // ----- Host
  char headerHost[HTTP_HEADER_HOST_MAX_LENGTH];

  snprintf(headerHost, sizeof(headerHost), "Host: %s:%d", ip.c_str(), (int) port);
  LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerHost));
  headers = curl_slist_append(headers, headerHost);
  outgoingMsgSize += strlen(headerHost) + 1;

  // ----- Tenant
  if (tenant != "")
  {
    headers = curl_slist_append(headers, ("fiware-service: " + tenant).c_str());
    outgoingMsgSize += tenant.size() + 16; // "fiware-service: "
  }

  // ----- Service-Path
  if (servicePath != "")
  {
    headers = curl_slist_append(headers, ("Fiware-ServicePath: " + servicePath).c_str());
    outgoingMsgSize += servicePath.size() + strlen("Fiware-ServicePath: ");
  }

  // ----- X-Auth-Token
  if (xauthToken != "")
  {
    headers = curl_slist_append(headers, ("X-Auth-Token: " + xauthToken).c_str());
    outgoingMsgSize += xauthToken.size() + strlen("X-Auth-Token: ");
  }

  // ----- Accept
  std::string acceptedFormats = "application/xml, application/json";
  if (acceptFormat != "")
  {
    acceptedFormats = acceptFormat;
  }

  std::string acceptString = "Accept: " + acceptedFormats;
  headers = curl_slist_append(headers, acceptString.c_str());
  outgoingMsgSize += acceptString.size();

  // ----- Expect
  headers = curl_slist_append(headers, "Expect: ");
  outgoingMsgSize += 8; // from "Expect: "

  // ----- Content-length
  std::stringstream contentLengthStringStream;
  contentLengthStringStream << content.size();
  std::string headerContentLength = "Content-length: " + contentLengthStringStream.str();
  LM_T(LmtHttpHeaders, ("HTTP-HEADERS: '%s'", headerContentLength.c_str()));
  headers = curl_slist_append(headers, headerContentLength.c_str());
  outgoingMsgSize += contentLengthStringStream.str().size() + 16; // from "Content-length: "
  outgoingMsgSize += content.size();

  // ----- Content-type
  headers = curl_slist_append(headers, ("Content-type: " + content_type).c_str());
  outgoingMsgSize += content_type.size() + 14; // from "Content-type: "


  // Check if total outgoing message size is too big
  if (outgoingMsgSize > MAX_DYN_MSG_SIZE)
  {
    LM_E(("Runtime Error (HTTP request to send is too large: %d bytes)", outgoingMsgSize));

    // Cleanup curl environment
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);

    free(httpResponse->memory);
    delete httpResponse;

    LM_TRANSACTION_END();
    return "error";
  }

  // Contents
  const char* payload = content.c_str();
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (u_int8_t*) payload);

  // Set up URL
  std::string url;
  if (isIPv6(ip))
    url = "[" + ip + "]";
  else
    url = ip;
  url = url + ":" + portAsString + (resource.at(0) == '/'? "" : "/") + resource;

  // Prepare CURL handle with obtained options
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb.c_str()); // Set HTTP verb
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Allow redirection (?)
  curl_easy_setopt(curl, CURLOPT_HEADER, 1); // Activate include the header in the body output
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Put headers in place
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeMemoryCallback); // Send data here
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*) httpResponse); // Custom data for response handling

  //
  // Timeout 
  //
  // The parameter timeoutInMilliseconds holds the timeout time in milliseconds.
  // If the timeout time requested is 0, then no timeuot is used.
  //
  if (timeoutInMilliseconds != 0) 
  {
    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeoutInMilliseconds);
  }


  // Synchronous HTTP request
  LM_T(LmtClientOutputPayload, ("Sending message %lu to HTTP server: sending message of %d bytes to HTTP server", callNo, outgoingMsgSize));
  res = curl_easy_perform(curl);

  if (res != CURLE_OK)
  {
    //
    // NOTE: This log line is used by the functional tests in cases/880_timeout_for_forward_and_notifications/
    //       So, this line should not be removed/altered, at least not without also modifying the functests.
    //
    LM_W(("Notification failure for %s:%s (curl_easy_perform failed: %s)", ip.c_str(), portAsString, curl_easy_strerror(res)));
    result = "";
  }
  else
  {
    // The Response is here
    LM_I(("Notification Successfully Sent to %s", url.c_str()));
    result.assign(httpResponse->memory, httpResponse->size);
  }

  // Cleanup curl environment
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);

  free(httpResponse->memory);
  delete httpResponse;

  LM_TRANSACTION_END();

  return result;
}