3 silcsymbiansocketstream.cpp
\r
5 Author: Pekka Riikonen <priikone@silcnet.org>
\r
7 Copyright (C) 2006 - 2007 Pekka Riikonen
\r
9 This program is free software; you can redistribute it and/or modify
\r
10 it under the terms of the GNU General Public License as published by
\r
11 the Free Software Foundation; version 2 of the License.
\r
13 This program is distributed in the hope that it will be useful,
\r
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
16 GNU General Public License for more details.
\r
20 /* In this implementation the sockets are in blocking mode, except that
\r
21 on Symbian the blocking mode is actually asynchronous, which semantically
\r
22 translates into non-blocking mode. The non-blocking mode just is not
\r
23 explicitly set because it would require us also to explicitly poll for the
\r
24 socket, which is done automatically by the Active Scheduler in blocking
\r
28 #include "silcsymbiansocketstream.h"
\r
30 /***************************** Socket Classes *******************************/
\r
32 /* Socket stream sender */
\r
34 class SilcSymbianSocketSend : public CActive {
\r
37 SilcSymbianSocketSend() : CActive(CActive::EPriorityStandard)
\r
39 CActiveScheduler::Add(this);
\r
43 ~SilcSymbianSocketSend()
\r
49 void Send(const TDesC8& buf, TSockXfrLength& ret_len)
\r
51 s->sock->Send(buf, 0, iStatus, ret_len);
\r
56 void Send(const TDesC8& buf, TSockXfrLength& ret_len,
\r
57 const char *remote_ip, int remote_port)
\r
62 remote = TInetAddr(remote_port);
\r
63 tmp = (TText *)remote_ip;
\r
64 if (remote.Input(tmp) == KErrNone) {
\r
65 s->sock->SendTo(buf, remote, 0, iStatus, ret_len);
\r
70 /* Sending callback */
\r
73 if (iStatus != KErrNone) {
\r
74 if (iStatus == KErrEof)
\r
81 /* Call stream callback */
\r
82 if (s->stream && s->stream->notifier)
\r
83 s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,
\r
84 s->stream->notifier_context);
\r
88 virtual void DoCancel()
\r
90 s->sock->CancelWrite();
\r
93 SilcSymbianSocket *s;
\r
96 /* Socket stream receiver */
\r
98 class SilcSymbianSocketReceive : public CActive {
\r
101 SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)
\r
103 CActiveScheduler::Add(this);
\r
107 ~SilcSymbianSocketReceive()
\r
115 if (!s->stream || s->stream->connected)
\r
116 s->sock->RecvOneOrMore(inbuf, 0, iStatus, inbuf_len);
\r
118 s->sock->RecvFrom(inbuf, remote, 0, iStatus);
\r
122 /* Reading callback */
\r
123 virtual void RunL()
\r
125 if (iStatus != KErrNone) {
\r
126 if (iStatus == KErrEof)
\r
134 inbuf_ptr = inbuf.Ptr();
\r
135 inbuf_len = inbuf.Length();
\r
137 /* Call stream callback */
\r
138 if (s->stream && s->stream->notifier)
\r
139 s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
\r
140 s->stream->notifier_context);
\r
147 virtual void DoCancel()
\r
149 s->sock->CancelRecv();
\r
153 const unsigned char *inbuf_ptr;
\r
154 TSockXfrLength inbuf_len;
\r
155 SilcSymbianSocket *s;
\r
159 /* Creates symbian socket stream context */
\r
161 SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
\r
164 SilcSymbianSocket *stream;
\r
166 stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
\r
169 stream->sock = sock;
\r
172 stream->send = new SilcSymbianSocketSend;
\r
173 if (!stream->send) {
\r
178 stream->receive = new SilcSymbianSocketReceive;
\r
179 if (!stream->receive) {
\r
180 delete stream->send;
\r
188 /***************************** SILC Stream API ******************************/
\r
190 /* Stream read operation */
\r
192 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
\r
193 SilcUInt32 buf_len)
\r
195 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
196 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
197 SilcSymbianSocketReceive *recv = s->receive;
\r
200 if (s->error || !s->stream)
\r
204 if (!recv->inbuf_len() || !recv->inbuf_ptr)
\r
207 len = recv->inbuf_len();
\r
211 /* Copy the read data */
\r
212 memcpy(buf, recv->inbuf_ptr, len);
\r
214 recv->inbuf_ptr = NULL;
\r
215 if (len < recv->inbuf_len())
\r
216 recv->inbuf_ptr += len;
\r
221 /* Stream write operation */
\r
223 int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
\r
224 SilcUInt32 data_len)
\r
226 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
227 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
228 SilcSymbianSocketSend *send = s->send;
\r
229 TSockXfrLength ret_len;
\r
230 TPtrC8 write_buf(data, data_len);
\r
232 if (s->would_block)
\r
234 if (s->error || !s->stream)
\r
240 send->Send(write_buf, ret_len);
\r
241 if (send->iStatus.Int() != KErrNone) {
\r
242 if (send->iStatus.Int() == KErrEof)
\r
250 s->would_block = 0;
\r
251 if (ret_len() < data_len)
\r
252 s->would_block = 1;
\r
257 /* Receive UDP packet, connected socket. */
\r
259 int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
\r
260 SilcUInt32 buf_len)
\r
262 return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
\r
265 /* Send UDP packet, connected socket. */
\r
267 int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
\r
268 SilcUInt32 data_len)
\r
270 SilcSocketStream sock = (SilcSocketStream)stream;
\r
272 /* In connectionless state check if remote IP and port is provided */
\r
273 if (!sock->connected && sock->ip && sock->port)
\r
274 return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
\r
276 /* In connected state use normal writing to socket. */
\r
277 return silc_socket_stream_write(stream, data, data_len);
\r
280 /* Receive UDP packet, connectionless socket */
\r
282 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
\r
283 SilcUInt32 remote_ip_addr_size, int *remote_port,
\r
284 unsigned char *buf, SilcUInt32 buf_len)
\r
286 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
287 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
288 SilcSymbianSocketReceive *recv = s->receive;
\r
293 if (!recv->inbuf_len() || !recv->inbuf_ptr)
\r
296 len = recv->inbuf_len();
\r
300 /* Copy the read data */
\r
301 memcpy(buf, recv->inbuf_ptr, len);
\r
303 recv->inbuf_ptr = NULL;
\r
304 if (len < recv->inbuf_len())
\r
305 recv->inbuf_ptr += len;
\r
307 if (remote_ip_addr && remote_ip_addr_size && remote_port) {
\r
309 recv->remote.Output(ip);
\r
310 silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
\r
312 *remote_port = recv->remote.Port();
\r
318 /* Send UDP packet, connectionless socket */
\r
320 int silc_net_udp_send(SilcStream stream,
\r
321 const char *remote_ip_addr, int remote_port,
\r
322 const unsigned char *data, SilcUInt32 data_len)
\r
324 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
325 SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
\r
326 SilcSymbianSocketSend *send = s->send;
\r
327 TSockXfrLength ret_len;
\r
328 TPtrC8 write_buf(data, data_len);
\r
330 if (s->would_block)
\r
336 send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
\r
337 if (send->iStatus.Int() != KErrNone) {
\r
338 if (send->iStatus.Int() == KErrEof)
\r
346 s->would_block = 0;
\r
347 if (ret_len() < data_len)
\r
348 s->would_block = 1;
\r
353 /* Closes socket */
\r
355 SilcBool silc_socket_stream_close(SilcStream stream)
\r
357 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
358 SilcSymbianSocket *s;
\r
360 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
\r
361 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
\r
364 s = (SilcSymbianSocket *)socket_stream->sock;
\r
370 /* Destroys the stream */
\r
372 void silc_socket_stream_destroy(SilcStream stream)
\r
374 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
375 SilcSymbianSocket *s;
\r
377 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
\r
378 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
\r
381 s = (SilcSymbianSocket *)socket_stream->sock;
\r
383 silc_socket_stream_close(stream);
\r
384 silc_free(socket_stream->ip);
\r
385 silc_free(socket_stream->hostname);
\r
386 silc_free(socket_stream);
\r
397 /* Sets stream notification callback for the stream */
\r
399 void silc_socket_stream_notifier(SilcStream stream,
\r
400 SilcSchedule schedule,
\r
401 SilcStreamNotifier callback,
\r
404 SilcSocketStream socket_stream = (SilcSocketStream)stream;
\r
405 SilcSymbianSocket *s;
\r
407 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
\r
408 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
\r
411 s = (SilcSymbianSocket *)socket_stream->sock;
\r
413 s->stream = socket_stream;
\r
417 socket_stream->notifier = callback;
\r
418 socket_stream->notifier_context = context;
\r
419 socket_stream->schedule = schedule;
\r