more error handling for jingle connections

iNPUTmice created

Change summary

res/values/strings.xml                                                      |  1 
src/eu/siacs/conversations/entities/Message.java                            |  1 
src/eu/siacs/conversations/services/XmppConnectionService.java              |  1 
src/eu/siacs/conversations/ui/ConversationFragment.java                     |  3 
src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java                | 48 
src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java         |  8 
src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java           | 35 
src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java           | 43 
src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java                 |  4 
src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java |  3 
10 files changed, 90 insertions(+), 57 deletions(-)

Detailed changes

res/values/strings.xml 🔗

@@ -248,4 +248,5 @@
     <string name="edit_conference_details">Touch to edit conference details</string>
     <string name="openpgp_messages_found">OpenPGP encrypted messages found</string>
     <string name="openpgp_click_to_decrypt">Click here to enter passphrase and decrypt messages</string>
+    <string name="reception_failed">Reception failed</string>
 </resources>

src/eu/siacs/conversations/entities/Message.java 🔗

@@ -12,6 +12,7 @@ public class Message extends AbstractEntity {
 	
 	public static final String TABLENAME = "messages";
 
+	public static final int STATUS_RECEPTION_FAILED = -3;
 	public static final int STATUS_RECEIVED_OFFER = -2;
 	public static final int STATUS_RECIEVING = -1;
 	public static final int STATUS_RECIEVED = 0;

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -232,6 +232,7 @@ public class XmppConnectionService extends Service {
 				accountChangedListener.onAccountListChangedListener();
 			}
 			if (account.getStatus() == Account.STATUS_ONLINE) {
+				mJingleConnectionManager.cancelInTransmission();
 				List<Conversation> conversations = getConversations();
 				for (int i = 0; i < conversations.size(); ++i) {
 					if (conversations.get(i).getAccount() == account) {

src/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -252,6 +252,9 @@ public class ConversationFragment extends Fragment {
 					info = getString(R.string.send_rejected);
 					error = true;
 					break;
+				case Message.STATUS_RECEPTION_FAILED:
+					info = getString(R.string.reception_failed);
+					error = true;
 				default:
 					if (multiReceived) {
 						info = message.getCounterpart();

src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java 🔗

@@ -75,7 +75,7 @@ public class JingleConnection {
 		}
 	};
 	
-	final OnFileTransmitted onFileTransmitted = new OnFileTransmitted() {
+	final OnFileTransmissionStatusChanged onFileTransmissionSatusChanged = new OnFileTransmissionStatusChanged() {
 		
 		@Override
 		public void onFileTransmitted(JingleFile file) {
@@ -96,6 +96,11 @@ public class JingleConnection {
 			}
 			Log.d("xmppService","sucessfully transmitted file:"+file.getAbsolutePath());
 		}
+
+		@Override
+		public void onFileTransferAborted() {
+			JingleConnection.this.cancel();
+		}
 	};
 	
 	private OnProxyActivated onProxyActivated = new OnProxyActivated() {
@@ -104,9 +109,9 @@ public class JingleConnection {
 		public void success() {
 			if (initiator.equals(account.getFullJid())) {
 				Log.d("xmppService","we were initiating. sending file");
-				transport.send(file,onFileTransmitted);
+				transport.send(file,onFileTransmissionSatusChanged);
 			} else {
-				transport.receive(file,onFileTransmitted);
+				transport.receive(file,onFileTransmissionSatusChanged);
 				Log.d("xmppService","we were responding. receiving file");
 			}
 		}
@@ -140,14 +145,14 @@ public class JingleConnection {
 			Reason reason = packet.getReason();
 			if (reason!=null) {
 				if (reason.hasChild("cancel")) {
-					this.receiveCancel();
+					this.cancel();
 				} else if (reason.hasChild("success")) {
 					this.receiveSuccess();
 				} else {
-					this.receiveCancel();
+					this.cancel();
 				}
 			} else {
-				this.receiveCancel();
+				this.cancel();
 			}
 		} else if (packet.isAction("session-accept")) {
 			returnResult = receiveAccept(packet);
@@ -279,13 +284,13 @@ public class JingleConnection {
 					}
 					this.file.setExpectedSize(size);
 				} else {
-					this.sendCancel();
+					this.cancel();
 				}
 			} else {
-				this.sendCancel();
+				this.cancel();
 			}
 		} else {
-			this.sendCancel();
+			this.cancel();
 		}
 	}
 	
@@ -405,7 +410,7 @@ public class JingleConnection {
 						connection.setActivated(true);
 					} else {
 						Log.d("xmppService","activated connection not found");
-						this.sendCancel();
+						this.cancel();
 					}
 				}
 				return true;
@@ -479,10 +484,10 @@ public class JingleConnection {
 			} else {
 				if (initiator.equals(account.getFullJid())) {
 					Log.d("xmppService","we were initiating. sending file");
-					connection.send(file,onFileTransmitted);
+					connection.send(file,onFileTransmissionSatusChanged);
 				} else {
 					Log.d("xmppService","we were responding. receiving file");
-					connection.receive(file,onFileTransmitted);
+					connection.receive(file,onFileTransmissionSatusChanged);
 				}
 			}
 		}
@@ -553,7 +558,7 @@ public class JingleConnection {
 		}
 		this.transportId = packet.getJingleContent().getTransportId();
 		this.transport = new JingleInbandTransport(this.account,this.responder,this.transportId,this.ibbBlockSize);
-		this.transport.receive(file, onFileTransmitted);
+		this.transport.receive(file, onFileTransmissionSatusChanged);
 		JinglePacket answer = bootstrapPacket("transport-accept");
 		Content content = new Content("initiator", "a-file-offer");
 		content.setTransportId(this.transportId);
@@ -582,7 +587,7 @@ public class JingleConnection {
 				
 				@Override
 				public void established() {
-					JingleConnection.this.transport.send(file, onFileTransmitted);
+					JingleConnection.this.transport.send(file, onFileTransmissionSatusChanged);
 				}
 			});
 			return true;
@@ -598,10 +603,21 @@ public class JingleConnection {
 		this.mJingleConnectionManager.finishConnection(this);
 	}
 	
-	private void receiveCancel() {
+	void cancel() {
+		this.sendCancel();
 		this.disconnect();
+		if (this.message!=null) {
+			if (this.responder.equals(account.getFullJid())) {
+				this.mXmppConnectionService.markMessage(this.message, Message.STATUS_RECEPTION_FAILED);
+			} else {
+				if (this.status == STATUS_INITIATED) {
+					this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_REJECTED);
+				} else {
+					this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED);
+				}
+			}
+		}
 		this.status = STATUS_CANCELED;
-		this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_REJECTED);
 		this.mJingleConnectionManager.finishConnection(this);
 	}
 	

src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java 🔗

@@ -155,4 +155,12 @@ public class JingleConnectionManager {
 			Log.d("xmppService","no sid found in incomming ibb packet");
 		}
 	}
+	
+	public void cancelInTransmission() {
+		for(JingleConnection connection : this.connections) {
+			if (connection.getStatus() == JingleConnection.STATUS_TRANSMITTING) {
+				connection.cancel();
+			}
+		}
+	}
 }

src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java 🔗

@@ -33,7 +33,7 @@ public class JingleInbandTransport extends JingleTransport {
 	private long remainingSize;
 	private MessageDigest digest;
 	
-	private OnFileTransmitted onFileTransmitted;
+	private OnFileTransmissionStatusChanged onFileTransmissionStatusChanged;
 
 	private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() {
 		@Override
@@ -77,8 +77,8 @@ public class JingleInbandTransport extends JingleTransport {
 	}
 
 	@Override
-	public void receive(JingleFile file, OnFileTransmitted callback) {
-		this.onFileTransmitted = callback;
+	public void receive(JingleFile file, OnFileTransmissionStatusChanged callback) {
+		this.onFileTransmissionStatusChanged = callback;
 		this.file = file;
 		try {
 			this.digest = MessageDigest.getInstance("SHA-1");
@@ -86,27 +86,35 @@ public class JingleInbandTransport extends JingleTransport {
 			file.getParentFile().mkdirs();
 			file.createNewFile();
 			this.fileOutputStream = getOutputStream(file);
+			if (this.fileOutputStream==null) {
+				callback.onFileTransferAborted();
+				return;
+			}
 			this.remainingSize = file.getExpectedSize();
 		} catch (NoSuchAlgorithmException e) {
-			e.printStackTrace();
+			callback.onFileTransferAborted();
 		} catch (IOException e) {
-			e.printStackTrace();
+			callback.onFileTransferAborted();
 		}
 	}
 
 	@Override
-	public void send(JingleFile file, OnFileTransmitted callback) {
-		this.onFileTransmitted = callback;
+	public void send(JingleFile file, OnFileTransmissionStatusChanged callback) {
+		this.onFileTransmissionStatusChanged = callback;
 		this.file = file;
 		try {
 			this.digest = MessageDigest.getInstance("SHA-1");
 			this.digest.reset();
 			fileInputStream = this.getInputStream(file);
+			if (fileInputStream==null) {
+				callback.onFileTransferAborted();
+				return;
+			}
 			this.sendNextBlock();
 		} catch (FileNotFoundException e) {
-			e.printStackTrace();
+			callback.onFileTransferAborted();
 		} catch (NoSuchAlgorithmException e) {
-			e.printStackTrace();
+			callback.onFileTransferAborted();
 		}
 	}
 
@@ -117,7 +125,7 @@ public class JingleInbandTransport extends JingleTransport {
 			if (count == -1) {
 				file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
 				fileInputStream.close();
-				this.onFileTransmitted.onFileTransmitted(file);
+				this.onFileTransmissionStatusChanged.onFileTransmitted(file);
 			} else {
 				this.digest.update(buffer);
 				String base64 = Base64.encodeToString(buffer, Base64.NO_WRAP);
@@ -134,8 +142,7 @@ public class JingleInbandTransport extends JingleTransport {
 				this.seq++;
 			}
 		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
+			this.onFileTransmissionStatusChanged.onFileTransferAborted();
 		}
 	}
 
@@ -154,10 +161,10 @@ public class JingleInbandTransport extends JingleTransport {
 				file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
 				fileOutputStream.flush();
 				fileOutputStream.close();
-				this.onFileTransmitted.onFileTransmitted(file);
+				this.onFileTransmissionStatusChanged.onFileTransmitted(file);
 			}
 		} catch (IOException e) {
-			e.printStackTrace();
+			this.onFileTransmissionStatusChanged.onFileTransferAborted();
 		}
 	}
 

src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java 🔗

@@ -10,7 +10,6 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 
-import android.util.Log;
 import eu.siacs.conversations.utils.CryptoHelper;
 
 public class JingleSocks5Transport extends JingleTransport {
@@ -84,7 +83,7 @@ public class JingleSocks5Transport extends JingleTransport {
 		
 	}
 
-	public void send(final JingleFile file, final OnFileTransmitted callback) {
+	public void send(final JingleFile file, final OnFileTransmissionStatusChanged callback) {
 		new Thread(new Runnable() {
 			
 			@Override
@@ -94,37 +93,34 @@ public class JingleSocks5Transport extends JingleTransport {
 					MessageDigest digest = MessageDigest.getInstance("SHA-1");
 					digest.reset();
 					fileInputStream = getInputStream(file);
+					if (fileInputStream==null) {
+						callback.onFileTransferAborted();
+						return;
+					}
 					int count;
-					long txBytes = 0;
 					byte[] buffer = new byte[8192];
 					while ((count = fileInputStream.read(buffer)) > 0) {
-						txBytes += count;
 						outputStream.write(buffer, 0, count);
 						digest.update(buffer, 0, count);
 					}
-					Log.d("xmppService","txBytes="+txBytes);
 					outputStream.flush();
 					file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
 					if (callback!=null) {
 						callback.onFileTransmitted(file);
 					}
 				} catch (FileNotFoundException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
+					callback.onFileTransferAborted();
 				} catch (IOException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
+					callback.onFileTransferAborted();
 				} catch (NoSuchAlgorithmException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
+					callback.onFileTransferAborted();
 				} finally {
 					try {
 						if (fileInputStream != null) {
 							fileInputStream.close();
 						}
 					} catch (IOException e) {
-						// TODO Auto-generated catch block
-						e.printStackTrace();
+						callback.onFileTransferAborted();
 					}
 				}
 			}
@@ -132,7 +128,7 @@ public class JingleSocks5Transport extends JingleTransport {
 		
 	}
 	
-	public void receive(final JingleFile file, final OnFileTransmitted callback) {
+	public void receive(final JingleFile file, final OnFileTransmissionStatusChanged callback) {
 		new Thread(new Runnable() {
 			
 			@Override
@@ -144,35 +140,34 @@ public class JingleSocks5Transport extends JingleTransport {
 					file.getParentFile().mkdirs();
 					file.createNewFile();
 					OutputStream fileOutputStream = getOutputStream(file);
+					if (fileOutputStream==null) {
+						callback.onFileTransferAborted();
+						return;
+					}
 					long remainingSize = file.getExpectedSize();
 					byte[] buffer = new byte[8192];
 					int count = buffer.length;
-					long rxBytes = 0;
 					while(remainingSize > 0) {
 						count = inputStream.read(buffer);
 						if (count==-1) {
-							Log.d("xmppService","read end");
+							callback.onFileTransferAborted();
+							return;
 						} else {
-							rxBytes += count;
 							fileOutputStream.write(buffer, 0, count);
 							digest.update(buffer, 0, count);
 							remainingSize-=count;
 						}
 					}
-					Log.d("xmppService","rx bytes="+rxBytes);
 					fileOutputStream.flush();
 					fileOutputStream.close();
 					file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
 					callback.onFileTransmitted(file);
 				} catch (FileNotFoundException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
+					callback.onFileTransferAborted();
 				} catch (IOException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
+					callback.onFileTransferAborted();
 				} catch (NoSuchAlgorithmException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
+					callback.onFileTransferAborted();
 				}
 			}
 		}).start();

src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java 🔗

@@ -19,8 +19,8 @@ import android.util.Log;
 
 public abstract class JingleTransport {
 	public abstract void connect(final OnTransportConnected callback);
-	public abstract void receive(final JingleFile file, final OnFileTransmitted callback);
-	public abstract void send(final JingleFile file, final OnFileTransmitted callback);
+	public abstract void receive(final JingleFile file, final OnFileTransmissionStatusChanged callback);
+	public abstract void send(final JingleFile file, final OnFileTransmissionStatusChanged callback);
 	private byte[] iv = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0xf};
 	
 	protected InputStream getInputStream(JingleFile file) throws FileNotFoundException {