diff --git a/httprl.module b/httprl.module
index 1fa9ebb..943de77 100644
--- a/httprl.module
+++ b/httprl.module
@@ -10,6 +10,23 @@
 define('HTTPRL_TIMEOUT', 30.0);
 
 /**
+ * Default maximum number of seconds the DNS portion of a request may take.
+ */
+define('HTTPRL_DNS_TIMEOUT', 5.0);
+
+/**
+ * Default maximum number of seconds establishing the TCP connection of a
+ * request may take.
+ */
+define('HTTPRL_CONNECT_TIMEOUT', 5.0);
+
+/**
+ * Default maximum number of seconds a connection may take to download the first
+ * byte.
+ */
+define('HTTPRL_TTFB_TIMEOUT', 20.0);
+
+/**
  * Default maximum number of seconds a function call may take.
  */
 define('HTTPRL_GLOBAL_TIMEOUT', 120.0);
@@ -289,7 +306,10 @@ function httprl_set_default_options(&$options) {
     'method' => 'GET',
     'data' => NULL,
     'max_redirects' => 3,
-    'timeout' => HTTPRL_TIMEOUT,
+    'timeout' => variable_get('httprl_timeout', HTTPRL_TIMEOUT),
+    'dns_timeout' => variable_get('httprl_dns_timeout', HTTPRL_DNS_TIMEOUT),
+    'connect_timeout' => variable_get('httprl_connect_timeout', HTTPRL_CONNECT_TIMEOUT),
+    'ttfb_timeout' => variable_get('httprl_ttfb_timeout', HTTPRL_TTFB_TIMEOUT),
     'context' => NULL,
     'blocking' => TRUE,
     'version' => '1.0',
@@ -680,6 +700,11 @@ function httprl_stream_connection_error_formatter($errno, $errstr, &$result) {
       $result->error = $errstr;
     }
   }
+  elseif ($errno == 110) {
+    // 110 means Connection timed out. This should be HTTPRL_REQUEST_TIMEOUT.
+    $result->code = HTTPRL_REQUEST_TIMEOUT;
+    $result->error = !empty($errstr) ? $errstr : $t('Connection timed out. TCP.');
+  }
   else {
     // When a network error occurs, we use a negative number so it does not
     // clash with the HTTP status codes.
@@ -722,14 +747,21 @@ function httprl_establish_stream_connection(&$result) {
       }
     }
 
+    // Set the DNS timeout.
+    $timeout = $result->options['dns_timeout'];
+    // If not using async_connect then add connect_timeout to timeout.
+    if (!$result->options['async_connect']) {
+      $timeout += $result->options['connect_timeout'];
+    }
+
     // Open the connection.
     if (empty($result->options['context'])) {
-      $result->fp = @stream_socket_client($result->socket, $errno, $errstr, $result->options['timeout'], $result->flags);
+      $result->fp = @stream_socket_client($result->socket, $errno, $errstr, $timeout, $result->flags);
     }
     else {
       // Create a stream with context. Context allows for the verification of
       // a SSL certificate.
-      $result->fp = @stream_socket_client($result->socket, $errno, $errstr, $result->options['timeout'], $result->flags, $result->options['context']);
+      $result->fp = @stream_socket_client($result->socket, $errno, $errstr, $timeout, $result->flags, $result->options['context']);
     }
     $count++;
   }
@@ -794,7 +826,18 @@ function httprl_establish_stream_connection(&$result) {
  *     may be followed. Defaults to 3.
  *   - timeout: A float representing the maximum number of seconds a connection
  *     may take. The default is 30 seconds. If a timeout occurs, the error code
- *     is set to the HTTPRL_REQUEST_TIMEOUT constant.
+ *     is set to the HTTPRL_REQUEST_ABORTED constant.
+ *   - dns_timeout: A float representing the maximum number of seconds a DNS
+ *     lookup request may take. The default is 5 seconds. If a timeout occurs,
+ *     the error code is set to the HTTPRL_HOST_NOT_FOUND constant.
+ *   - connect_timeout: A float representing the maximum number of seconds
+ *     establishing the TCP connection may take. The default is 5 seconds. If a
+ *     timeout occurs, the error code is set to the HTTPRL_REQUEST_TIMEOUT
+ *     constant.
+ *   - ttfb_timeout: A float representing the maximum number of seconds a
+ *     connection may take to download the first byte. The default is 20
+ *     seconds. If a timeout occurs, the error code is set to the
+ *     HTTPRL_REQUEST_ABORTED constant.
  *   - context: A context resource created with stream_context_create().
  *   - blocking: set to FALSE to make this not care about the returned data.
  *   - version: HTTP Version 1.0 or 1.1. Default is 1.0 for a good reason.
@@ -861,7 +904,7 @@ function httprl_request($urls, $options = array()) {
   foreach ($urls as $url) {
     $result = new stdClass();
     $result->url = $url;
-    $result->status = 'in progress';
+    $result->status = 'Connecting.';
     $result->code = 0;
     $result->chunk_size = 1024;
     $result->data = '';
@@ -996,7 +1039,6 @@ function httprl_send_request($results = NULL) {
   $start_time_this_run = $start_time_global = microtime(TRUE);
 
   // Run the loop as long as we have a stream to read/write to.
-  $empty_runs = 0;
   $stream_select_timeout = 1;
   $stream_write_count = 0;
 
@@ -1016,13 +1058,19 @@ function httprl_send_request($results = NULL) {
     $start_time_this_run = $now;
     $global_time = $global_timeout - ($start_time_this_run - $start_time_global);
 
-    $reset_empty_runs = FALSE;
     // Inspect each stream, checking for timeouts and connection limits.
     foreach ($responses as $id => &$result) {
       // See if function timed out.
       if ($global_time <= 0) {
         // Function timed out & the request is not done.
-        if ($result->status == 'in progress') {
+        if ($result->status == 'Connecting.') {
+          $result->error = $t('Function timed out. TCP.');
+          // If stream is not done writing, then remove one from the write count.
+          if (isset($result->fp)) {
+            $stream_write_count--;
+          }
+        }
+        elseif ($result->status == 'Writing To Server.') {
           $result->error = $t('Function timed out. Write.');
           // If stream is not done writing, then remove one from the write count.
           if (isset($result->fp)) {
@@ -1030,7 +1078,7 @@ function httprl_send_request($results = NULL) {
           }
         }
         else {
-          $result->error = $t('Function timed out.');
+          $result->error = $t('Function timed out. Read');
         }
         $result->code = HTTPRL_FUNCTION_TIMEOUT;
         $result->status = 'Done.';
@@ -1045,45 +1093,47 @@ function httprl_send_request($results = NULL) {
         $result->running_time += $elapsed_time;
         // Calculate how much time is left of the original timeout value.
         $timeout = $result->options['timeout'] - $result->running_time;
-        // No streams are ready from stream_select, See if end server has
-        // dropped the connection, or has failed to make the connection.
-        $socket_name = 'Not empty.';
-        if ($result->options['async_connect'] && $empty_runs > 32) {
-          // If nothing has happened after 32 runs, see if the connection has
-          // been made.
-          $socket_name = stream_socket_get_name($result->fp, TRUE);
-        }
 
         // Connection was dropped or connection timed out.
-        if ($timeout <= 0 || empty($socket_name)) {
+        if ($timeout <= 0 || ($result->status == 'Connecting.' && $result->running_time > $result->options['connect_timeout'])) {
           $result->error = $t('Connection timed out.');
-          if (empty($socket_name)) {
-            $result->error .= ' ' . $t('If you believe this is a false error, set async_connect to false in the options array that is passed into httprl_request() and try again.');
-          }
           // Stream timed out & the request is not done.
-          if ($result->status == 'in progress') {
-            $result->error .= $t(' Write.');
+          if ($result->status == 'Connecting.') {
+            $result->error .= ' ' . $t('Connect Timeout.');
+            // If stream is not done writing, then remove one from the write count.
+            $stream_write_count--;
+          }
+          elseif ($result->status == 'Writing To Server.') {
+            $result->error .= ' ' . $t('Write.');
             // If stream is not done writing, then remove one from the write count.
             $stream_write_count--;
           }
           else {
-            $result->error .= $t(' Read.');
+            $result->error .= ' ' . $t('Read.') . $timeout;
           }
           $result->code = HTTPRL_REQUEST_TIMEOUT;
           $result->status = 'Done.';
 
           // Do post processing on the stream.
           httprl_post_processing($id, $responses, $output, $timeout);
-          $reset_empty_runs = TRUE;
+          continue;
+        }
+
+        if (!isset($responses[$id]->time_to_first_byte) && $result->running_time > $result->options['ttfb_timeout']) {
+          $result->error = $t('Connection timed out. Time to First Byte Timeout.');
+          $result->code = HTTPRL_REQUEST_ABORTED;
+          $result->status = 'Done.';
+
+          // Do post processing on the stream.
+          httprl_post_processing($id, $responses, $output, $timeout);
           continue;
         }
       }
 
       // Connection was handled elsewhere.
-      if (!isset($result->fp) && $result->status != 'in progress') {
+      if (!isset($result->fp) && $result->status != 'Connecting.') {
         // Do post processing on the stream.
         httprl_post_processing($id, $responses, $output);
-        $reset_empty_runs = TRUE;
         continue;
       }
 
@@ -1105,7 +1155,7 @@ function httprl_send_request($results = NULL) {
       // If the conditions are correct, let the stream be ran in this loop.
       if ($global_connection_limit >= $global_connection_count && $domain_connection_limit[$host] >= $domain_connection_count[$host]) {
         // Establish a new connection.
-        if (!isset($result->fp) && $result->status == 'in progress') {
+        if (!isset($result->fp) && $result->status == 'Connecting.') {
           // Establish a connection to the server.
           httprl_establish_stream_connection($result);
 
@@ -1141,11 +1191,6 @@ function httprl_send_request($results = NULL) {
     if (empty($this_run)) {
       continue;
     }
-    if ($reset_empty_runs) {
-      $empty_runs = 0;
-      $reset_empty_runs = FALSE;
-    }
-
 
 
     // Set the read and write vars to the streams var.
@@ -1159,7 +1204,6 @@ function httprl_send_request($results = NULL) {
     // We have some streams to read/write to.
     $rw_done = FALSE;
     if (!empty($n)) {
-      $empty_runs = 0;
 
       // Readable sockets either have data for us, or are failed connection
       // attempts.
@@ -1181,6 +1225,10 @@ function httprl_send_request($results = NULL) {
         $chunk = fread($r, $responses[$id]->chunk_size);
         if (httprl_strlen($chunk) > 0) {
           $rw_done = TRUE;
+          if (!isset($responses[$id]->time_to_first_byte)) {
+            // Calculate Time to Frist Byte.
+            $responses[$id]->time_to_first_byte = $result->running_time + microtime(TRUE) - $start_time_this_run;
+          }
         }
         $responses[$id]->data .= $chunk;
 
@@ -1239,7 +1287,11 @@ function httprl_send_request($results = NULL) {
         $info = stream_get_meta_data($r);
         $alive = !$info['eof'] && !feof($r) && !$info['timed_out'] && httprl_strlen($chunk);
         if (!$alive) {
-          if ($responses[$id]->status == 'in progress') {
+          if ($responses[$id]->status == 'Connecting.') {
+            $responses[$id]->error = $t('Connection refused by destination. TCP.');
+            $responses[$id]->code = HTTPRL_CONNECTION_REFUSED;
+          }
+          if ($responses[$id]->status == 'Writing To Server.') {
             $responses[$id]->error = $t('Connection refused by destination. Write.');
             $responses[$id]->code = HTTPRL_CONNECTION_REFUSED;
           }
@@ -1259,7 +1311,7 @@ function httprl_send_request($results = NULL) {
         foreach ($write as $w) {
           $id = array_search($w, $this_run);
           // Make sure ID is in the streams & status is for writing.
-          if ($id === FALSE || empty($responses[$id]->status) || $responses[$id]->status != 'in progress') {
+          if ($id === FALSE || empty($responses[$id]->status) || ($responses[$id]->status != 'Connecting.' && $responses[$id]->status != 'Writing To Server.')) {
             continue;
           }
 
@@ -1314,6 +1366,10 @@ function httprl_send_request($results = NULL) {
             $rw_done = TRUE;
           }
           else {
+            // Change status to 'Writing To Server.'
+            if ($responses[$id]->status = 'Connecting.') {
+              $responses[$id]->status = 'Writing To Server.';
+            }
             // There is more data to write to this socket. Cut what was sent
             // across the stream and resend whats left next time in the loop.
             $responses[$id]->request_left = substr($data_to_send, $bytes);
@@ -1322,23 +1378,6 @@ function httprl_send_request($results = NULL) {
         }
       }
     }
-    else {
-      $empty_runs++;
-    }
-    if ($empty_runs > 400) {
-      // If stream_select hasn't returned a valid read or write stream after
-      // 10+ seconds, error out.
-      foreach ($this_run as $id => $fp) {
-        // stream_select timed out & the request is not done.
-        $responses[$id]->error = $t('stream_select() timed out.');
-        $responses[$id]->code = HTTPRL_STREAM_SELECT_TIMEOUT;
-        $responses[$id]->status = 'Done.';
-
-        // Do post processing on the stream.
-        httprl_post_processing($id, $responses, $output);
-        continue;
-      }
-    }
     if (!$rw_done) {
       // Wait 5ms for data buffers.
       usleep(5000);
