1package eu.siacs.conversations.xmpp.jingle;
2
3import java.io.FileNotFoundException;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.OutputStream;
7import java.net.Socket;
8import java.net.UnknownHostException;
9import java.security.MessageDigest;
10import java.security.NoSuchAlgorithmException;
11import java.util.Arrays;
12
13import android.util.Log;
14import eu.siacs.conversations.utils.CryptoHelper;
15
16public class JingleSocks5Transport extends JingleTransport {
17 private JingleCandidate candidate;
18 private String destination;
19 private OutputStream outputStream;
20 private InputStream inputStream;
21 private boolean isEstablished = false;
22 private boolean activated = false;
23 protected Socket socket;
24
25 public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
26 this.candidate = candidate;
27 try {
28 MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
29 StringBuilder destBuilder = new StringBuilder();
30 destBuilder.append(jingleConnection.getSessionId());
31 if (candidate.isOurs()) {
32 destBuilder.append(jingleConnection.getAccountJid());
33 destBuilder.append(jingleConnection.getCounterPart());
34 } else {
35 destBuilder.append(jingleConnection.getCounterPart());
36 destBuilder.append(jingleConnection.getAccountJid());
37 }
38 mDigest.reset();
39 this.destination = CryptoHelper.bytesToHex(mDigest
40 .digest(destBuilder.toString().getBytes()));
41 } catch (NoSuchAlgorithmException e) {
42
43 }
44 }
45
46 public void connect(final OnTransportConnected callback) {
47 new Thread(new Runnable() {
48
49 @Override
50 public void run() {
51 try {
52 socket = new Socket(candidate.getHost(), candidate.getPort());
53 inputStream = socket.getInputStream();
54 outputStream = socket.getOutputStream();
55 byte[] login = { 0x05, 0x01, 0x00 };
56 byte[] expectedReply = { 0x05, 0x00 };
57 byte[] reply = new byte[2];
58 outputStream.write(login);
59 inputStream.read(reply);
60 if (Arrays.equals(reply, expectedReply)) {
61 String connect = "" + '\u0005' + '\u0001' + '\u0000' + '\u0003'
62 + '\u0028' + destination + '\u0000' + '\u0000';
63 outputStream.write(connect.getBytes());
64 byte[] result = new byte[2];
65 inputStream.read(result);
66 int status = result[1];
67 if (status == 0) {
68 isEstablished = true;
69 callback.established();
70 } else {
71 callback.failed();
72 }
73 } else {
74 socket.close();
75 callback.failed();
76 }
77 } catch (UnknownHostException e) {
78 callback.failed();
79 } catch (IOException e) {
80 callback.failed();
81 }
82 }
83 }).start();
84
85 }
86
87 public void send(final JingleFile file, final OnFileTransmitted callback) {
88 new Thread(new Runnable() {
89
90 @Override
91 public void run() {
92 InputStream fileInputStream = null;
93 try {
94 MessageDigest digest = MessageDigest.getInstance("SHA-1");
95 digest.reset();
96 fileInputStream = getInputStream(file);
97 int count;
98 long txBytes = 0;
99 byte[] buffer = new byte[8192];
100 while ((count = fileInputStream.read(buffer)) > 0) {
101 txBytes += count;
102 outputStream.write(buffer, 0, count);
103 digest.update(buffer, 0, count);
104 }
105 Log.d("xmppService","txBytes="+txBytes);
106 outputStream.flush();
107 file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
108 if (callback!=null) {
109 callback.onFileTransmitted(file);
110 }
111 } catch (FileNotFoundException e) {
112 // TODO Auto-generated catch block
113 e.printStackTrace();
114 } catch (IOException e) {
115 // TODO Auto-generated catch block
116 e.printStackTrace();
117 } catch (NoSuchAlgorithmException e) {
118 // TODO Auto-generated catch block
119 e.printStackTrace();
120 } finally {
121 try {
122 if (fileInputStream != null) {
123 fileInputStream.close();
124 }
125 } catch (IOException e) {
126 // TODO Auto-generated catch block
127 e.printStackTrace();
128 }
129 }
130 }
131 }).start();
132
133 }
134
135 public void receive(final JingleFile file, final OnFileTransmitted callback) {
136 new Thread(new Runnable() {
137
138 @Override
139 public void run() {
140 try {
141 MessageDigest digest = MessageDigest.getInstance("SHA-1");
142 digest.reset();
143 inputStream.skip(45);
144 file.getParentFile().mkdirs();
145 file.createNewFile();
146 OutputStream fileOutputStream = getOutputStream(file);
147 long remainingSize = file.getExpectedSize();
148 byte[] buffer = new byte[8192];
149 int count = buffer.length;
150 long rxBytes = 0;
151 while(remainingSize > 0) {
152 count = inputStream.read(buffer);
153 if (count==-1) {
154 Log.d("xmppService","read end");
155 } else {
156 rxBytes += count;
157 fileOutputStream.write(buffer, 0, count);
158 digest.update(buffer, 0, count);
159 remainingSize-=count;
160 }
161 }
162 Log.d("xmppService","rx bytes="+rxBytes);
163 fileOutputStream.flush();
164 fileOutputStream.close();
165 file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
166 callback.onFileTransmitted(file);
167 } catch (FileNotFoundException e) {
168 // TODO Auto-generated catch block
169 e.printStackTrace();
170 } catch (IOException e) {
171 // TODO Auto-generated catch block
172 e.printStackTrace();
173 } catch (NoSuchAlgorithmException e) {
174 // TODO Auto-generated catch block
175 e.printStackTrace();
176 }
177 }
178 }).start();
179 }
180
181 public boolean isProxy() {
182 return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
183 }
184
185 public boolean needsActivation() {
186 return (this.isProxy() && !this.activated);
187 }
188
189 public void disconnect() {
190 if (this.socket!=null) {
191 try {
192 this.socket.close();
193 } catch (IOException e) {
194
195 }
196 }
197 }
198
199 public boolean isEstablished() {
200 return this.isEstablished;
201 }
202
203 public JingleCandidate getCandidate() {
204 return this.candidate;
205 }
206
207 public void setActivated(boolean activated) {
208 this.activated = activated;
209 }
210}