Exemplo n.º 1
0
/**
 * Open a socket connection to the proxy server
 * @param serverName Name of the server, i.e. "localhost"
 * @param port Port number to connect with, i.e. DEFAULT_PROXY_PORT
 */
error_t clientsocket_open(const char *serverName, int port) {
  struct sockaddr_in serverAddress;
  struct hostent *server;

  assert(serverName);

  SYSLOG_INFO("Attempting to open socket to %s on port %d", serverName, port);

  gTerminate = false;

  socketFd = socket(AF_INET, SOCK_STREAM, 0);
  if ((socketFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    SYSLOG_ERR("ERROR opening socket");
    return -1;
  }

  if ((server = gethostbyname(serverName)) == NULL) {
    SYSLOG_ERR("ERROR, no such host\n");
    return -1;
  }

  bzero((char *) &serverAddress, sizeof(serverAddress));
  serverAddress.sin_family = AF_INET;
  memcpy((char *) server->h_addr, (char *) &serverAddress.sin_addr.s_addr, server->h_length);
  serverAddress.sin_port = htons(port);

  SYSLOG_INFO("Connecting...");
  if (connect(socketFd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
    SYSLOG_ERR("ERROR connecting");
    return FAIL;
  }

  SYSLOG_INFO("Connection established on fd %d", socketFd);

  // Initialize the thread
  pthread_attr_init(&sThreadAttr);

  // Will run detached from the main dispatcher thread
  pthread_attr_setdetachstate(&sThreadAttr, PTHREAD_CREATE_DETACHED);

  // Round robin schedule is fine when processing is extremely low
  pthread_attr_setschedpolicy(&sThreadAttr, SCHED_RR);

  // Create the thread
  if (pthread_create(&sThreadId, &sThreadAttr, &_clientCommThread, NULL)) {
    SYSLOG_ERR("Creating proxy thread failed: %s", strerror(errno));
    clientsocket_close();
    return FAIL;
  }

  return SUCCESS;
}
Exemplo n.º 2
0
/**
 * @brief   Called when creating a curl data structure that will be shared across different
 *              http connections. DNS caching data is such data structure.
 *
 * @param   curlShHandle: pointer to a CURLSH structure that will be instantiated by curl_share_init
 *
 * @return  none
 **/
void libhttpcomm_curlShareInit(CURLSH *curlShHandle)
{
    curlShHandle = curl_share_init();

    if (curlShHandle != NULL)
    {
        if(curl_share_setopt(curlShHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS) != CURLSHE_OK)
        {
            SYSLOG_ERR("curl_easy_setopt CURLSHOPT_SHARE");
        }
    }else
    {
        SYSLOG_ERR("curl_share_init");
    }
}
Exemplo n.º 3
0
/**
 * Parse the characters found as the value of an XML tag
 */
static void _login_xml_charactersHandler(void *ctx, const xmlChar *ch, int len) {
  int i;
  char output[API_KEY_LENGTH];
  login_info_t *loginInfo = (login_info_t *) ctx;

  if (len > 0 && len < API_KEY_LENGTH) {
    for (i = 0; i < len; i++) {
      //if not equal a LF, CR store the character
      if ((ch[i] != 10) && (ch[i] != 13)) {
        output[i] = ch[i];
      }
    }
    output[i] = '\0';

    if (strcmp(loginInfo->xmlTag, "keyExpire") == 0) {
      // Tag is ok, but do nothing

    } else if (strcmp(loginInfo->xmlTag, "resultCode") == 0) {
      loginInfo->resultCode = atoi(output);

    } else if (strcmp(loginInfo->xmlTag, "key") == 0) {
      snprintf(apiKey, sizeof(apiKey), "%s", output);
      libconfigio_write(proxycli_getConfigFilename(), CONFIGIO_API_KEY, apiKey);
    } else {
      SYSLOG_DEBUG("Login does not support XML tag %s", loginInfo->xmlTag);
    }

  } else {
    SYSLOG_ERR("Received an XML value that is too long to parse");
  }
}
Exemplo n.º 4
0
/**********************************************************************************************//**
 * @brief   Called when a message has to be received from the server. this is a standard streamer
 *              if the size of the data to read, equal to size*nmemb, the function can return
 *              what was read and the function will be called again by libcurl.
 *
 * @param   ptr: where the received message resides
 * @param   size: size*nmemb == number of bytes to read
 * @param   nmemb: size*nmemb == number of bytes to read
 * @param   userp: ptr to where the message will be written -> inputted by CURLOPT_WRITEDATA call below
 *
 * @return  number of bytes that were written
 ***************************************************************************************************/
static size_t writer(void *ptr, size_t size, size_t nmemb, void *userp)
{
    struct HttpIoInfo *dataToRead = (struct HttpIoInfo *) userp;
    char *data = (char *)ptr;

    if (dataToRead == NULL || dataToRead->buffer == NULL)
    {
        SYSLOG_ERR ("dataToRead == NULL");
        return 0;
    }

    // keeping one byte for the null byte
    if((strlen(dataToRead->buffer)+(size * nmemb)) > (dataToRead->size - 1))
    {
        SYSLOG_WARNING ("buffer overflow would result -> strlen(writeData): %u, (size * nmemb): %u, max size: %u",
                strlen(dataToRead->buffer), (size * nmemb), dataToRead->size);
        return 0;
    }
    else
    {

    }
    strncat(dataToRead->buffer, data, (size * nmemb));
    return (size * nmemb);
}
Exemplo n.º 5
0
/**
 * Parse the characters found as the value of an XML tag
 */
static void _getactivationinfo_xml_charactersHandler(void *ctx, const xmlChar *ch, int len) {
    int i;
    char output[ACTIVATION_KEY_LENGTH];
    getactivationinfo_info_t *getActivationInfo = (getactivationinfo_info_t *) ctx;

    if (len > 0 && len < ACTIVATION_KEY_LENGTH) {
        for (i = 0; i < len; i++) {
            //if not equal a LF, CR store the character
            if ((ch[i] != 10) && (ch[i] != 13)) {
                output[i] = ch[i];
            }
        }
        output[i] = '\0';

        if (strcmp(getActivationInfo->xmlTag, "resultCode") == 0) {
            getActivationInfo->resultCode = atoi(output);

        } else if (strcmp(getActivationInfo->xmlTag, "deviceActivationKey") == 0) {
            snprintf(activationKey, sizeof(activationKey), "%s", output);

        } else {
            SYSLOG_DEBUG("Activation does not support XML tag %s", getActivationInfo->xmlTag);
        }

    } else {
        SYSLOG_ERR("Received an XML value that is too long to parse");
    }
}
Exemplo n.º 6
0
/**
 * Obtain the 48-bit MAC dest and convert to an EUI-64 value from the
 * hardware NIC
 *
 * @param dest Buffer of at least 8 bytes
 * @param destLen Length of the buffer
 * @return SUCCESS if we are able to capture the EUI64
 */
error_t eui64_toBytes(uint8_t *dest, int destLen) {
  struct ifreq *ifr;
  struct ifconf ifc;
  char buf[1024];
  int sock, i;
  int ok = 0;


  assert(dest);

  if(destLen < EUI64_BYTES_SIZE) {
    return FAIL;
  }

  memset(dest, 0x0, destLen);

  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock == -1) {
    return -1;
  }

  ifc.ifc_len = sizeof(buf);
  ifc.ifc_buf = buf;
  ioctl(sock, SIOCGIFCONF, &ifc);

  ifr = ifc.ifc_req;
  for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); ifr++) {
      if (strcmp(ifr->ifr_name, "eth0") == 0 || strcmp(ifr->ifr_name, "eth1")
	      == 0 || strcmp(ifr->ifr_name, "wlan0") == 0 || strcmp(ifr->ifr_name,
		  "br0") == 0) {
	  if (ioctl(sock, SIOCGIFFLAGS, ifr) == 0) {
	      if (!(ifr->ifr_flags & IFF_LOOPBACK)) {
		  if (ioctl(sock, SIOCGIFHWADDR, ifr) == 0) {
		      ok = 1;
		      break;
		  }
	      }
	  }
      }
  }

  close(sock);
  if (ok) {
    /* Convert 48 bit MAC dest to EUI-64 */
    memcpy(dest, ifr->ifr_hwaddr.sa_data, 6);
    /* Insert the converting bits in the middle */
    /* dest[3] = 0xFF;
    dest[4] = 0xFE;
    memcpy(&dest[5], &(ifr->ifr_hwaddr.sa_data[3]), 3);
    */
  } else {
    SYSLOG_ERR("Couldn't read MAC dest to seed EUI64");
    return FAIL;
  }

  return SUCCESS;
}
Exemplo n.º 7
0
/**
 * Send a message to the proxy
 * @param message Message to send
 * @param len Length of the message to send
 */
error_t clientsocket_send(const char *message, int len) {
  assert(message);

  if (write(socketFd, message, len) < 0) {
    SYSLOG_ERR("ERROR writing to socket");
    return FAIL;
  }

  return SUCCESS;
}
Exemplo n.º 8
0
/**
 * @brief   Called when a message has to be sent to the server. this is a standard streamer
 *              if the size of the data to write is larger than size*nmemb, this function
 *              will be called several times by libcurl.
 *
 * @param   ptr: where data has to be written
 * @param   size: size*nmemb == maximum number of bytes that can be written each time
 * @param   nmemb: size*nmemb == maximum number of bytes that can be written each time
 * @param   userp: ptr to message to write -> inputted by CURLOPT_READDATA call below
 *
 * @return  number of bytes that were written
 **/
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
    struct HttpIoInfo *dataToWrite = (struct HttpIoInfo *) userp;
    int dataWritten = 0;

    if (dataToWrite == NULL || dataToWrite->buffer == NULL)
    {
        SYSLOG_ERR ("dataToWrite == NULL");
        return 0;
    }

    if (size * nmemb < 1)
    {
        SYSLOG_ERR("size * nmemb < 1");
        return 0;
    }

    if (dataToWrite->size > 0)
    {
        if (dataToWrite->size > (size * nmemb))
        {
            dataWritten = size * nmemb;
            SYSLOG_DEBUG("dataToWrite->size = %u is larger than size * nmemb = %u",
                    dataToWrite->size, size * nmemb);
        }
        else
        {
            dataWritten = dataToWrite->size;
        }
        memcpy (ptr, dataToWrite->buffer, dataWritten);
        dataToWrite->buffer += dataWritten;
        dataToWrite->size -= dataWritten;

        return dataWritten; /* we return 1 byte at a time! */
    }
    else
    {
        return 0;
    }

    return 0;
}
Exemplo n.º 9
0
/**
 * Parse the characters found as the value of an XML tag
 */
static void _registrationinfo_xml_charactersHandler(void *ctx, const xmlChar *ch, int len) {
    int i;
    char output[ACTIVATION_KEY_LENGTH];
    registrationinfo_info_t *registrationInfo = (registrationinfo_info_t *) ctx;

    if (len > 0 && len < ACTIVATION_KEY_LENGTH) {
        for (i = 0; i < len; i++) {
            //if not equal a LF, CR store the character
            if ((ch[i] != 10) && (ch[i] != 13)) {
                output[i] = ch[i];
            }
        }
        output[i] = '\0';

        if (strcmp(registrationInfo->xmlTag, "resultCode") == 0) {
            registrationInfo->resultCode = atoi(output);

        } else if (strcmp(registrationInfo->xmlTag, "host") == 0) {
            libconfigio_write(proxycli_getConfigFilename(), CONFIGIO_CLOUD_HOST, output);

        } else if (strcmp(registrationInfo->xmlTag, "port") == 0) {
            libconfigio_write(proxycli_getConfigFilename(), CONFIGIO_CLOUD_PORT, output);

        } else if (strcmp(registrationInfo->xmlTag, "uri") == 0) {
            libconfigio_write(proxycli_getConfigFilename(), CONFIGIO_CLOUD_URI, output);

        } else if (strcmp(registrationInfo->xmlTag, "useSSL") == 0) {
            libconfigio_write(proxycli_getConfigFilename(), CONFIGIO_CLOUD_USE_SSL, output);

        } else {
            SYSLOG_DEBUG("Registration does not support XML tag %s", registrationInfo->xmlTag);
        }
    } else {
        SYSLOG_ERR("Received an XML value that is too long to parse");
    }
}
Exemplo n.º 10
0
/**
 * @brief   Generic function to write token into a file in the form (token=value)
 *
 * @param   fileName: file name for which token will be updated
 * @param   token: Token in file to update: example (ESP_HOST_NAME)
 * @param   value: value of token to update (see definition of max buffer sizes in libconfigio.h)
 *
 * @return  SUCCESS or FAIL
*/
error_t libconfigio_write(const char* fileName, const char* token, const char* value)
{
    error_t retVal = SUCCESS;
    FILE *configFd = NULL;
    FILE *tmpConfigFd = NULL; // of back up file
    char line[LINE_MAX];
    long filePos = -1; ///where the current value is located
    long eofPos = -1; ///where the end of the file is
    char currentValue[LINE_MAX];
    char tmpFileName[256]; ///back up file name when copying the file

    assert(fileName);
    assert(token);
    assert(value);

    memset(line, 0, sizeof(line));

    umask(022); // setting permissions to be able to write, open files

    // note that the config file or a link to it must be in /opt/etc, the source file is in
    // hub/etc/
    if (access(fileName, F_OK) != 0)
    {
        SYSLOG_DEBUG("file %s does not exist -> will be created", fileName);
    }else if (access(fileName, W_OK) != 0)
    {
        SYSLOG_DEBUG("no write permission for file %s", fileName);
        return FAIL;
    }else
    {
        // see if the token already exists -> if so read it and gets its line position in the file.
        filePos = libconfigio_read (fileName, token, currentValue, sizeof(currentValue));

        if(strcmp (value, currentValue) == 0)
        {
            // found value and it is the same -> no need to write the flash -> we're done
            retVal = SUCCESS;
            goto out;
        }
    }

    if (filePos != -1) //if found the value
    {
        //used for backing up of data when rewriting values -> temporary file
        snprintf(tmpFileName, sizeof(tmpFileName), "%s.tmp", fileName);
        // TODO: use temp file tmpnam() from Linux
        tmpConfigFd = fopen(tmpFileName, "w+");
        if (tmpConfigFd == NULL)
        {
            SYSLOG_ERR("%s -> could not open %s for reading and writing", strerror(errno), tmpFileName);
            retVal = FAIL;
            goto out;
        }

        // file that we will update
        configFd = fopen(fileName, "r+");
        if (configFd == NULL)
        {
            SYSLOG_ERR("%s -> could not open %s for reading and writing", strerror(errno), fileName);
            retVal = FAIL;
            goto out;
        }

        //find which that existing value is
        fseek(configFd, filePos, SEEK_SET);

        //get the first line and then dump it.
        if (fgets(line, sizeof(line), configFd) == NULL)
        {
          SYSLOG_ERR("fgets of first line failed");
        }

        // now we need to cpy the following lines in the temporary file
        while (!feof (configFd))
        {
            if(fgets(line, sizeof(line), configFd) == NULL)
            {
                break;
            }
            else if(fputs(line, tmpConfigFd) == EOF)
            {
                SYSLOG_ERR("writing tmp file %s, %s", tmpFileName, strerror(errno));
            }
        }

        //go back to where that line is
        fseek(configFd, filePos, SEEK_SET);
        // write the new value
        fprintf(configFd, "%s=%s\n", token,value);
        // then recopy the tmp file where we are now
        //go back to where that line is
        fseek(tmpConfigFd, 0, SEEK_SET);

        // now we need to cpy the following lines in the temporary file
        while (!feof (tmpConfigFd))
        {
            if(fgets(line, sizeof(line), tmpConfigFd) == NULL)
            {
                break;
            }
            else
            {
                if(fputs(line, configFd) == EOF)
                {
                    SYSLOG_ERR("writing cur file %s, %s", fileName, strerror(errno));
                }
            }
        }
        //update so that we know the file size
        eofPos = ftell(configFd);
    }
    else
    {
        //create - write token + value in file if either value or file does not exist

        //find where that existing value is
        if(configFd != NULL)
        {
            fclose(configFd);
        }
        configFd = fopen(fileName, "a+");
        if (configFd == NULL)
        {
            SYSLOG_ERR("%s -> could not open %s for appending", strerror(errno), fileName);
            retVal = FAIL;
            goto out;
        }
        fprintf(configFd, "%s=%s\n", token,value);

    }

    out:
        if (configFd != NULL)
        {
            if (eofPos > 0)
            {
                //eliminate junk at the end.
                if(ftruncate(fileno(configFd), eofPos) < 0)
                {
                    SYSLOG_ERR("ftruncate failed: %s", strerror(errno));
                }
            }
            fflush(configFd);
            fclose(configFd);
        }

        if (tmpConfigFd != NULL)
        {
            fclose(tmpConfigFd);
            remove(tmpFileName);
        }
        return retVal;
}
Exemplo n.º 11
0
/**
 * @brief   Generic function to read token from a file in the form (token=value)
 *
 * @param   fileName: file name for which token will be updated
 * @param   token: Token in file to read: example (ESP_HOST_NAME)
 * @param   value: ptr to which token will be written (see definition of max buffer sizes in libconfigio.h)
 * @param   valueSize: size of buffer pointed by value
 *
 * @return  offset in file of the line where the token reside in the file. -1 if not present or
 *              file does not exist
 **/
long libconfigio_read(const char* fileName, const char* token, char* value, int valueSize)
{
    long retVal = -1;
    FILE *configFd = NULL;
    char line[LINE_MAX];
    char *eofStatus;
    char *tmpString;
    int index = 0;

    assert(fileName);
    assert(token);
    assert(value);

    memset(line,0, sizeof(line));

    umask(022); // setting permissions to be able to read, write, open files

    if (access(fileName, F_OK) != 0)
    {
        SYSLOG_ERR("file %s does not exist", fileName);
        retVal = -1;
        goto out;
    }else if (access(fileName, R_OK) != 0)
    {
        SYSLOG_ERR("no read permission for file %s", fileName);
        retVal = -1;
        goto out;
    }else
    {
        //file exists
    }

    configFd = fopen(fileName, "r");
    if (configFd == NULL)
    {
        SYSLOG_ERR("%s -> could not open %s for reading", strerror(errno), fileName);
        retVal = -1;
        goto out;
    }

    // read file and see if token is already there
    while (feof(configFd) == 0)
    {
        eofStatus = fgets(line, sizeof(line), configFd);
        if( eofStatus == NULL ) //another indication of EOF
        {
            break;
        }

        tmpString = strstr(line, token);

        if(tmpString != NULL)
        {
            tmpString = strstr(tmpString, "=");
            if (tmpString == NULL)
            {
                retVal = -1;
                goto out;
            }

            tmpString++;
            while (isspace(*tmpString))    // skip leading spaces and tabs
            {
                tmpString++;
            }

            //copy value in string
            // stop when you get a control character.. new line, new feed
            index = 0;
            while (iscntrl(*tmpString) == 0 && index < valueSize)
            {
                value[index] = *tmpString;
                tmpString++;
                index++;
            }
            value[index] = '\0';

            retVal = ftell(configFd) - strlen(line); //get position in the file
            break;
        }
    }

    out:
        if (configFd != NULL)
        {
            fclose(configFd);
        }
        return retVal;

}
Exemplo n.º 12
0
/**
 * @brief   Sends a file through HTTP to a remote computer
 *
 * @param   url: url of the server (hostname + uri)
 * @param   sslCertPath: location of where the certificate is
 * @param   authToken: authentication token to be added in the header
 * @param   fileName: ptr to message to send. NULL if none
 * @param   rxBuffer: ptr for storing message received by the server -> must exist
 * @param   maxRxBufferSize: max size of rxBuffer in bytes.
 * @param   timeouts: specifies connect and transfer timeouts for the connection
 *
 * @return  true for success, false for failure
 */
int libhttpcomm_sendFile(const char *url, const char *sslCertPath, const char *authToken,
                char *fileName, char *rxBuffer, int maxRxBufferSize, http_timeout_t timeouts)
{
    CURL * curlHandle;
    CURLcode curlResult;
    FILE *file = NULL;
    char tempString[PATH_MAX];
    char errorBuffer[CURL_ERROR_SIZE];
    int fileSize = 0;
    struct HttpIoInfo inBoundCommInfo;
    struct curl_slist *slist = NULL;
    struct stat fileStats;
    double connectDuration = 0.0;
    double transferDuration = 0.0;
    double nameResolvingDuration = 0.0;
    long httpResponseCode = 0;
    long httpConnectCode = 0;
    long curlErrno = 0;
    bool_t retVal = true;

    assert (url);
    assert (fileName);

    curlHandle = curl_easy_init();
    if (curlHandle)
    {
        //creating the curl object
        // TODO: not sure that setting a pointer to a pointer that is scoped elsewhere is correct.
        file = fopen(fileName, "r");
        if (file == NULL)
        {
            SYSLOG_ERR("%s opening %s", strerror(errno), fileName);
            retVal = false;
            goto out;
        }

        if (stat (fileName, &fileStats) >= 0)
        {
            fileSize = (int)fileStats.st_size;
        }else
        {
            SYSLOG_ERR("stats returned %s", strerror(errno));
        }

        slist = curl_slist_append(slist, "Content-Type: application/octet-stream");
        snprintf(tempString, sizeof(tempString), "Content-Length: %d", fileSize);
        slist = curl_slist_append(slist, tempString);

        SYSLOG_DEBUG("fileName: %s, url: %s, fileSize = %d", fileName, url, fileSize);

        if (_libhttpcomm_configureHttp(curlHandle, NULL, slist, CURLOPT_POST, url,
                sslCertPath, authToken, timeouts, NULL) == false)
        {
            retVal = false;
            goto out;
        }

        curlResult = curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, errorBuffer);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_ERRORBUFFER", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        /* pointer to pass to our read function */
        // here you must put the file info
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_READDATA, file);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_READDATA", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        // sets maximum size of our internal buffer
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_BUFFERSIZE, maxRxBufferSize);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_BUFFERSIZE", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        // CURLOPT_WRITEFUNCTION and CURLOPT_WRITEDATA in this context refers to
        // data received from the server... so curl will write data to us.
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, writer);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_WRITEFUNCTION", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        inBoundCommInfo.buffer = rxBuffer;
        inBoundCommInfo.size = maxRxBufferSize;

        curlResult = curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &inBoundCommInfo);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_WRITEDATA", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        curlResult = curl_easy_perform(curlHandle);

        curl_easy_getinfo(curlHandle, CURLINFO_APPCONNECT_TIME, &connectDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_NAMELOOKUP_TIME, &nameResolvingDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_TOTAL_TIME, &transferDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &httpResponseCode );
        curl_easy_getinfo(curlHandle, CURLINFO_HTTP_CONNECTCODE, &httpConnectCode );

        if (nameResolvingDuration >= 2.0)
        {
            SYSLOG_WARNING("connectDuration=%.2lf, nameResolvingDuration=%.2lf, transferDuration=%.2lf, "
                    "httpConnectCode=%ld",
                    connectDuration, nameResolvingDuration, transferDuration, httpConnectCode);
        }
        else
        {
            SYSLOG_DEBUG("connectDuration=%.2lf, nameResolvingDuration=%.2lf, transferDuration=%.2lf, "
                    "httpConnectCode=%ld",
                    connectDuration, nameResolvingDuration, transferDuration, httpConnectCode);
        }

        if (httpResponseCode >= 300 || httpConnectCode >= 300)
        {
            SYSLOG_ERR("HTTP error response code: %ld, connect code: %ld", httpResponseCode, httpConnectCode);
            retVal = false;
            goto out;
        }

        if (curlResult != CURLE_OK)
        {
            if (curlResult != CURLE_ABORTED_BY_CALLBACK)
            {
                if (curl_easy_getinfo(curlHandle, CURLINFO_OS_ERRNO, &curlErrno) != CURLE_OK)
                {
                    curlErrno = 0;
                    SYSLOG_ERR("curl_easy_getinfo");
                }
                SYSLOG_ERR("curl_easy_perform: %s, %s for url %s",
                        curl_easy_strerror(curlResult), strerror((int)curlErrno), url);
            }else
            {
                SYSLOG_DEBUG("quitting curl transfer");
            }
            retVal = false;
            goto out;
        }

        // the following is a special case - a time-out from the server is going to return a
        // string with 1 character in it ...
        if (strlen(rxBuffer) > 1)
        {
            /* put the result into the main buffer and return */
            SYSLOG_DEBUG("received msg length %d", strlen(rxBuffer));
        }else
        {
            if (strlen(rxBuffer) == 1)
            {
                SYSLOG_DEBUG("received time-out message from the server");
            }
            rxBuffer[0] = '\0';
            goto out;
        }
    }
    else
    {
        SYSLOG_ERR("curl_easy_init failed");
        retVal = false;
    }

    out:
      fclose(file);
      _libhttpcomm_closeHttp(curlHandle, slist);
      return retVal;
}
Exemplo n.º 13
0
/**
 * @brief   Get a file through HTTP from PPC servers
 *
 * @param   shareCurlHandle: Curl handle shared across connections
 * @param   url: url of the server (hostname + uri)
 * @param   sslCertPath: location of where the certificate is
 * @param   authToken: authentication token to be added in the header
 * @param   rxFile: FILE ptr to the incoming file
 * @param   maxRxFileSize: max size of the file to receive
 * @param   timeouts: specifies connect and transfer timeouts for the connection
 * @param   ProgressCallback: function pointer that will be called every second during the connection
 *
 * @return  true for success, false for failure
 */
int libhttpcomm_getFile(CURLSH * shareCurlHandle, const char *url, const char *sslCertPath, const char *authToken,
                FILE *rxFile, int maxRxFileSize, http_timeout_t timeouts,
                int (*ProgressCallback) (void *clientp, double dltotal, double dlnow, double ultotal, double ulnow))
{
    CURL * curlHandle;
    CURLcode curlResult;
    char errorBuffer[CURL_ERROR_SIZE];
    struct curl_slist *slist = NULL;
    double connectDuration = 0.0;
    double transferDuration = 0.0;
    double nameResolvingDuration = 0.0;
    long curlErrno = 0;
    long httpResponseCode = 0;
    long httpConnectCode = 0;
    bool_t retVal = true;

    assert (rxFile);
    assert (url);

    SYSLOG_DEBUG("url: %s", url);

    curlHandle = curl_easy_init();
    if (curlHandle)
    {
        if (_libhttpcomm_configureHttp(curlHandle, shareCurlHandle, slist, CURLOPT_HTTPGET, url,
                sslCertPath, authToken, timeouts, ProgressCallback) == false)
        {
            retVal = false;
            goto out;
        }

        curlResult = curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, errorBuffer);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_ERRORBUFFER", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        // sets maximum size of our internal buffer
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_BUFFERSIZE, maxRxFileSize);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_BUFFERSIZE", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        curlResult = curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, rxFile);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_WRITEDATA", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        curlResult = curl_easy_perform(curlHandle);

        curl_easy_getinfo(curlHandle, CURLINFO_APPCONNECT_TIME, &connectDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_NAMELOOKUP_TIME, &nameResolvingDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_TOTAL_TIME, &transferDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &httpResponseCode );
        curl_easy_getinfo(curlHandle, CURLINFO_HTTP_CONNECTCODE, &httpConnectCode );

        if (httpResponseCode >= 300 || httpConnectCode >= 300)
        {
            retVal = false;
            goto out;
        }

        if (nameResolvingDuration >= 2.0)
        {
            SYSLOG_WARNING("connectDuration=%.2lf, nameResolvingDuration=%.2lf, transferDuration=%.2lf",
                    connectDuration, nameResolvingDuration, transferDuration);
        }
        else
        {
            SYSLOG_DEBUG("connectDuration=%.2lf, nameResolvingDuration=%.2lf, transferDuration=%.2lf",
                    connectDuration, nameResolvingDuration, transferDuration);
        }

        if (curlResult != CURLE_OK)
        {
            if (curlResult != CURLE_ABORTED_BY_CALLBACK)
            {
                if (curl_easy_getinfo(curlHandle, CURLINFO_OS_ERRNO, &curlErrno) != CURLE_OK)
                {
                    curlErrno = 0;
                    SYSLOG_ERR("curl_easy_getinfo");
                }
                SYSLOG_ERR("curl_easy_perform: %s, %s for url %s",
                        curl_easy_strerror(curlResult), strerror((int)curlErrno), url);
            }else
            {
                SYSLOG_DEBUG("quitting curl transfer");
            }
            retVal = false;
            goto out;
        }
    }
    else
    {
        SYSLOG_ERR("curl_easy_init failed");
        retVal = false;
    }

    out:
      _libhttpcomm_closeHttp(curlHandle, slist);
      return retVal;
}
Exemplo n.º 14
0
/**
 * @brief   Sends a message through HTTP to PPC servers
 *
 * @param   shareCurlHandle: Curl handle shared across connections
 * @param   httpMethod: CURLOPT_POST or CURLOPT_HTTPGET
 * @param   url: url of the server (hostname + uri)
 * @param   sslCertPath: location of where the certificate is
 * @param   authToken: authentication token to be added in the header
 * @param   msgToSendPtr: ptr to message to send. NULL if none
 * @param   msgToSendSize: send of msgToSendPtr
 * @param   rxBuffer: ptr for storing message received by the server -> must exist
 * @param   maxRxBufferSize: max size of rxBuffer in bytes -> if 0 it is assumed that rxBuffer is of type FILE*
 * @param   timeouts: specifies connect and transfer timeouts for the connection
 * @param   ProgressCallback: function pointer that will be called every second during the connection
 *
 * @return  true for success, false for failure
 */
int libhttpcomm_postMsg(CURLSH * shareCurlHandle, CURLoption httpMethod, const char *url, const char *sslCertPath, const char *authToken,
                char *msgToSendPtr, int msgToSendSize, char *rxBuffer, int maxRxBufferSize, http_param_t params,
                int (*ProgressCallback) (void *clientp, double dltotal, double dlnow, double ultotal, double ulnow))
{
    CURL * curlHandle = NULL;
    CURLcode curlResult;
    char tempString[PATH_MAX];
    char errorBuffer[CURL_ERROR_SIZE];
    struct HttpIoInfo outBoundCommInfo;
    struct HttpIoInfo inBoundCommInfo;
    struct curl_slist *slist = NULL;
    double connectDuration = 0.0;
    double transferDuration = 0.0;
    double nameResolvingDuration = 0.0;
    long httpResponseCode = 0;
    long httpConnectCode = 0;
    long curlErrno = 0;

    assert (rxBuffer);
    assert(url);

    if (params.verbose == true)
    {
        if (msgToSendPtr != NULL)
        {
            SYSLOG_DEBUG("httpMethod: 0x%x, url: %s, size: %d, outgoing msg: %s",
                    httpMethod, url, msgToSendSize, msgToSendPtr);
        }else
        {
            SYSLOG_DEBUG("httpMethod: 0x%x, url: %s", httpMethod, url);
        }
    }

    rxBuffer[0] = 0;

    curlHandle = curl_easy_init();

    if ( params.key != NULL )
    {
	slist = curl_slist_append(slist, params.key);
	slist = curl_slist_append(slist, "Content-Type:");
    }

    if (curlHandle)
    {
	if ( httpMethod == CURLOPT_POST )
	{
	    if ( msgToSendSize > 0 )
	    {
		slist = curl_slist_append(slist, "Content-Type: text/xml");
		snprintf(tempString, sizeof(tempString), "Content-Length: %d", msgToSendSize);
		slist = curl_slist_append(slist, tempString);
	    }
	    else if ( msgToSendSize == 0 )
	    {
		snprintf(tempString, sizeof(tempString), "Content-Length: %d", msgToSendSize);
		slist = curl_slist_append(slist, tempString);
	    }
	}
	else if ( httpMethod  == CURLOPT_HTTPGET )
	{
	    if ( params.password != NULL )
	    {
		SYSLOG_ERR("password: %s", params.password);
		slist = curl_slist_append(slist, params.password);
	    }
	    if ( params.key != NULL )
	    {
		SYSLOG_ERR("key: %s", params.key);
		slist = curl_slist_append(slist, params.key);
	    }
	}

        if (_libhttpcomm_configureHttp(curlHandle, shareCurlHandle, slist, httpMethod, url,
                sslCertPath, authToken, params.timeouts, ProgressCallback) == false)
        {
            curlErrno = ENOEXEC;
            goto out;
        }

        curlResult = curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, errorBuffer);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_ERRORBUFFER", curl_easy_strerror(curlResult));
            curlErrno = ENOEXEC;
            goto out;
        }

        // CURLOPT_READFUNCTION and CURLOPT_READDATA in this context refers to
        // data to be sent to the server... so curl will read data from us.
        if(msgToSendPtr != NULL)
        {
	    if ( msgToSendSize > 0 )
	    {
		curlResult = curl_easy_setopt(curlHandle, CURLOPT_READFUNCTION, read_callback);
		if (curlResult != CURLE_OK)
		{
		    SYSLOG_ERR("%s CURLOPT_READFUNCTION", curl_easy_strerror(curlResult));
		    curlErrno = ENOEXEC;
		    goto out;
		}

		//creating the curl object
		// TODO: not sure that setting a pointer to a pointer that is scoped elsewhere is correct.
		outBoundCommInfo.buffer = msgToSendPtr;
		outBoundCommInfo.size = msgToSendSize;
		/* pointer to pass to our read function */
		// here you must put the file info
		curlResult = curl_easy_setopt(curlHandle, CURLOPT_READDATA, &outBoundCommInfo);
		if (curlResult != CURLE_OK)
		{
		    SYSLOG_ERR("%s CURLOPT_READDATA", curl_easy_strerror(curlResult));
		    curlErrno = ENOEXEC;
		    goto out;
		}
	    }
        }

        // sets maximum size of our internal buffer
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_BUFFERSIZE, maxRxBufferSize);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_BUFFERSIZE", curl_easy_strerror(curlResult));
            curlErrno = ENOEXEC;
            goto out;
        }

        // CURLOPT_WRITEFUNCTION and CURLOPT_WRITEDATA in this context refers to
        // data received from the server... so curl will write data to us.
	curlResult = curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, writer);
	if (curlResult != CURLE_OK)
	{
	    SYSLOG_ERR("%s CURLOPT_WRITEFUNCTION", curl_easy_strerror(curlResult));
	    curlErrno = ENOEXEC;
	    goto out;
	}

	inBoundCommInfo.buffer = rxBuffer;
	inBoundCommInfo.size = maxRxBufferSize;

	curlResult = curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &inBoundCommInfo);
	if (curlResult != CURLE_OK)
	{
	    SYSLOG_ERR("%s CURLOPT_WRITEDATA", curl_easy_strerror(curlResult));
	    curlErrno = ENOEXEC;
	    goto out;
	}

	curlResult = curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, NULL);
	if (curlResult != CURLE_OK)
	{
	    SYSLOG_ERR("%s CURLOPT_POSTFIELDS", curl_easy_strerror(curlResult));
	    curlErrno = ENOEXEC;
	    goto out;
	}

	curlResult = curl_easy_perform(curlHandle);

        curl_easy_getinfo(curlHandle, CURLINFO_APPCONNECT_TIME, &connectDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_NAMELOOKUP_TIME, &nameResolvingDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_TOTAL_TIME, &transferDuration );
        curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &httpResponseCode );
        curl_easy_getinfo(curlHandle, CURLINFO_HTTP_CONNECTCODE, &httpConnectCode );

        if (httpResponseCode >= 300 || httpConnectCode >= 300)
        {
            if (params.verbose == true) SYSLOG_ERR("HTTP error response code:%ld, connect code:%ld", httpResponseCode, httpConnectCode);
            curlErrno = EHOSTUNREACH;
            goto out;
        }

        if (curlResult != CURLE_OK)
        {
            if (curlResult != CURLE_ABORTED_BY_CALLBACK)
            {
                if (curl_easy_getinfo(curlHandle, CURLINFO_OS_ERRNO, &curlErrno) != CURLE_OK)
                {
                    curlErrno = ENOEXEC;
                    SYSLOG_ERR("curl_easy_getinfo");
                }
                if (curlResult == CURLE_OPERATION_TIMEDOUT) curlErrno = ETIMEDOUT; /// time out error must be distinctive
                else if (curlErrno == 0) curlErrno = ENOEXEC; /// can't be equalt to 0 if curlResult != CURLE_OK

                if (params.verbose == true) SYSLOG_WARNING("%s, %s for url %s",
                        curl_easy_strerror(curlResult), strerror((int)curlErrno), url);
            }else
            {
                curlErrno = EAGAIN;
                if (params.verbose == true) SYSLOG_DEBUG("quitting curl transfer");
            }
            goto out;
        }else if (params.verbose == true)
        {
            if (nameResolvingDuration >= 2.0)
            {
                SYSLOG_WARNING("connectDuration=%.2lf, nameResolvingDuration=%.2lf, transferDuration=%.2lf, "
                        "httpConnectCode=%ld",
                        connectDuration, nameResolvingDuration, transferDuration, httpConnectCode);
            }
            else
            {
                SYSLOG_DEBUG("connectDuration=%.2lf, nameResolvingDuration=%.2lf, transferDuration=%.2lf, "
                        "httpConnectCode=%ld",
                        connectDuration, nameResolvingDuration, transferDuration, httpConnectCode);
            }
        }

        // the following is a special case - a time-out from the server is going to return a
        // string with 1 character in it ...
        if (strlen(rxBuffer) > 1)
        {
            /* put the result into the main buffer and return */
            if (params.verbose == true) SYSLOG_DEBUG("received msg length %d", strlen(rxBuffer));
            if(msgToSendPtr != NULL && msgToSendSize > 0 )
            {
              msgToSendPtr[0] = 0;
            }

        }else
        {
            SYSLOG_DEBUG("received time-out message from the server");
            rxBuffer[0] = '\0';
            curlErrno = EAGAIN;
            goto out;
        }
    }
    else
    {
        SYSLOG_ERR("curl_easy_init failed");
        curlErrno = ENOEXEC;
    }

    out:
      _libhttpcomm_closeHttp(curlHandle, slist);
      return (int)curlErrno;
}
Exemplo n.º 15
0
/**
 * @brief   This function configures a HTTP connection with PPC standard parameters
 *
 * @param   curlHandle: curl handle to configure
 * @param   shareCurlHandle: curl handle shared across connections, used for DNS caching.
 * @param   slist: linked list that stores the HTTP Header
 * @param   httpMethod: HTTP RESTFUL method to use (GET, POST, DELETE PUT)
 * @param   url: url of the server (hostname + uri)
 * @param   sslCertPath: location of where the certificate is
 * @param   authToken: authentication token to be added in the header
 * @param   fileName: ptr to message to send. NULL if none
 * @param   rxBuffer: ptr for storing message received by the server -> must exist
 * @param   maxRxBufferSize: max size of rxBuffer in bytes.
 * @param   timeouts: specifies connect and transfer timeouts for the connection
 * @param   ProgressCallback: Function to be called periodically by curl every second
 *              while the transfer is underway
 *
 * @return  true for success, false for failure
 */
int _libhttpcomm_configureHttp(CURL * curlHandle, CURLSH * shareCurlHandle, struct curl_slist *slist, CURLoption httpMethod,
        const char *url, const char *sslCertPath, const char *authToken, http_timeout_t timeouts,
        int (*ProgressCallback) (void *clientp, double dltotal, double dlnow, double ultotal, double ulnow))
{
    int retVal = true;
    CURLcode curlResult;
    char tempString[256];

    if (shareCurlHandle != NULL)
    {
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_SHARE, shareCurlHandle);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_SHARE", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }
    }

    curlResult = curl_easy_setopt(curlHandle, CURLOPT_DNS_CACHE_TIMEOUT, HTTPCOMM_DEFAULT_DNS_CACHING_TIMEOUT_SEC);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_FORBID_REUSE", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

    // no signals when using c-ares
    curlResult = curl_easy_setopt(curlHandle, CURLOPT_NOSIGNAL, 1L);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_NOSIGNAL", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

    //making sure that this is a new connection
    curlResult = curl_easy_setopt(curlHandle, CURLOPT_FORBID_REUSE, false);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_FORBID_REUSE", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

#if 0
    //TODO:
    curlResult = curl_easy_setopt(curlHandle, CURLOPT_VERBOSE, true);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_VERBOSE", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }
#endif

    curlResult = curl_easy_setopt(curlHandle, CURLOPT_FRESH_CONNECT, false);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_FRESH_CONNECT", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

    // for safe multi-threaded operation
    // now only used in one thread. to be able to disable signal -> c-ares library has be used
    // for name resolving
    curlResult = curl_easy_setopt(curlHandle, CURLOPT_NOSIGNAL, 1);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_NOSIGNAL", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

    // less than 30 seconds is not reliable
    if (timeouts.connectTimeout != 0)
    {
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_CONNECTTIMEOUT, timeouts.connectTimeout);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_CONNECTTIMEOUT", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }
    }

    if (timeouts.transferTimeout != 0)
    {
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_TIMEOUT, timeouts.transferTimeout);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_TIMEOUT", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }
    }

    // set progress meter so that we can read if the push pipe is getting full
    if(ProgressCallback != NULL)
    {
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_NOPROGRESS, 0);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_NOPROGRESS", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        curlResult = curl_easy_setopt(curlHandle, CURLOPT_PROGRESSFUNCTION, ProgressCallback);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_PROGRESSFUNCTION", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }
    }

    if (sslCertPath != NULL)
    {
        curlResult = curl_easy_setopt(curlHandle, CURLOPT_SSL_VERIFYPEER, 0L);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_SSL_VERIFYPEER", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }

        curlResult = curl_easy_setopt(curlHandle, CURLOPT_CAPATH, sslCertPath);
        if (curlResult != CURLE_OK)
        {
            SYSLOG_ERR("%s CURLOPT_CAPATH", curl_easy_strerror(curlResult));
            retVal = false;
            goto out;
        }
    }

    curlResult = curl_easy_setopt(curlHandle, CURLOPT_URL, url);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_URL", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

    curlResult = curl_easy_setopt(curlHandle, httpMethod, 1L);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_POST", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

    // all is ready, so do it -> set the http header
    //generic http header
    slist = curl_slist_append(slist, "User-Agent: IOT Proxy");

    if (authToken != NULL)
    {
        snprintf(tempString, sizeof(tempString), "PPCAuthorization: esp token=%s", authToken);
        slist = curl_slist_append(slist, tempString);
    }

    //TODO: may want to add a paramter for an optional header line
    curlResult = curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, slist);
    if (curlResult != CURLE_OK)
    {
        SYSLOG_ERR("%s CURLOPT_HTTPHEADER", curl_easy_strerror(curlResult));
        retVal = false;
        goto out;
    }

    out:
        return retVal;
}