Index: wp-includes/comment.php
===================================================================
--- wp-includes/comment.php	(revision 5852)
+++ wp-includes/comment.php	(working copy)
@@ -668,14 +668,41 @@
 
 
 function generic_ping($post_id = 0) {
+	$errors = get_option('ping_errors');
+	if ( !is_array($errors) )
+		$errors = array();
 	$services = get_option('ping_sites');
 	$services = preg_replace("|(\s)+|", '$1', $services); // Kill dupe lines
 	$services = trim($services);
 	if ( '' != $services ) {
+		$update_ping_sites = false;
 		$services = explode("\n", $services);
-		foreach ( (array) $services as $service )
-			weblog_ping($service);
+		foreach ( (array) $services as $i => $service ) {
+			$error = weblog_ping($service);
+			if ( $error ) {
+				if ( !isset($errors[$service]) )
+					$errors[$service] = array('count' => 0);
+				$errors[$service]['count']++;
+				$errors[$service]['last_message'] = $error;
+				$statusCode = preg_match('/HTTP status: (\d\d\d)/', $error, $reg) ? intval($reg[1]) : false;
+				// Remove servers that keep failing, and allow server owners
+				// to speed up the process by returning 403 Forbidden, 404 
+				// Not Found or 410 Gone
+				if ( $errors[$service]['count'] > 20 ||
+				     $errors[$service]['count'] > 3 && in_array($statusCode, array(403, 404, 410))) {
+
+					unset($services[$i]);
+					unset($errors[$service]);
+					$update_ping_sites = true;
+				}
+			} else {
+				unset($errors[$service]);
+			}
+		}
+		if ($update_ping_sites)
+			update_option('ping_sites', implode("\n", $services));
 	}
+	update_option('ping_errors', $errors);
 
 	return $post_id;
 }
@@ -799,8 +826,27 @@
 	// when set to true, this outputs debug messages by itself
 	$client->debug = false;
 	$home = trailingslashit( get_option('home') );
-	if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
+	$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') );
+	// If there was an XML-RPC service ("200" is a required but not sufficient
+	// condition) but it did not know extendedPing, try a regular ping
+	if ( $client->isError() && substr($client->getHttpStatus(), 0, 3) == '200' )
 		$client->query('weblogUpdates.ping', get_option('blogname'), $home);
+
+	$error = false;
+	if ( $client->isError() ) {
+		$httpStatus = $client->getHttpStatus();
+		if ($httpStatus && substr($httpStatus, 0, 3) != '200')
+			$error = 'HTTP status: ' . $httpStatus;
+		else
+			$error = $client->getErrorMessage();
+	} else {
+		$response = $client->getResponse();
+		if ( !isset($response['flerror']) || $response['flerror'] ) {
+			$error = isset($response['message']) && $response['message']
+			    ? $response['message'] : 'Invalid response';
+		}
+	}
+	return $error;
 }
 
 //
Index: wp-includes/class-IXR.php
===================================================================
--- wp-includes/class-IXR.php	(revision 5852)
+++ wp-includes/class-IXR.php	(working copy)
@@ -460,6 +460,7 @@
 	var $timeout;
     // Storage place for an error message
     var $error = false;
+    var $httpStatus = false;
     function IXR_Client($server, $path = false, $port = 80, $timeout = false) {
         if (!$path) {
             // Assume we have been given a URL instead
@@ -513,8 +514,14 @@
             $line = fgets($fp, 4096);
             if (!$gotFirstLine) {
                 // Check line for '200'
-                if (strstr($line, '200') === false) {
-                    $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
+                if (preg_match('|^HTTP/1\.. ((\d\d\d) .*)|', $line, $reg)) {
+                    $this->httpStatus = $reg[1];
+                    if ($reg[2] != '200') {
+                        $this->error = new IXR_Error(-32300, 'transport error - ' . $this->httpStatus);
+                        return false;
+                    }
+                } else {
+                    $this->error = new IXR_Error(-32300, 'transport error - no headers received' . $line);
                     return false;
                 }
                 $gotFirstLine = true;
@@ -554,6 +561,10 @@
     function getErrorCode() {
         return $this->error->code;
     }
+    function getHttpStatus() {
+        // e.g. "200 OK" or "404 Not found"
+        return $this->httpStatus;
+    }
     function getErrorMessage() {
         return $this->error->message;
     }
Index: wp-admin/options-writing.php
===================================================================
--- wp-admin/options-writing.php	(revision 5852)
+++ wp-admin/options-writing.php	(working copy)
@@ -102,6 +102,32 @@
 
 <textarea name="ping_sites" id="ping_sites" style="width: 98%;" rows="3" cols="50"><?php form_option('ping_sites'); ?></textarea>
 
+<p><?php _e('These update services failed your last update. You should consider removing these services from the list above.') ?></p>
+<dl>
+<?php
+$has_errors = false;
+$services = get_option('ping_sites');
+$errors = get_option('ping_errors');
+if (is_array($errors)) 
+foreach (get_option('ping_errors') as $service => $error) :
+if (preg_match('/(^|\s)' . preg_quote($service, '/') . '($|\s)/', $services)) :
+echo "<dt>" . htmlspecialchars($service) . "</dt>";
+echo "<dd>";
+if ($error['count'] > 1) :
+printf(__('Failed %d times. Last error message was: '), $error['count']);
+endif;
+echo htmlspecialchars($error['last_message']);
+echo "</dd>";
+$has_errors = true;
+endif;
+endforeach;
+
+if (!$has_errors) :
+echo "<dd><em>" . __('No errors') . "</em></dd>";
+endif;
+?>
+</dl>
+
 <?php else : ?>
 
 	<p><?php printf(__('WordPress is not notifying any <a href="http://codex.wordpress.org/Update_Services">Update Services</a> because of your blog\'s <a href="%s">privacy settings</a>.'), 'options-privacy.php'); ?>
@@ -118,4 +144,4 @@
 </form>
 </div>
 
-<?php include('./admin-footer.php') ?>
\ No newline at end of file
+<?php include('./admin-footer.php') ?>
