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