Removed unnecessary stream op pointer checks.
[silc.git] / lib / silcutil / symbian / silcsymbiansocketstream.cpp
1 /*
2
3   silcsymbiansocketstream.cpp
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2006 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 /* In this implementation the sockets are in blocking mode, except that
21    on Symbian the blocking mode is actually asynchronous, which semantically
22    translates into non-blocking mode.  The non-blocking mode just is not
23    explicitly set because it would require us also to explicitly poll for the
24    socket, which is done automatically by the Active Scheduler in blocking
25    mode. */
26
27 #include "silc.h"
28 #include "silcsymbiansocketstream.h"
29
30 /***************************** Socket Classes *******************************/
31
32 /* Socket stream sender */
33
34 class SilcSymbianSocketSend : public CActive {
35 public:
36   /* Constructor */
37   SilcSymbianSocketSend() : CActive(CActive::EPriorityStandard)
38   {
39     CActiveScheduler::Add(this);
40   }
41
42   /* Destructor */
43   ~SilcSymbianSocketSend()
44   {
45     Cancel();
46   }
47
48   /* Send data */
49   void Send(const TDesC8& buf, TSockXfrLength& ret_len)
50   {
51     s->sock->Send(buf, 0, iStatus, ret_len);
52     SetActive();
53   }
54
55   /* Send data */
56   void Send(const TDesC8& buf, TSockXfrLength& ret_len,
57             const char *remote_ip, int remote_port)
58   {
59     TInetAddr remote;
60     TBuf<64> tmp;
61
62     remote = TInetAddr(remote_port);
63     tmp = (TText *)remote_ip;
64     if (remote.Input(tmp) == KErrNone) {
65       s->sock->SendTo(buf, remote, 0, iStatus, ret_len);
66       SetActive();
67     }
68   }
69
70   /* Sending callback */
71   virtual void RunL()
72   {
73     if (iStatus != KErrNone) {
74       if (iStatus == KErrEof)
75         s->eof = 1;
76       else
77         s->error = 1;
78       return;
79     }
80
81     /* Call stream callback */
82     if (s->stream && s->stream->notifier)
83       s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,
84                           s->stream->notifier_context);
85   }
86
87   /* Cancel */
88   virtual void DoCancel()
89   {
90     s->sock->CancelWrite();
91   }
92
93   SilcSymbianSocket *s;
94 };
95
96 /* Socket stream receiver */
97
98 class SilcSymbianSocketReceive : public CActive {
99 public:
100   /* Constructor */
101   SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)
102   {
103     CActiveScheduler::Add(this);
104   }
105
106   /* Destructor */
107   ~SilcSymbianSocketReceive()
108   {
109     Cancel();
110   }
111
112   /* Read data */
113   void Read()
114   {
115     if (!s->stream || s->stream->connected)
116       s->sock->RecvOneOrMore(inbuf, 0, iStatus, inbuf_len);
117     else
118       s->sock->RecvFrom(inbuf, remote, 0, iStatus);
119     SetActive();
120   }
121
122   /* Reading callback */
123   virtual void RunL()
124   {
125     if (iStatus != KErrNone) {
126       if (iStatus == KErrEof)
127         s->eof = 1;
128       else
129         s->error = 1;
130       return;
131     }
132
133     if (!inbuf_ptr)
134       inbuf_ptr = inbuf.Ptr();
135     inbuf_len = inbuf.Length();
136
137     /* Call stream callback */
138     if (s->stream && s->stream->notifier)
139       s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
140                           s->stream->notifier_context);
141
142     /* Read more */
143     Read();
144   }
145
146   /* Cancel */
147   virtual void DoCancel()
148   {
149     s->sock->CancelRecv();
150   }
151
152   TBuf8<8192> inbuf;
153   const unsigned char *inbuf_ptr;
154   TSockXfrLength inbuf_len;
155   SilcSymbianSocket *s;
156   TInetAddr remote;
157 };
158
159 /* Creates symbian socket stream context */
160
161 SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
162                                               RSocketServ *ss)
163 {
164   SilcSymbianSocket *stream;
165
166   stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
167   if (!stream)
168     return NULL;
169   stream->sock = sock;
170   stream->ss = ss;
171
172   stream->send = new SilcSymbianSocketSend;
173   if (!stream->send) {
174     silc_free(stream);
175     return NULL;
176   }
177
178   stream->receive = new SilcSymbianSocketReceive;
179   if (!stream->receive) {
180     delete stream->send;
181     silc_free(stream);
182     return NULL;
183   }
184
185   return stream;
186 }
187
188 /***************************** SILC Stream API ******************************/
189
190 /* Stream read operation */
191
192 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
193                             SilcUInt32 buf_len)
194 {
195   SilcSocketStream socket_stream = (SilcSocketStream)stream;
196   SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
197   SilcSymbianSocketReceive *recv = s->receive;
198   int len;
199
200   if (s->error || !s->stream)
201     return -2;
202   if (s->eof)
203     return 0;
204   if (!recv->inbuf_len() || !recv->inbuf_ptr)
205     return -1;
206
207   len = recv->inbuf_len();
208   if (buf_len < len)
209     len = buf_len;
210
211   /* Copy the read data */
212   memcpy(buf, recv->inbuf_ptr, len);
213
214   recv->inbuf_ptr = NULL;
215   if (len < recv->inbuf_len())
216     recv->inbuf_ptr += len;
217
218   return len;
219 }
220
221 /* Stream write operation */
222
223 int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
224                              SilcUInt32 data_len)
225 {
226   SilcSocketStream socket_stream = (SilcSocketStream)stream;
227   SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
228   SilcSymbianSocketSend *send = s->send;
229   TSockXfrLength ret_len;
230   TPtrC8 write_buf(data, data_len);
231
232   if (s->would_block)
233     return -1;
234   if (s->error || !s->stream)
235     return -2;
236   if (s->eof)
237     return 0;
238
239   /* Send data */
240   send->Send(write_buf, ret_len);
241   if (send->iStatus.Int() != KErrNone) {
242     if (send->iStatus.Int() == KErrEof)
243       return 0;
244     return -2;
245   }
246
247   if (!ret_len())
248     return -1;
249
250   s->would_block = 0;
251   if (ret_len() < data_len)
252     s->would_block = 1;
253
254   return ret_len();
255 }
256
257 /* Receive UDP packet, connected socket. */
258
259 int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
260                                 SilcUInt32 buf_len)
261 {
262   return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
263 }
264
265 /* Send UDP packet, connected socket. */
266
267 int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
268                                  SilcUInt32 data_len)
269 {
270   SilcSocketStream sock = (SilcSocketStream)stream;
271
272   /* In connectionless state check if remote IP and port is provided */
273   if (!sock->connected && sock->ip && sock->port)
274     return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
275
276   /* In connected state use normal writing to socket. */
277   return silc_socket_stream_write(stream, data, data_len);
278 }
279
280 /* Receive UDP packet, connectionless socket */
281
282 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
283                          SilcUInt32 remote_ip_addr_size, int *remote_port,
284                          unsigned char *buf, SilcUInt32 buf_len)
285 {
286   SilcSocketStream socket_stream = (SilcSocketStream)stream;
287   SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
288   SilcSymbianSocketReceive *recv = s->receive;
289   int len;
290
291   if (s->eof)
292     return 0;
293   if (!recv->inbuf_len() || !recv->inbuf_ptr)
294     return -1;
295
296   len = recv->inbuf_len();
297   if (buf_len < len)
298     len = buf_len;
299
300   /* Copy the read data */
301   memcpy(buf, recv->inbuf_ptr, len);
302
303   recv->inbuf_ptr = NULL;
304   if (len < recv->inbuf_len())
305     recv->inbuf_ptr += len;
306
307   if (remote_ip_addr && remote_ip_addr_size && remote_port) {
308     TBuf<64> ip;
309     recv->remote.Output(ip);
310     silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
311                  ip.Length());
312     *remote_port = recv->remote.Port();
313   }
314
315   return len;
316 }
317
318 /* Send UDP packet, connectionless socket  */
319
320 int silc_net_udp_send(SilcStream stream,
321                       const char *remote_ip_addr, int remote_port,
322                       const unsigned char *data, SilcUInt32 data_len)
323 {
324   SilcSocketStream socket_stream = (SilcSocketStream)stream;
325   SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
326   SilcSymbianSocketSend *send = s->send;
327   TSockXfrLength ret_len;
328   TPtrC8 write_buf(data, data_len);
329
330   if (s->would_block)
331     return -1;
332   if (s->eof)
333     return 0;
334
335   /* Send data */
336   send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
337   if (send->iStatus.Int() != KErrNone) {
338     if (send->iStatus.Int() == KErrEof)
339       return 0;
340     return -2;
341   }
342
343   if (!ret_len())
344     return -1;
345
346   s->would_block = 0;
347   if (ret_len() < data_len)
348     s->would_block = 1;
349
350   return ret_len();
351 }
352
353 /* Closes socket */
354
355 SilcBool silc_socket_stream_close(SilcStream stream)
356 {
357   SilcSocketStream socket_stream = (SilcSocketStream)stream;
358   SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
359   s->sock->Close();
360
361   return TRUE;
362 }
363
364 /* Destroys the stream */
365
366 void silc_socket_stream_destroy(SilcStream stream)
367 {
368   SilcSocketStream socket_stream = (SilcSocketStream)stream;
369   SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
370
371   silc_socket_stream_close(stream);
372   silc_free(socket_stream->ip);
373   silc_free(socket_stream->hostname);
374   silc_free(socket_stream);
375   delete s->send;
376   delete s->receive;
377   delete s->sock;
378   if (s->ss) {
379     s->ss->Close();
380     delete s->ss;
381   }
382   silc_free(s);
383 }
384
385 /* Sets stream notification callback for the stream */
386
387 void silc_socket_stream_notifier(SilcStream stream,
388                                  SilcSchedule schedule,
389                                  SilcStreamNotifier callback,
390                                  void *context)
391 {
392   SilcSocketStream socket_stream = (SilcSocketStream)stream;
393   SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
394
395   if (callback)
396     s->stream = socket_stream;
397   else
398     s->stream = NULL;
399
400   socket_stream->notifier = callback;
401   socket_stream->notifier_context = context;
402   socket_stream->schedule = schedule;
403 }