4 silcsymbiansocketstream.cpp
6 Author: Pekka Riikonen <priikone@silcnet.org>
8 Copyright (C) 2006 - 2007 Pekka Riikonen
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; version 2 of the License.
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. See the
17 GNU General Public License for more details.
21 /* In this implementation the sockets are in blocking mode, except that
22 on Symbian the blocking mode is actually asynchronous, which semantically
23 translates into non-blocking mode. The non-blocking mode just is not
24 explicitly set because it would require us also to explicitly poll for the
25 socket, which is done automatically by the Active Scheduler in blocking
29 #include "silcsymbiansocketstream.h"
31 /***************************** Socket Classes *******************************/
33 /* Socket stream sender */
35 class SilcSymbianSocketSend : public CActive {
38 SilcSymbianSocketSend() : CActive(CActive::EPriorityStandard)
40 CActiveScheduler::Add(this);
44 ~SilcSymbianSocketSend()
50 void Send(const TDesC8& buf, TSockXfrLength& ret_len)
52 SILC_LOG_DEBUG(("Send()"));
53 s->sock->Send(buf, 0, iStatus, ret_len);
59 void Send(const TDesC8& buf, TSockXfrLength& ret_len,
60 const char *remote_ip, int remote_port)
65 SILC_LOG_DEBUG(("Send()"));
67 remote = TInetAddr(remote_port);
68 tmp = (TText *)remote_ip;
69 if (remote.Input(tmp) == KErrNone) {
70 s->sock->SendTo(buf, remote, 0, iStatus, ret_len);
76 /* Sending callback */
79 SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
81 if (iStatus != KErrNone) {
82 if (iStatus == KErrEof)
89 /* Call stream callback */
92 if (s->stream && s->stream->notifier)
93 s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,
94 s->stream->notifier_context);
99 virtual void DoCancel()
101 s->sock->CancelWrite();
104 SilcSymbianSocket *s;
107 /* Socket stream receiver */
109 class SilcSymbianSocketReceive : public CActive {
112 SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)
114 CActiveScheduler::Add(this);
118 ~SilcSymbianSocketReceive()
126 SILC_LOG_DEBUG(("Read()"));
128 if (s->stream && s->stream->connected)
129 s->sock->RecvOneOrMore(inbuf, 0, iStatus, read_len);
131 s->sock->RecvFrom(inbuf, remote, 0, iStatus);
136 /* Reading callback */
139 SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
141 if (iStatus != KErrNone) {
142 if (iStatus == KErrEof)
147 /* Call stream callback */
148 if (s->stream && s->stream->notifier)
149 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
150 s->stream->notifier_context);
154 if (!s->stream || s->stream->connected)
155 inbuf_len = read_len();
157 inbuf_len = inbuf.Length();
160 inbuf_ptr = inbuf.Ptr();
162 /* Call stream callback until all has been read */
163 if (s->stream && s->stream->notifier)
164 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
165 s->stream->notifier_context);
174 virtual void DoCancel()
176 s->sock->CancelRecv();
180 const unsigned char *inbuf_ptr;
182 TSockXfrLength read_len;
183 SilcSymbianSocket *s;
187 /* Creates symbian socket stream context */
189 SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
192 SilcSymbianSocket *stream;
194 stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
200 SILC_LOG_DEBUG(("Create new Symbian socket %p", stream));
202 stream->send = new SilcSymbianSocketSend;
207 stream->send->s = stream;
209 stream->receive = new SilcSymbianSocketReceive;
210 if (!stream->receive) {
215 stream->receive->s = stream;
216 stream->receive->inbuf_ptr = NULL;
217 stream->receive->inbuf_len = 0;
222 /***************************** SILC Stream API ******************************/
226 /* Stream read operation */
228 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
231 SilcSocketStream socket_stream = (SilcSocketStream)stream;
232 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
233 SilcSymbianSocketReceive *recv = s->receive;
236 SILC_LOG_DEBUG(("Reading from sock %p", s));
238 if (s->error || !s->stream) {
239 SILC_LOG_DEBUG(("Error reading from sock %p", s));
243 SILC_LOG_DEBUG(("EOF from sock %p", s));
246 if (!recv->inbuf_len || !recv->inbuf_ptr) {
247 SILC_LOG_DEBUG(("Cannot read now from sock %p", s));
251 len = recv->inbuf_len;
255 /* Copy the read data */
256 memcpy(buf, recv->inbuf_ptr, len);
258 if (len < recv->inbuf_len) {
259 recv->inbuf_ptr += len;
260 recv->inbuf_len -= len;
262 recv->inbuf_ptr = NULL;
266 SILC_LOG_DEBUG(("Read %d bytes", len));
271 /* Stream write operation */
273 int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
276 SilcSocketStream socket_stream = (SilcSocketStream)stream;
277 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
278 SilcSymbianSocketSend *send = s->send;
279 TSockXfrLength ret_len;
280 TPtrC8 write_buf(data, data_len);
282 SILC_LOG_DEBUG(("Writing to sock %p", s));
284 if (s->error || !s->stream) {
285 SILC_LOG_DEBUG(("Error writing to sock %p", s));
289 SILC_LOG_DEBUG(("EOF from sock %p", s));
292 if (s->would_block) {
293 SILC_LOG_DEBUG(("Cannot write now to sock %p", s));
298 send->Send(write_buf, ret_len);
299 if (send->iStatus.Int() != KErrNone) {
300 if (send->iStatus.Int() == KErrEof) {
301 SILC_LOG_DEBUG(("EOF from sock %p", s));
304 SILC_LOG_DEBUG(("Error writing to sock %p, error %d", s,
305 send->iStatus.Int()));
313 if (ret_len() < data_len)
316 SILC_LOG_DEBUG(("Wrote %d bytes", ret_len()));
321 /* Receive UDP packet, connected socket. */
323 int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
326 return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
329 /* Send UDP packet, connected socket. */
331 int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
334 SilcSocketStream sock = (SilcSocketStream)stream;
336 /* In connectionless state check if remote IP and port is provided */
337 if (!sock->connected && sock->ip && sock->port)
338 return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
340 /* In connected state use normal writing to socket. */
341 return silc_socket_stream_write(stream, data, data_len);
344 /* Receive UDP packet, connectionless socket */
346 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
347 SilcUInt32 remote_ip_addr_size, int *remote_port,
348 unsigned char *buf, SilcUInt32 buf_len)
350 SilcSocketStream socket_stream = (SilcSocketStream)stream;
351 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
352 SilcSymbianSocketReceive *recv = s->receive;
357 if (!recv->inbuf_len || !recv->inbuf_ptr)
360 len = recv->inbuf_len;
364 /* Copy the read data */
365 memcpy(buf, recv->inbuf_ptr, len);
367 if (len < recv->inbuf_len) {
368 recv->inbuf_ptr += len;
369 recv->inbuf_len -= len;
371 recv->inbuf_ptr = NULL;
375 if (remote_ip_addr && remote_ip_addr_size && remote_port) {
377 recv->remote.Output(ip);
378 silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
380 *remote_port = recv->remote.Port();
386 /* Send UDP packet, connectionless socket */
388 int silc_net_udp_send(SilcStream stream,
389 const char *remote_ip_addr, int remote_port,
390 const unsigned char *data, SilcUInt32 data_len)
392 SilcSocketStream socket_stream = (SilcSocketStream)stream;
393 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
394 SilcSymbianSocketSend *send = s->send;
395 TSockXfrLength ret_len;
396 TPtrC8 write_buf(data, data_len);
404 send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
405 if (send->iStatus.Int() != KErrNone) {
406 if (send->iStatus.Int() == KErrEof)
415 if (ret_len() < data_len)
423 SilcBool silc_socket_stream_close(SilcStream stream)
425 SilcSocketStream socket_stream = (SilcSocketStream)stream;
426 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
432 /* Destroys the stream */
434 void silc_socket_stream_destroy(SilcStream stream)
436 SilcSocketStream socket_stream = (SilcSocketStream)stream;
437 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
439 SILC_LOG_DEBUG(("Destroying sock %p", s));
441 silc_socket_stream_close(stream);
442 silc_free(socket_stream->ip);
443 silc_free(socket_stream->hostname);
444 silc_free(socket_stream);
455 /* Sets stream notification callback for the stream */
457 SilcBool silc_socket_stream_notifier(SilcStream stream,
458 SilcSchedule schedule,
459 SilcStreamNotifier callback,
462 SilcSocketStream socket_stream = (SilcSocketStream)stream;
463 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
465 SILC_LOG_DEBUG(("Setting stream notifier for sock %p", s));
468 s->stream = socket_stream;
472 socket_stream->notifier = callback;
473 socket_stream->notifier_context = context;
474 socket_stream->schedule = schedule;
476 /* Schedule for receiving data by doing one read operation */