private function makeRequest($socket, $req, $retry = true) {
    $bytes_written = 0;
    $bytes_total = strlen($req);
    $closed = false;

    // Retries with exponential backoff until success
    $backoff = 100;   // Set initial waiting time to 100ms

    while (true) {
      // Send request to server
      while (!$closed && $bytes_written < $bytes_total) {
        try {
          // Since we're try catch'ing prevent PHP logs.
          $written = @fwrite($socket, substr($req, $bytes_written));
        } catch (Exception $e) {
          $this->handleError($e->getCode(), $e->getMessage());
          $closed = true;
        }
        if (!isset($written) || !$written) {
          $closed = true;
        } else {
          $bytes_written += $written;
        }
      }

      // Get response for request
      $statusCode = 0;
      $errorMessage = "";

      if (!$closed) {
        $res = $this->parseResponse(fread($socket, 2048));
        $statusCode = (int)$res["status"];
        $errorMessage = $res["message"];
      }
      fclose($socket);

      // If status code is 200, return true
      if (200 == $statusCode) {
        return true;
      }

      // If status code is greater than 500 and less than 600, it indicates server error
      // Error code 429 indicates rate limited.
      // Retry uploading in these cases.
      if (($statusCode >= 500 && $statusCode <= 600) || 429 == $statusCode || 0 == $statusCode) {
        if ($backoff >= $this->maximum_backoff_duration) {
          break;
        }

        usleep($backoff * 1000);
      } elseif ($statusCode >= 400) {
        if ($this->debug()) {
          $this->handleError($res["status"], $res["message"]);
        }

        break;
      }

      // Retry uploading...
      $backoff *= 2;
      $socket = $this->createSocket();
    }

    return $success;
  }