3 /// Class wrapper to encapsulate the Blackberry USB logical socket
7 Copyright (C) 2005, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
25 #include "protostructs.h"
36 Socket::Socket(Device
&dev
, int writeEndpoint
, int readEndpoint
)
38 m_writeEp(writeEndpoint
),
39 m_readEp(readEndpoint
),
49 // trap exceptions in the destructor
51 // a non-default socket has been opened, close it
54 catch( std::runtime_error
&re
) {
55 // do nothing... log it?
56 dout("Exception caught in ~Socket: " << re
.what());
60 void Socket::Open(uint16_t socket
, uint8_t flag
)
64 throw BError("Socket: already open");
70 packet
.size
= SB_SOCKET_PACKET_SIZE
;
71 packet
.command
= SB_COMMAND_OPEN_SOCKET
;
72 packet
.data
.socket
.socket
= socket
;
73 packet
.data
.socket
.param
= flag
;
75 Data
send(&packet
, packet
.size
);
77 if( !Send(send
, receive
) ) {
79 throw BError(GetLastStatus(), "Error opening socket");
82 // starting fresh, reset sequence ID
84 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
85 CheckSequence(receive
);
91 CheckSize(receive
, SB_SOCKET_PACKET_SIZE
);
92 MAKE_PACKET(rpack
, receive
);
93 if( rpack
->command
!= SB_COMMAND_OPENED_SOCKET
||
94 rpack
->data
.socket
.socket
!= socket
||
95 rpack
->data
.socket
.param
!= flag
)
97 eout("Packet:\n" << receive
);
98 throw BError("Socket: Bad OPENED packet in Open");
101 // success! save the socket
108 if( m_socket
!= 0 ) {
109 // only close non-default sockets
111 // build close command
112 Barry::Packet packet
;
114 packet
.size
= SB_SOCKET_PACKET_SIZE
;
115 packet
.command
= SB_COMMAND_CLOSE_SOCKET
;
116 packet
.data
.socket
.socket
= m_socket
;
117 packet
.data
.socket
.param
= m_flag
;
119 Data
command(&packet
, packet
.size
);
121 if( !Send(command
, response
) ) {
122 // reset so this won't be called again
126 eeout(command
, response
);
127 throw BError(GetLastStatus(), "Error closing socket");
130 // starting fresh, reset sequence ID
132 if( IS_COMMAND(response
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
133 CheckSequence(response
);
135 // still need our ACK
139 CheckSize(response
, SB_SOCKET_PACKET_SIZE
);
140 MAKE_PACKET(rpack
, response
);
141 if( rpack
->command
!= SB_COMMAND_CLOSED_SOCKET
||
142 rpack
->data
.socket
.socket
!= m_socket
||
143 rpack
->data
.socket
.param
!= m_flag
)
145 // reset so this won't be called again
149 eout("Packet:\n" << response
);
150 throw BError("Socket: Bad CLOSED packet in Close");
153 // and finally, there always seems to be an extra read of
154 // an empty packet at the end... just throw it away
155 // Receive(response);
157 // reset socket and flag
163 // sends 'send' data to device, and waits for response, using
164 // "read first, write second" order observed in capture
166 // returns true on success, on failure, use GetLastStatus() for kernel
168 bool Socket::Send(const Data
&send
, Data
&receive
)
170 IO rd
= m_dev
.ABulkRead(m_readEp
, receive
);
171 IO wr
= m_dev
.ABulkWrite(m_writeEp
, send
);
177 m_lastStatus
= rd
.GetStatus();
178 receive
.ReleaseBuffer(m_lastStatus
>= 0 ? rd
.GetSize() : 0);
179 return m_lastStatus
>= 0;
182 bool Socket::Receive(Data
&receive
)
184 IO rd
= m_dev
.ABulkRead(m_readEp
, receive
);
188 m_lastStatus
= rd
.GetStatus();
189 receive
.ReleaseBuffer(m_lastStatus
>= 0 ? rd
.GetSize() : 0);
190 return m_lastStatus
>= 0;
193 // appends fragment to whole... if whole is empty, simply copies, and
194 // sets command to DATA instead of FRAGMENTED. Always updates the
195 // packet size of whole, to reflect the total size
196 void Socket::AppendFragment(Data
&whole
, const Data
&fragment
)
198 if( whole
.GetSize() == 0 ) {
199 // empty, so just copy
203 // has some data already, so just append
204 int size
= whole
.GetSize();
205 unsigned char *buf
= whole
.GetBuffer(size
+ fragment
.GetSize());
206 MAKE_PACKET(fpack
, fragment
);
207 int fragsize
= fragment
.GetSize() - SB_FRAG_HEADER_SIZE
;
209 memcpy(buf
+size
, &fpack
->data
.db
.data
.fragment
, fragsize
);
210 whole
.ReleaseBuffer(size
+ fragsize
);
213 // update whole's size and command type for future sanity
214 Barry::Packet
*wpack
= (Barry::Packet
*) whole
.GetBuffer();
215 wpack
->size
= (uint16_t) whole
.GetSize();
216 wpack
->command
= SB_COMMAND_DB_DATA
;
217 // don't need to call ReleaseBuffer here, since we're not changing
218 // the real size size
221 void Socket::CheckSequence(const Data
&seq
)
223 // if( m_socket == 0 ) {
224 // // don't do any sequence checking on socket 0
228 MAKE_PACKET(spack
, seq
);
229 if( (unsigned int) seq
.GetSize() < SB_SEQUENCE_PACKET_SIZE
) {
230 eout("Short sequence packet:\n" << seq
);
231 throw BError("Socket: invalid sequence packet");
234 // we'll cheat here... if the packet's sequence is 0, we'll
235 // silently restart, otherwise, fail
236 uint32_t sequenceId
= spack
->data
.sequence
.sequenceId
;
237 if( sequenceId
== 0 ) {
238 // silently restart (will advance below)
242 if( sequenceId
!= m_sequenceId
) {
243 if( m_socket
!= 0 ) {
244 eout("Socket sequence: " << m_sequenceId
245 << ". Packet sequence: " << sequenceId
);
246 throw BError("Socket: out of sequence");
249 dout("Bad sequence on socket 0: expected: "
251 << ". Packet sequence: " << sequenceId
);
260 // sends the send packet down to the device, fragmenting if
261 // necessary, and returns the response in receive, defragmenting
263 // Blocks until response received or timed out in Usb::Device
264 bool Socket::Packet(const Data
&send
, Data
&receive
)
267 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
268 // function that forces the socket number to the correct current value,
269 // but putting it here means a copy on every packet.
271 // force socket to our socket
272 Data send = sendorig;
273 Barry::Packet *sspack = (Barry::Packet *)send.GetBuffer(2);
274 sspack->socket = GetSocket();
277 MAKE_PACKET(spack
, send
);
278 if( send
.GetSize() < MIN_PACKET_SIZE
||
279 (spack
->command
!= SB_COMMAND_DB_DATA
&&
280 spack
->command
!= SB_COMMAND_DB_DONE
) )
282 // we don't do that around here
283 throw std::logic_error("Socket: unknown send data in Packet()");
286 if( send
.GetSize() > MAX_PACKET_SIZE
) {
287 // not yet implemented
288 throw std::logic_error("Socket: fragmented sends not implemented");
295 if( !Send(send
, inFrag
) )
298 bool done
= false, frag
= false;
301 MAKE_PACKET(rpack
, inFrag
);
303 // check the packet's validity
304 if( inFrag
.GetSize() > 0 ) {
309 switch( rpack
->command
)
311 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
312 CheckSequence(inFrag
);
315 case SB_COMMAND_DB_DATA
:
317 AppendFragment(receive
, inFrag
);
325 case SB_COMMAND_DB_FRAGMENTED
:
326 AppendFragment(receive
, inFrag
);
330 case SB_COMMAND_DB_DONE
:
336 eout("Command: " << rpack
->command
<< inFrag
);
337 throw BError("Socket: unhandled packet in Packet()");
343 //std::cerr << "Blank! " << blankCount << std::endl;
344 if( blankCount
== 10 ) {
345 // only ask for more data on stalled sockets
347 throw BError("Socket: 10 blank packets received");
352 // not done yet, ask for another read
353 if( !Receive(inFrag
) )
361 bool Socket::NextRecord(Data
&receive
)
363 Barry::Packet packet
;
364 packet
.socket
= GetSocket();
366 packet
.command
= SB_COMMAND_DB_DONE
;
367 packet
.data
.db
.tableCmd
= 0;
368 packet
.data
.db
.data
.db
.operation
= 0;
370 Data
command(&packet
, packet
.size
);
371 return Packet(command
, receive
);