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