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 isEstablished = true;
73 callback.established();
74 } else {
75 callback.failed();
76 }
77 } else {
78 socket.close();
79 callback.failed();
80 }
81 } catch (UnknownHostException e) {
82 callback.failed();
83 } catch (IOException e) {
84 callback.failed();
85 }
86 }
87 }).start();
88
89 }
90
91 public void send(final JingleFile file, final OnFileTransmitted callback) {
92 new Thread(new Runnable() {
93
94 @Override
95 public void run() {
96 FileInputStream fileInputStream = null;
97 try {
98 MessageDigest digest = MessageDigest.getInstance("SHA-1");
99 digest.reset();
100 fileInputStream = new FileInputStream(file);
101 int count;
102 byte[] buffer = new byte[8192];
103 while ((count = fileInputStream.read(buffer)) > 0) {
104 outputStream.write(buffer, 0, count);
105 digest.update(buffer, 0, count);
106 }
107 outputStream.flush();
108 file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
109 if (callback!=null) {
110 callback.onFileTransmitted(file);
111 }
112 } catch (FileNotFoundException e) {
113 // TODO Auto-generated catch block
114 e.printStackTrace();
115 } catch (IOException e) {
116 // TODO Auto-generated catch block
117 e.printStackTrace();
118 } catch (NoSuchAlgorithmException e) {
119 // TODO Auto-generated catch block
120 e.printStackTrace();
121 } finally {
122 try {
123 if (fileInputStream != null) {
124 fileInputStream.close();
125 }
126 } catch (IOException e) {
127 // TODO Auto-generated catch block
128 e.printStackTrace();
129 }
130 }
131 }
132 }).start();
133
134 }
135
136 public void receive(final JingleFile file, final OnFileTransmitted callback) {
137 new Thread(new Runnable() {
138
139 @Override
140 public void run() {
141 try {
142 MessageDigest digest = MessageDigest.getInstance("SHA-1");
143 digest.reset();
144 inputStream.skip(45);
145 file.getParentFile().mkdirs();
146 file.createNewFile();
147 FileOutputStream fileOutputStream = new FileOutputStream(file);
148 long remainingSize = file.getExpectedSize();
149 byte[] buffer = new byte[8192];
150 int count = buffer.length;
151 while(remainingSize > 0) {
152 Log.d("xmppService","remaning size:"+remainingSize);
153 if (remainingSize<=count) {
154 count = (int) remainingSize;
155 }
156 count = inputStream.read(buffer, 0, count);
157 if (count==-1) {
158 Log.d("xmppService","end of stream");
159 } else {
160 fileOutputStream.write(buffer, 0, count);
161 digest.update(buffer, 0, count);
162 remainingSize-=count;
163 }
164 }
165 fileOutputStream.flush();
166 fileOutputStream.close();
167 file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
168 Log.d("xmppService","transmitted filename was: "+file.getAbsolutePath());
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 void disconnect() {
189 if (this.socket!=null) {
190 try {
191 this.socket.close();
192 Log.d("xmppService","cloesd socket with "+candidate.getHost()+":"+candidate.getPort());
193 } catch (IOException e) {
194 Log.d("xmppService","error closing socket with "+candidate.getHost()+":"+candidate.getPort());
195 }
196 }
197 }
198
199 public boolean isEstablished() {
200 return this.isEstablished;
201 }
202
203 public JingleCandidate getCandidate() {
204 return this.candidate;
205 }
206}