4 silcsymbiansocketstream.cpp
\r
6 Author: Pekka Riikonen <priikone@silcnet.org>
\r
8 Copyright (C) 2006 Pekka Riikonen
\r
10 This program is free software; you can redistribute it and/or modify
\r
11 it under the terms of the GNU General Public License as published by
\r
12 the Free Software Foundation; version 2 of the License.
\r
14 This program is distributed in the hope that it will be useful,
\r
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
17 GNU General Public License for more details.
\r
21 /* In this implementation the sockets are in blocking mode, except that
\r
22 on Symbian the blocking mode is actually asynchronous, which semantically
\r
23 translates into non-blocking mode. The non-blocking mode just is not
\r
24 explicitly set because it would require us also to explicitly poll for the
\r
25 socket, which is done automatically by the Active Scheduler in blocking
\r
29 #include "silcsymbiansocketstream.h"
\r
31 /***************************** Socket Classes *******************************/
\r
33 /* Socket stream sender */
\r
35 class SilcSymbianSocketSend : public CActive {
\r
38 SilcSymbianSocketSend() : CActive(CActive::EPriorityStandard)
\r
40 CActiveScheduler::Add(this);
\r
44 ~SilcSymbianSocketSend()
\r
50 void Send(const TDesC8& buf, TSockXfrLength& ret_len)
\r
52 s->sock->Send(buf, 0, iStatus, ret_len);
\r
57 void Send(const TDesC8& buf, TSockXfrLength& ret_len,
\r
58 const char *remote_ip, int remote_port)
\r
63 remote = TInetAddr(remote_port);
\r
64 tmp = (TText *)remote_ip;
\r
65 if (remote.Input(tmp) == KErrNone) {
\r
66 s->sock->SendTo(buf, remote, 0, iStatus, ret_len);
\r
71 /* Sending callback */
\r
74 if (iStatus != KErrNone) {
\r
75 if (iStatus == KErrEof)
\r
82 /* Call stream callback */
\r
83 if (s->stream && s->stream->notifier)
\r
84 s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,
\r
85 s->stream->notifier_context);
\r
91 s->sock->CancelWrite();
\r
94 SilcSymbianSocket *s;
\r
97 /* Socket stream receiver */
\r
99 class SilcSymbianSocketReceive : public CActive {
\r
102 SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)
\r
104 CActiveScheduler::Add(this);
\r
108 ~SilcSymbianSocketReceive()
\r
116 if (!s->stream || s->stream->connected)
\r
117 s->sock->RecvOneOrMore(inbuf, 0, iStatus, inbuf_len);
\r
119 s->sock->RecvFrom(inbuf, remote, 0, iStatus);
\r
123 /* Reading callback */
\r
126 if (iStatus != KErrNone) {
\r
127 if (iStatus == KErrEof)
\r
135 inbuf_ptr = inbuf.Ptr();
\r
136 inbuf_len = inbuf.Length();
\r
138 /* Call stream callback */
\r
139 if (s->stream && s->stream->notifier)
\r
140 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
\r
141 s->stream->notifier_context);
\r
150 s->sock->CancelRecv();
\r
154 const unsigned char *inbuf_ptr;
\r
155 TSockXfrLength inbuf_len;
\r
156 SilcSymbianSocket *s;
\r
160 /* Creates symbian socket stream context */
\r
162 SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
\r
165 SilcSymbianSocket *stream;
\r
167 stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
\r
170 stream->sock = sock;
\r
173 stream->send = new SilcSymbianSocketSend;
\r
174 if (!stream->send) {
\r
179 stream->receive = new SilcSymbianSocketReceive;
\r
180 if (!stream->receive) {
\r
181 delete stream->send;
\r
189 /***************************** SILC Stream API ******************************/
\r
191 /* Stream read operation */
\r
193 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
\r
194 SilcUInt32 buf_len)
\r
196 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
197 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
198 SilcSymbianSocketReceive *recv = s->receive;
\r
201 if (s->error || !s->stream)
\r
205 if (!recv->inbuf_len() || !recv->inbuf_ptr)
\r
208 len = recv->inbuf_len();
\r
212 /* Copy the read data */
\r
213 memcpy(buf, recv->inbuf_ptr, len);
\r
215 recv->inbuf_ptr = NULL;
\r
216 if (len < recv->inbuf_len())
\r
217 recv->inbuf_ptr += len;
\r
222 /* Stream write operation */
\r
224 int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
\r
225 SilcUInt32 data_len)
\r
227 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
228 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
229 SilcSymbianSocketSend *send = s->send;
\r
230 TSockXfrLength ret_len;
\r
231 TPtrC8 write_buf(data, data_len);
\r
233 if (s->would_block)
\r
235 if (s->error || !s->stream)
\r
241 send->Send(write_buf, ret_len);
\r
242 if (send->iStatus.Int() != KErrNone) {
\r
243 if (send->iStatus.Int() == KErrEof)
\r
251 s->would_block = 0;
\r
252 if (ret_len() < data_len)
\r
253 s->would_block = 1;
\r
258 /* Receive UDP packet, connected socket. */
\r
260 int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
\r
261 SilcUInt32 buf_len)
\r
263 return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
\r
266 /* Send UDP packet, connected socket. */
\r
268 int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
\r
269 SilcUInt32 data_len)
\r
271 SilcSocketStream sock = (SilcSocketStream)stream;
\r
273 /* In connectionless state check if remote IP and port is provided */
\r
274 if (!sock->connected && sock->ip && sock->port)
\r
275 return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
\r
277 /* In connected state use normal writing to socket. */
\r
278 return silc_socket_stream_write(stream, data, data_len);
\r
281 /* Receive UDP packet, connectionless socket */
\r
283 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
\r
284 SilcUInt32 remote_ip_addr_size, int *remote_port,
\r
285 unsigned char *buf, SilcUInt32 buf_len)
\r
287 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
288 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
289 SilcSymbianSocketReceive *recv = s->receive;
\r
294 if (!recv->inbuf_len() || !recv->inbuf_ptr)
\r
297 len = recv->inbuf_len();
\r
301 /* Copy the read data */
\r
302 memcpy(buf, recv->inbuf_ptr, len);
\r
304 recv->inbuf_ptr = NULL;
\r
305 if (len < recv->inbuf_len())
\r
306 recv->inbuf_ptr += len;
\r
308 if (remote_ip_addr && remote_ip_addr_size && remote_port) {
\r
310 recv->remote.Output(ip);
\r
311 silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
\r
313 *remote_port = recv->remote.Port();
\r
319 /* Send UDP packet, connectionless socket */
\r
321 int silc_net_udp_send(SilcStream stream,
\r
322 const char *remote_ip_addr, int remote_port,
\r
323 const unsigned char *data, SilcUInt32 data_len)
\r
325 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
326 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
327 SilcSymbianSocketSend *send = s->send;
\r
328 TSockXfrLength ret_len;
\r
329 TPtrC8 write_buf(data, data_len);
\r
331 if (s->would_block)
\r
337 send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
\r
338 if (send->iStatus.Int() != KErrNone) {
\r
339 if (send->iStatus.Int() == KErrEof)
\r
347 s->would_block = 0;
\r
348 if (ret_len() < data_len)
\r
349 s->would_block = 1;
\r
354 /* Closes socket */
\r
356 SilcBool silc_socket_stream_close(SilcStream stream)
\r
358 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
359 SilcSymbianSocket *s;
\r
361 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
\r
362 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
\r
365 s = (SilcSymbianSocket *)socket_stream->sock;
\r
371 /* Destroys the stream */
\r
373 void silc_socket_stream_destroy(SilcStream stream)
\r
375 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
376 SilcSymbianSocket *s;
\r
378 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
\r
379 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
\r
382 s = (SilcSymbianSocket *)socket_stream->sock;
\r
384 silc_socket_stream_close(stream);
\r
385 silc_free(socket_stream->ip);
\r
386 silc_free(socket_stream->hostname);
\r
387 silc_free(socket_stream);
\r
398 /* Sets stream notification callback for the stream */
\r
400 void silc_socket_stream_notifier(SilcStream stream,
\r
401 SilcSchedule schedule,
\r
402 SilcStreamNotifier callback,
\r
405 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
406 SilcSymbianSocket *s;
\r
408 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
\r
409 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
\r
412 s = (SilcSymbianSocket *)socket_stream->sock;
\r
414 s->stream = socket_stream;
\r
418 socket_stream->notifier = callback;
\r
419 socket_stream->notifier_context = context;
\r
420 socket_stream->schedule = schedule;
\r