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