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);
58 void Send(const TDesC8& buf, TSockXfrLength& ret_len,
59 const char *remote_ip, int remote_port)
64 SILC_LOG_DEBUG(("Send()"));
66 remote = TInetAddr(remote_port);
67 tmp = (TText *)remote_ip;
68 if (remote.Input(tmp) == KErrNone) {
69 s->sock->SendTo(buf, remote, 0, iStatus, ret_len);
74 /* Sending callback */
77 SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
79 if (iStatus != KErrNone) {
80 if (iStatus == KErrEof)
87 /* Call stream callback */
90 if (s->stream && s->stream->notifier)
91 s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,
92 s->stream->notifier_context);
97 virtual void DoCancel()
99 s->sock->CancelWrite();
102 SilcSymbianSocket *s;
105 /* Socket stream receiver */
107 class SilcSymbianSocketReceive : public CActive {
110 SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)
112 CActiveScheduler::Add(this);
116 ~SilcSymbianSocketReceive()
124 SILC_LOG_DEBUG(("Read()"));
126 if (!s->stream || s->stream->connected)
127 s->sock->RecvOneOrMore(inbuf, 0, iStatus, read_len);
129 s->sock->RecvFrom(inbuf, remote, 0, iStatus);
134 /* Reading callback */
137 SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
139 if (iStatus != KErrNone) {
140 if (iStatus == KErrEof)
145 /* Call stream callback */
146 if (s->stream && s->stream->notifier)
147 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
148 s->stream->notifier_context);
152 if (!s->stream || s->stream->connected)
153 inbuf_len = read_len();
155 inbuf_len = inbuf.Length();
158 inbuf_ptr = inbuf.Ptr();
160 /* Call stream callback until all has been read */
161 if (s->stream && s->stream->notifier)
162 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
163 s->stream->notifier_context);
172 virtual void DoCancel()
174 s->sock->CancelRecv();
178 const unsigned char *inbuf_ptr;
180 TSockXfrLength read_len;
181 SilcSymbianSocket *s;
185 /* Creates symbian socket stream context */
187 SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
190 SilcSymbianSocket *stream;
192 stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
198 SILC_LOG_DEBUG(("Create new Symbian socket %p", stream));
200 stream->send = new SilcSymbianSocketSend;
206 stream->receive = new SilcSymbianSocketReceive;
207 if (!stream->receive) {
212 stream->receive->inbuf_ptr = NULL;
213 stream->receive->inbuf_len = 0;
218 /***************************** SILC Stream API ******************************/
222 /* Stream read operation */
224 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
227 SilcSocketStream socket_stream = (SilcSocketStream)stream;
228 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
229 SilcSymbianSocketReceive *recv = s->receive;
232 SILC_LOG_DEBUG(("Reading from sock %p", s));
234 if (s->error || !s->stream) {
235 SILC_LOG_DEBUG(("Error reading from sock %p", s));
239 SILC_LOG_DEBUG(("EOF from sock %p", s));
242 if (!recv->inbuf_len || !recv->inbuf_ptr) {
243 SILC_LOG_DEBUG(("Cannot read now from sock %p", s));
247 len = recv->inbuf_len;
251 /* Copy the read data */
252 memcpy(buf, recv->inbuf_ptr, len);
254 if (len < recv->inbuf_len) {
255 recv->inbuf_ptr += len;
256 recv->inbuf_len -= len;
258 recv->inbuf_ptr = NULL;
262 SILC_LOG_DEBUG(("Read %d bytes", len));
267 /* Stream write operation */
269 int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
272 SilcSocketStream socket_stream = (SilcSocketStream)stream;
273 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
274 SilcSymbianSocketSend *send = s->send;
275 TSockXfrLength ret_len;
276 TPtrC8 write_buf(data, data_len);
278 SILC_LOG_DEBUG(("Writing to sock %p", s));
280 if (s->error || !s->stream) {
281 SILC_LOG_DEBUG(("Error writing to sock %p", s));
285 SILC_LOG_DEBUG(("EOF from sock %p", s));
288 if (s->would_block) {
289 SILC_LOG_DEBUG(("Cannot write now to sock %p", s));
294 send->Send(write_buf, ret_len);
295 if (send->iStatus.Int() != KErrNone) {
296 if (send->iStatus.Int() == KErrEof) {
297 SILC_LOG_DEBUG(("EOF from sock %p", s));
300 SILC_LOG_DEBUG(("Error writing to sock %p, error %d", s,
301 send->iStatus.Int()));
309 if (ret_len() < data_len)
312 SILC_LOG_DEBUG(("Wrote %d bytes", ret_len()));
317 /* Receive UDP packet, connected socket. */
319 int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
322 return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
325 /* Send UDP packet, connected socket. */
327 int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
330 SilcSocketStream sock = (SilcSocketStream)stream;
332 /* In connectionless state check if remote IP and port is provided */
333 if (!sock->connected && sock->ip && sock->port)
334 return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
336 /* In connected state use normal writing to socket. */
337 return silc_socket_stream_write(stream, data, data_len);
340 /* Receive UDP packet, connectionless socket */
342 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
343 SilcUInt32 remote_ip_addr_size, int *remote_port,
344 unsigned char *buf, SilcUInt32 buf_len)
346 SilcSocketStream socket_stream = (SilcSocketStream)stream;
347 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
348 SilcSymbianSocketReceive *recv = s->receive;
353 if (!recv->inbuf_len || !recv->inbuf_ptr)
356 len = recv->inbuf_len;
360 /* Copy the read data */
361 memcpy(buf, recv->inbuf_ptr, len);
363 if (len < recv->inbuf_len) {
364 recv->inbuf_ptr += len;
365 recv->inbuf_len -= len;
367 recv->inbuf_ptr = NULL;
371 if (remote_ip_addr && remote_ip_addr_size && remote_port) {
373 recv->remote.Output(ip);
374 silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
376 *remote_port = recv->remote.Port();
382 /* Send UDP packet, connectionless socket */
384 int silc_net_udp_send(SilcStream stream,
385 const char *remote_ip_addr, int remote_port,
386 const unsigned char *data, SilcUInt32 data_len)
388 SilcSocketStream socket_stream = (SilcSocketStream)stream;
389 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
390 SilcSymbianSocketSend *send = s->send;
391 TSockXfrLength ret_len;
392 TPtrC8 write_buf(data, data_len);
400 send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
401 if (send->iStatus.Int() != KErrNone) {
402 if (send->iStatus.Int() == KErrEof)
411 if (ret_len() < data_len)
419 SilcBool silc_socket_stream_close(SilcStream stream)
421 SilcSocketStream socket_stream = (SilcSocketStream)stream;
422 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
428 /* Destroys the stream */
430 void silc_socket_stream_destroy(SilcStream stream)
432 SilcSocketStream socket_stream = (SilcSocketStream)stream;
433 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
435 SILC_LOG_DEBUG(("Destroying sock %p", s));
437 silc_socket_stream_close(stream);
438 silc_free(socket_stream->ip);
439 silc_free(socket_stream->hostname);
440 silc_free(socket_stream);
451 /* Sets stream notification callback for the stream */
453 SilcBool silc_socket_stream_notifier(SilcStream stream,
454 SilcSchedule schedule,
455 SilcStreamNotifier callback,
458 SilcSocketStream socket_stream = (SilcSocketStream)stream;
459 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
461 SILC_LOG_DEBUG(("Setting stream notifier for sock %p", s));
464 s->stream = socket_stream;
468 socket_stream->notifier = callback;
469 socket_stream->notifier_context = context;
470 socket_stream->schedule = schedule;
472 /* Schedule for receiving data by doing one read operation */