4 silcsymbiansocketstream.cpp
6 Author: Pekka Riikonen <priikone@silcnet.org>
8 Copyright (C) 2006 - 2008 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
28 #include "silcruntime.h"
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);
137 /* Reading callback */
140 SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
142 if (iStatus != KErrNone) {
143 if (iStatus == KErrEof)
148 /* Call stream callback */
149 if (s->stream && s->stream->notifier)
150 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
151 s->stream->notifier_context);
155 if (!s->stream || s->stream->connected)
156 inbuf_len = read_len();
158 inbuf_len = inbuf.Length();
161 inbuf_ptr = inbuf.Ptr();
163 /* Call stream callback until all has been read */
164 if (s->stream && s->stream->notifier)
165 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
166 s->stream->notifier_context);
175 virtual void DoCancel()
177 s->sock->CancelRecv();
181 const unsigned char *inbuf_ptr;
183 TSockXfrLength read_len;
184 SilcSymbianSocket *s;
188 /* Creates symbian socket stream context */
190 SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
193 SilcSymbianSocket *stream;
195 stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
201 SILC_LOG_DEBUG(("Create new Symbian socket %p", stream));
203 stream->send = new SilcSymbianSocketSend;
208 stream->send->s = stream;
210 stream->receive = new SilcSymbianSocketReceive;
211 if (!stream->receive) {
216 stream->receive->s = stream;
217 stream->receive->inbuf_ptr = NULL;
218 stream->receive->inbuf_len = 0;
223 /***************************** SILC Stream API ******************************/
227 /* Stream read operation */
229 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
232 SilcSocketStream socket_stream = (SilcSocketStream)stream;
233 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
234 SilcSymbianSocketReceive *recv = s->receive;
237 SILC_LOG_DEBUG(("Reading from sock %p", s));
239 if (s->error || !s->stream) {
240 SILC_LOG_DEBUG(("Error reading from sock %p", s));
244 SILC_LOG_DEBUG(("EOF from sock %p", s));
247 if (!recv->inbuf_len || !recv->inbuf_ptr) {
248 SILC_LOG_DEBUG(("Cannot read now from sock %p", s));
252 len = recv->inbuf_len;
256 /* Copy the read data */
257 memcpy(buf, recv->inbuf_ptr, len);
259 if (len < recv->inbuf_len) {
260 recv->inbuf_ptr += len;
261 recv->inbuf_len -= len;
263 recv->inbuf_ptr = NULL;
267 SILC_LOG_DEBUG(("Read %d bytes", len));
272 /* Stream write operation */
274 int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
277 SilcSocketStream socket_stream = (SilcSocketStream)stream;
278 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
279 SilcSymbianSocketSend *send = s->send;
280 TSockXfrLength ret_len;
281 TPtrC8 write_buf(data, data_len);
283 SILC_LOG_DEBUG(("Writing to sock %p", s));
285 if (s->error || !s->stream) {
286 SILC_LOG_DEBUG(("Error writing to sock %p", s));
290 SILC_LOG_DEBUG(("EOF from sock %p", s));
293 if (s->would_block) {
294 SILC_LOG_DEBUG(("Cannot write now to sock %p", s));
299 send->Send(write_buf, ret_len);
300 if (send->iStatus.Int() != KErrNone) {
301 if (send->iStatus.Int() == KErrEof) {
302 SILC_LOG_DEBUG(("EOF from sock %p", s));
305 SILC_LOG_DEBUG(("Error writing to sock %p, error %d", s,
306 send->iStatus.Int()));
314 if (ret_len() < data_len)
317 SILC_LOG_DEBUG(("Wrote %d bytes", ret_len()));
322 /* Receive UDP packet, connected socket. */
324 int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
327 return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
330 /* Send UDP packet, connected socket. */
332 int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
335 SilcSocketStream sock = (SilcSocketStream)stream;
337 /* In connectionless state check if remote IP and port is provided */
338 if (!sock->connected && sock->ip && sock->port)
339 return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
341 /* In connected state use normal writing to socket. */
342 return silc_socket_stream_write(stream, data, data_len);
345 /* Receive UDP packet, connectionless socket */
347 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
348 SilcUInt32 remote_ip_addr_size, int *remote_port,
349 unsigned char *buf, SilcUInt32 buf_len)
351 SilcSocketStream socket_stream = (SilcSocketStream)stream;
352 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
353 SilcSymbianSocketReceive *recv = s->receive;
358 if (!recv->inbuf_len || !recv->inbuf_ptr)
361 len = recv->inbuf_len;
365 /* Copy the read data */
366 memcpy(buf, recv->inbuf_ptr, len);
368 if (len < recv->inbuf_len) {
369 recv->inbuf_ptr += len;
370 recv->inbuf_len -= len;
372 recv->inbuf_ptr = NULL;
376 if (remote_ip_addr && remote_ip_addr_size && remote_port) {
378 recv->remote.Output(ip);
379 silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
381 *remote_port = recv->remote.Port();
387 /* Send UDP packet, connectionless socket */
389 int silc_net_udp_send(SilcStream stream,
390 const char *remote_ip_addr, int remote_port,
391 const unsigned char *data, SilcUInt32 data_len)
393 SilcSocketStream socket_stream = (SilcSocketStream)stream;
394 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
395 SilcSymbianSocketSend *send = s->send;
396 TSockXfrLength ret_len;
397 TPtrC8 write_buf(data, data_len);
405 send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
406 if (send->iStatus.Int() != KErrNone) {
407 if (send->iStatus.Int() == KErrEof)
416 if (ret_len() < data_len)
424 SilcBool silc_socket_stream_close(SilcStream stream)
426 SilcSocketStream socket_stream = (SilcSocketStream)stream;
427 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
433 /* Destroys the stream */
435 void silc_socket_stream_destroy(SilcStream stream)
437 SilcSocketStream socket_stream = (SilcSocketStream)stream;
438 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
440 SILC_LOG_DEBUG(("Destroying sock %p", s));
442 silc_socket_stream_close(stream);
443 silc_free(socket_stream->ip);
444 silc_free(socket_stream->hostname);
445 silc_free(socket_stream);
456 /* Sets stream notification callback for the stream */
458 SilcBool silc_socket_stream_notifier(SilcStream stream,
459 SilcSchedule schedule,
460 SilcStreamNotifier callback,
463 SilcSocketStream socket_stream = (SilcSocketStream)stream;
464 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
466 SILC_LOG_DEBUG(("Setting stream notifier for sock %p", s));
469 s->stream = socket_stream;
473 socket_stream->notifier = callback;
474 socket_stream->notifier_context = context;
475 socket_stream->schedule = schedule;
477 /* Schedule for receiving data by doing one read operation */