2c2fea50c374866a65086f3cf8db81fb1e0a27fd
[silc.git] / lib / silcutil / symbian / silcsymbiannet.cpp
1 /*
2
3   silcsymbiannet.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 #include "silc.h"
21 #include "silcsymbiansocketstream.h"
22
23 /************************ Static utility functions **************************/
24
25 static SilcBool silc_net_set_sockaddr(TInetAddr *addr, const char *ip_addr,
26                                       int port)
27 {
28   /* Check for IPv4 and IPv6 addresses */
29   if (ip_addr) {
30     if (!silc_net_is_ip(ip_addr)) {
31       SILC_LOG_ERROR(("%s is not IP address", ip_addr));
32       return FALSE;
33     }
34
35     if (silc_net_is_ip4(ip_addr)) {
36       /* IPv4 address */
37       unsigned char buf[4];
38       TUint32 a;
39
40       if (!silc_net_addr2bin(ip_addr, buf, sizeof(buf)))
41         return FALSE;
42
43       SILC_GET32_MSB(a, buf);
44       addr->SetAddress(a);
45       addr->SetPort(port);
46     } else {
47 #ifdef HAVE_IPV6
48       SILC_LOG_ERROR(("IPv6 not supported"));
49       return FALSE;
50 #else
51       SILC_LOG_ERROR(("Operating System does not support IPv6"));
52       return FALSE;
53 #endif
54     }
55   } else {
56     addr->SetAddress(0);
57     addr->SetPort(port);
58   }
59
60   return TRUE;
61 }
62
63 /****************************** TCP Listener ********************************/
64
65 class SilcSymbianTCPListener;
66
67 extern "C" {
68
69 /* Deliver new stream to upper layer */
70
71 static void silc_net_accept_stream(SilcSocketStreamStatus status,
72                                    SilcStream stream, void *context)
73 {
74   SilcNetListener listener = (SilcNetListener)context;
75
76   /* In case of error, the socket has been destroyed already via
77      silc_stream_destroy. */
78   if (status != SILC_SOCKET_OK)
79     return;
80
81   listener->callback(SILC_NET_OK, stream, listener->context);
82 }
83
84 } /* extern "C" */
85
86 /* TCP Listener class */
87
88 class SilcSymbianTCPListener : public CActive {
89 public:
90   /* Constructor */
91   SilcSymbianTCPListener() : CActive(CActive::EPriorityStandard)
92   {
93     CActiveScheduler::Add(this);
94   }
95
96   /* Destructor */
97   ~SilcSymbianTCPListener()
98   {
99     Cancel();
100   }
101
102   /* Listen for connection */
103   void Listen()
104   {
105     SILC_LOG_DEBUG(("Listen()"));
106
107     new_conn = new RSocket;
108     if (!new_conn)
109       return;
110     if (new_conn->Open(ss) != KErrNone) {
111       Listen();
112       return;
113     }
114
115     /* Start listenning */
116     sock.Accept(*new_conn, iStatus);
117     SetActive();
118   }
119
120   /* Listener callback */
121   virtual void RunL()
122   {
123     SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
124
125     if (iStatus != KErrNone) {
126       if (new_conn)
127         delete new_conn;
128       new_conn = NULL;
129       Listen();
130       return;
131     }
132
133     SILC_LOG_DEBUG(("Accept new connection"));
134
135     /* Set socket options */
136     new_conn->SetOpt(KSoReuseAddr, KSolInetIp, 1);
137
138     /* Create socket stream */
139     silc_socket_tcp_stream_create(
140                         (SilcSocket)silc_create_symbian_socket(new_conn, NULL),
141                         listener->lookup, listener->require_fqdn,
142                         listener->schedule, silc_net_accept_stream,
143                         (void *)listener);
144     new_conn = NULL;
145
146     /* Continue listenning */
147     Listen();
148   }
149
150   /* Cancel */
151   virtual void DoCancel()
152   {
153     sock.CancelAll();
154     ss.Close();
155     if (new_conn)
156       delete new_conn;
157   }
158
159   RSocket *new_conn;
160   RSocket sock;
161   RSocketServ ss;
162   SilcNetListener listener;
163 };
164
165 extern "C" {
166
167 /* Create TCP listener */
168
169 SilcNetListener
170 silc_net_tcp_create_listener(const char **local_ip_addr,
171                              SilcUInt32 local_ip_count, int port,
172                              SilcBool lookup, SilcBool require_fqdn,
173                              SilcSchedule schedule,
174                              SilcNetCallback callback, void *context)
175 {
176   SilcNetListener listener = NULL;
177   SilcSymbianTCPListener *l = NULL;
178   TInetAddr server;
179   TInt ret;
180   int i;
181
182   SILC_LOG_DEBUG(("Creating TCP listener"));
183
184   if (port < 0 || !schedule || !callback)
185     goto err;
186
187   listener = (SilcNetListener)silc_calloc(1, sizeof(*listener));
188   if (!listener) {
189     callback(SILC_NET_NO_MEMORY, NULL, context);
190     return NULL;
191   }
192   listener->schedule = schedule;
193   listener->callback = callback;
194   listener->context = context;
195   listener->require_fqdn = require_fqdn;
196   listener->lookup = lookup;
197
198   if (local_ip_count > 0) {
199     listener->socks = (SilcSocket *)silc_calloc(local_ip_count,
200                                                 sizeof(*listener->socks));
201     if (!listener->socks) {
202       callback(SILC_NET_NO_MEMORY, NULL, context);
203       return NULL;
204     }
205   } else {
206     listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks));
207     if (!listener->socks) {
208       callback(SILC_NET_NO_MEMORY, NULL, context);
209       return NULL;
210     }
211
212     local_ip_count = 1;
213   }
214
215   /* Bind to local addresses */
216   for (i = 0; i < local_ip_count; i++) {
217     SILC_LOG_DEBUG(("Binding to local address %s",
218                     local_ip_addr ? local_ip_addr[i] : "0.0.0.0"));
219
220     l = new SilcSymbianTCPListener;
221     if (!l)
222       goto err;
223
224     /* Connect to socket server */
225     ret = l->ss.Connect();
226     if (ret != KErrNone)
227       goto err;
228
229 #ifdef SILC_THREADS
230     /* Make our socket shareable between threads */
231     l->ss.ShareAuto();
232 #endif /* SILC_THREADS */
233
234     /* Set listener address */
235     if (!silc_net_set_sockaddr(&server, local_ip_addr[i], port))
236       goto err;
237
238     /* Create the socket */
239     ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp);
240     if (ret != KErrNone) {
241       SILC_LOG_ERROR(("Cannot create socket, error %d", ret));
242       goto err;
243     }
244
245     /* Set the socket options */
246     ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1);
247     if (ret != KErrNone) {
248       SILC_LOG_ERROR(("Cannot set socket options, error %d", ret));
249       goto err;
250     }
251
252     /* Bind the listener socket */
253     ret = l->sock.Bind(server);
254     if (ret != KErrNone) {
255       SILC_LOG_DEBUG(("Cannot bind socket, error %d", ret));
256       goto err;
257     }
258
259     /* Specify that we are listenning */
260     ret = l->sock.Listen(5);
261     if (ret != KErrNone) {
262       SILC_LOG_ERROR(("Cannot set socket listenning, error %d", ret));
263       goto err;
264     }
265     l->Listen();
266
267     l->listener = listener;
268     listener->socks[i] = (SilcSocket)l;
269     listener->socks_count++;
270   }
271
272   SILC_LOG_DEBUG(("TCP listener created"));
273
274   return listener;
275
276  err:
277   if (l)
278     delete l;
279   if (callback)
280     callback(SILC_NET_ERROR, NULL, context);
281   if (listener)
282     silc_net_close_listener(listener);
283   return NULL;
284 }
285
286 /* Create TCP listener, multiple ports */
287
288 SilcNetListener
289 silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports,
290                               SilcUInt32 port_count,
291                               SilcBool ignore_port_error,
292                               SilcBool lookup, SilcBool require_fqdn,
293                               SilcSchedule schedule,
294                               SilcNetCallback callback, void *context)
295 {
296   SilcNetListener listener = NULL;
297   SilcSymbianTCPListener *l = NULL;
298   TInetAddr server;
299   TInt ret;
300   int i;
301
302   SILC_LOG_DEBUG(("Creating TCP listener"));
303
304   if (!schedule || !callback)
305     goto err;
306
307   listener = (SilcNetListener)silc_calloc(1, sizeof(*listener));
308   if (!listener) {
309     callback(SILC_NET_NO_MEMORY, NULL, context);
310     return NULL;
311   }
312   listener->schedule = schedule;
313   listener->callback = callback;
314   listener->context = context;
315   listener->require_fqdn = require_fqdn;
316   listener->lookup = lookup;
317
318   if (port_count > 0) {
319     listener->socks = (SilcSocket *)silc_calloc(port_count,
320                                                 sizeof(*listener->socks));
321     if (!listener->socks) {
322       callback(SILC_NET_NO_MEMORY, NULL, context);
323       return NULL;
324     }
325   } else {
326     listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks));
327     if (!listener->socks) {
328       callback(SILC_NET_NO_MEMORY, NULL, context);
329       return NULL;
330     }
331
332     port_count = 1;
333   }
334
335   /* Bind to ports */
336   for (i = 0; i < port_count; i++) {
337     SILC_LOG_DEBUG(("Binding to local address %s:%d",
338                     local_ip_addr ? local_ip_addr : "0.0.0.0",
339                     ports ? ports[i] : 0));
340
341     l = new SilcSymbianTCPListener;
342     if (!l)
343       goto err;
344
345     /* Connect to socket server */
346     ret = l->ss.Connect();
347     if (ret != KErrNone)
348       goto err;
349
350 #ifdef SILC_THREADS
351     /* Make our socket shareable between threads */
352     l->ss.ShareAuto();
353 #endif /* SILC_THREADS */
354
355     /* Set listener address */
356     if (!silc_net_set_sockaddr(&server, local_ip_addr, ports ? ports[i] : 0)) {
357       if (ignore_port_error) {
358         delete l;
359         continue;
360       }
361       goto err;
362     }
363
364     /* Create the socket */
365     ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp);
366     if (ret != KErrNone) {
367       if (ignore_port_error) {
368         delete l;
369         continue;
370       }
371       SILC_LOG_ERROR(("Cannot create socket, error %d", ret));
372       goto err;
373     }
374
375     /* Set the socket options */
376     ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1);
377     if (ret != KErrNone) {
378       if (ignore_port_error) {
379         delete l;
380         continue;
381       }
382       SILC_LOG_ERROR(("Cannot set socket options, error %d", ret));
383       goto err;
384     }
385
386     /* Bind the listener socket */
387     ret = l->sock.Bind(server);
388     if (ret != KErrNone) {
389       if (ignore_port_error) {
390         delete l;
391         continue;
392       }
393       SILC_LOG_DEBUG(("Cannot bind socket, error %d", ret));
394       goto err;
395     }
396
397     /* Specify that we are listenning */
398     ret = l->sock.Listen(5);
399     if (ret != KErrNone) {
400       if (ignore_port_error) {
401         delete l;
402         continue;
403       }
404       SILC_LOG_ERROR(("Cannot set socket listenning, error %d", ret));
405       goto err;
406     }
407     l->Listen();
408
409     l->listener = listener;
410     listener->socks[i] = (SilcSocket)l;
411     listener->socks_count++;
412   }
413
414   if (ignore_port_error && !listener->socks_count) {
415     l = NULL;
416     goto err;
417   }
418
419   SILC_LOG_DEBUG(("TCP listener created"));
420
421   return listener;
422
423  err:
424   if (l)
425     delete l;
426   if (callback)
427     callback(SILC_NET_ERROR, NULL, context);
428   if (listener)
429     silc_net_close_listener(listener);
430   return NULL;
431 }
432
433 /* Close network listener */
434
435 void silc_net_close_listener(SilcNetListener listener)
436 {
437   int i;
438
439   SILC_LOG_DEBUG(("Closing network listener"));
440
441   if (!listener)
442     return;
443
444   for (i = 0; i < listener->socks_count; i++) {
445     SilcSymbianTCPListener *l = (SilcSymbianTCPListener *)listener->socks[i];
446     l->sock.CancelAll();
447     l->sock.Close();
448     l->ss.Close();
449     if (l->new_conn)
450       delete l->new_conn;
451     delete l;
452   }
453
454   silc_free(listener->socks);
455   silc_free(listener);
456 }
457
458
459 /**************************** TCP/IP connecting *****************************/
460
461 static void silc_net_connect_stream(SilcSocketStreamStatus status,
462             SilcStream stream, void *context);
463
464 } /* extern "C" */
465
466 /* TCP connecting class */
467
468 class SilcSymbianTCPConnect : public CActive {
469 public:
470   /* Constructor */
471   SilcSymbianTCPConnect() : CActive(CActive::EPriorityStandard)
472   {
473     CActiveScheduler::Add(this);
474   }
475
476   /* Destructor */
477   ~SilcSymbianTCPConnect()
478   {
479     silc_free(remote);
480     if (op)
481       silc_async_free(op);
482     Cancel();
483   }
484
485   /* Connect to remote host */
486   void Connect(TSockAddr &addr)
487   {
488     SILC_LOG_DEBUG(("Connect()"));
489     sock->Connect(addr, iStatus);
490     SetActive();
491   }
492
493   /* Connection callback */
494   virtual void RunL()
495   {
496     SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
497
498     if (iStatus != KErrNone) {
499       if (callback)
500         callback(SILC_NET_ERROR, NULL, context);
501       sock->CancelConnect();
502       delete sock;
503       ss->Close();
504       delete ss;
505       sock = NULL;
506       ss = NULL;
507       delete this;
508       return;
509     }
510
511     SILC_LOG_DEBUG(("Connected to host %s on %d", remote_ip, port));
512
513     /* Create stream */
514     if (callback) {
515       silc_socket_tcp_stream_create(
516                              (SilcSocket)silc_create_symbian_socket(sock, ss),
517                              TRUE, FALSE, schedule, silc_net_connect_stream,
518                              (void *)this);
519       sock = NULL;
520       ss = NULL;
521     } else {
522       sock->Close();
523       delete sock;
524       ss->Close();
525       delete ss;
526       sock = NULL;
527       ss = NULL;
528       delete this;
529     }
530   }
531
532   /* Cancel */
533   virtual void DoCancel()
534   {
535     if (ss) {
536       ss->Close();
537       delete ss;
538     }
539     if (sock) {
540       sock->CancelConnect();
541       delete sock;
542     }
543   }
544
545   RSocket *sock;
546   RSocketServ *ss;
547   char *remote;
548   char remote_ip[64];
549   int port;
550   SilcAsyncOperation op;
551   SilcSchedule schedule;
552   SilcNetCallback callback;
553   void *context;
554 };
555
556 extern "C" {
557
558 /* TCP stream creation callback */
559
560 static void silc_net_connect_stream(SilcSocketStreamStatus status,
561                                     SilcStream stream, void *context)
562 {
563   SilcSymbianTCPConnect *conn = (SilcSymbianTCPConnect *)context;
564   SilcNetStatus net_status = SILC_NET_OK;
565
566   SILC_LOG_DEBUG(("Socket stream creation status %d", status));
567
568   if (status != SILC_SOCKET_OK) {
569     /* In case of error, the socket has been destroyed already via
570        silc_stream_destroy. */
571     if (status == SILC_SOCKET_UNKNOWN_IP)
572       net_status = SILC_NET_UNKNOWN_IP;
573     else if (status == SILC_SOCKET_UNKNOWN_HOST)
574       net_status = SILC_NET_UNKNOWN_HOST;
575     else
576       net_status = SILC_NET_ERROR;
577   }
578
579   /* Call connection callback */
580   if (conn->callback)
581     conn->callback(net_status, stream, conn->context);
582   else if (stream)
583     silc_stream_destroy(stream);
584
585   delete conn;
586 }
587
588 /* Connecting abort callback */
589
590 static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
591 {
592   SilcSymbianTCPConnect *conn = (SilcSymbianTCPConnect *)context;
593
594   /* Abort */
595   conn->callback = NULL;
596   conn->op = NULL;
597   if (conn->sock)
598     conn->sock->CancelConnect();
599 }
600
601 /* Create TCP/IP connection */
602
603 SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
604                                         const char *remote_ip_addr,
605                                         int remote_port,
606                                         SilcSchedule schedule,
607                                         SilcNetCallback callback,
608                                         void *context)
609 {
610   SilcSymbianTCPConnect *conn;
611   TInetAddr local, remote;
612   SilcNetStatus status;
613   TInt ret;
614
615   if (!remote_ip_addr || remote_port < 1 || !schedule || !callback)
616     return NULL;
617
618   SILC_LOG_DEBUG(("Creating connection to host %s port %d",
619                   remote_ip_addr, remote_port));
620
621   conn = new SilcSymbianTCPConnect;
622   if (!conn) {
623     callback(SILC_NET_NO_MEMORY, NULL, context);
624     return NULL;
625   }
626   conn->schedule = schedule;
627   conn->callback = callback;
628   conn->context = context;
629   conn->port = remote_port;
630   conn->remote = strdup(remote_ip_addr);
631   if (!conn->remote) {
632     status = SILC_NET_NO_MEMORY;
633     goto err;
634   }
635
636   /* Allocate socket */
637   conn->sock = new RSocket;
638   if (!conn->sock) {
639     status = SILC_NET_NO_MEMORY;
640     goto err;
641   }
642
643   /* Allocate socket server */
644   conn->ss = new RSocketServ;
645   if (!conn->ss) {
646     status = SILC_NET_NO_MEMORY;
647     goto err;
648   }
649
650   /* Connect to socket server */
651   ret = conn->ss->Connect();
652   if (ret != KErrNone) {
653     SILC_LOG_ERROR(("Error connecting to socket server, error %d", ret));
654     status = SILC_NET_ERROR;
655     goto err;
656   }
657
658 #ifdef SILC_THREADS
659   /* Make our socket shareable between threads */
660   conn->ss->ShareAuto();
661 #endif /* SILC_THREADS */
662
663   /* Start async operation */
664   conn->op = silc_async_alloc(silc_net_connect_abort, NULL, (void *)conn);
665   if (!conn->op) {
666     status = SILC_NET_NO_MEMORY;
667     goto err;
668   }
669
670   /* Do host lookup */
671   if (!silc_net_gethostbyname(remote_ip_addr, FALSE, conn->remote_ip,
672                               sizeof(conn->remote_ip))) {
673     SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
674                     "host", conn->remote));
675     status = SILC_NET_HOST_UNREACHABLE;
676     goto err;
677   }
678
679   /* Create the connection socket */
680   ret = conn->sock->Open(*conn->ss, KAfInet, KSockStream, KProtocolInetTcp);
681   if (ret != KErrNone) {
682     SILC_LOG_ERROR(("Cannot create socket, error %d", ret));
683     status = SILC_NET_ERROR;
684     goto err;
685   }
686
687   /* Set appropriate options */
688   conn->sock->SetOpt(KSoTcpNoDelay, KSolInetTcp, 1);
689   conn->sock->SetOpt(KSoTcpKeepAlive, KSolInetTcp, 1);
690
691   /* Bind to the local address if provided */
692   if (local_ip_addr)
693     if (silc_net_set_sockaddr(&local, local_ip_addr, 0))
694       conn->sock->Bind(local);
695
696   /* Connect to the host */
697   if (!silc_net_set_sockaddr(&remote, conn->remote_ip, remote_port)) {
698     SILC_LOG_ERROR(("Cannot connect (cannot set address)"));
699     status = SILC_NET_ERROR;
700     goto err;
701   }
702   conn->Connect(remote);
703
704   SILC_LOG_DEBUG(("Connection operation in progress"));
705
706   return conn->op;
707
708  err:
709   if (conn->ss) {
710     conn->ss->Close();
711     delete conn->ss;
712   }
713   if (conn->sock)
714     delete conn->sock;
715   if (conn->remote)
716     silc_free(conn->remote);
717   if (conn->op)
718     silc_async_free(conn->op);
719   callback(status, NULL, context);
720   delete conn;
721   return NULL;
722 }
723
724 /****************************** UDP routines ********************************/
725
726 /* Create UDP/IP connection */
727
728 SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port,
729                                 const char *remote_ip_addr, int remote_port,
730                                 SilcSchedule schedule)
731 {
732   SilcSymbianSocket *s;
733   SilcStream stream;
734   TInetAddr local, remote;
735   TRequestStatus status;
736   RSocket *sock = NULL;
737   RSocketServ *ss = NULL;
738   TInt ret;
739
740   SILC_LOG_DEBUG(("Creating UDP stream"));
741
742   if (!schedule)
743     goto err;
744
745   SILC_LOG_DEBUG(("Binding to local address %s",
746                   local_ip_addr ? local_ip_addr : "0.0.0.0"));
747
748   sock = new RSocket;
749   if (!sock)
750     goto err;
751
752   ss = new RSocketServ;
753   if (!ss)
754     goto err;
755
756   /* Open socket server */
757   ret = ss->Connect();
758   if (ret != KErrNone)
759     goto err;
760
761 #ifdef SILC_THREADS
762   /* Make our socket shareable between threads */
763   ss->ShareAuto();
764 #endif /* SILC_THREADS */
765
766   /* Get local bind address */
767   if (!silc_net_set_sockaddr(&local, local_ip_addr, local_port))
768     goto err;
769
770   /* Create the socket */
771   ret = sock->Open(*ss, KAfInet, KSockDatagram, KProtocolInetUdp);
772   if (ret != KErrNone) {
773     SILC_LOG_ERROR(("Cannot create socket"));
774     goto err;
775   }
776
777   /* Set the socket options */
778   sock->SetOpt(KSoReuseAddr, KSolInetIp, 1);
779
780   /* Bind the listener socket */
781   ret = sock->Bind(local);
782   if (ret != KErrNone) {
783     SILC_LOG_DEBUG(("Cannot bind socket"));
784     goto err;
785   }
786
787   /* Set to connected state if remote address is provided. */
788   if (remote_ip_addr && remote_port) {
789     if (silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port)) {
790       sock->Connect(remote, status);
791       if (status != KErrNone) {
792         SILC_LOG_DEBUG(("Cannot connect UDP stream"));
793         goto err;
794       }
795     }
796   }
797
798   /* Encapsulate into socket stream */
799   s = silc_create_symbian_socket(sock, ss);
800   if (!s)
801     goto err;
802   stream =
803     silc_socket_udp_stream_create((SilcSocket)s, local_ip_addr ?
804                                   silc_net_is_ip6(local_ip_addr) : FALSE,
805                                   remote_ip_addr ? TRUE : FALSE, schedule);
806   if (!stream)
807     goto err;
808
809   SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
810   return stream;
811
812  err:
813   if (sock)
814     delete sock;
815   if (ss) {
816     ss->Close();
817     delete ss;
818   }
819   return NULL;
820 }
821
822 /* Sets socket to non-blocking mode */
823
824 int silc_net_set_socket_nonblock(SilcSocket sock)
825 {
826   /* Nothing to do in Symbian where blocking socket mode is asynchronous
827      already (ie. non-blocking). */
828   return 0;
829 }
830
831 /* Converts the IP number string from numbers-and-dots notation to
832    binary form. */
833
834 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
835 {
836   int ret = 0;
837   struct in_addr tmp;
838
839   ret = inet_aton(addr, &tmp);
840   if (bin_len < 4)
841     return FALSE;
842
843   memcpy(bin, (unsigned char *)&tmp.s_addr, 4);
844
845   return ret != 0;
846 }
847
848 /* Get remote host and IP from socket */
849
850 SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,
851                                      char **ip)
852 {
853   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
854   TInetAddr addr;
855   char host[256];
856   TBuf<64> tmp;
857
858   if (hostname)
859     *hostname = NULL;
860   *ip = NULL;
861
862   s->sock->RemoteName(addr);
863   addr.Output(tmp);
864
865   *ip = (char *)silc_memdup(tmp.Ptr(), tmp.Length());
866   if (*ip == NULL)
867     return FALSE;
868
869   /* Do reverse lookup if we want hostname too. */
870   if (hostname) {
871     /* Get host by address */
872     if (!silc_net_gethostbyaddr(*ip, host, sizeof(host)))
873       return FALSE;
874
875     *hostname = (char *)silc_memdup(host, strlen(host));
876     SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));
877
878     /* Reverse */
879     if (!silc_net_gethostbyname(*hostname, TRUE, host, sizeof(host)))
880       return FALSE;
881
882     if (strcmp(*ip, host))
883       return FALSE;
884   }
885
886   SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
887   return TRUE;
888 }
889
890 /* Get local host and IP from socket */
891
892 SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,
893                                       char **ip)
894 {
895   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
896   TInetAddr addr;
897   char host[256];
898   TBuf<64> tmp;
899
900   if (hostname)
901     *hostname = NULL;
902   *ip = NULL;
903
904   s->sock->LocalName(addr);
905   addr.Output(tmp);
906
907   *ip = (char *)silc_memdup(tmp.Ptr(), tmp.Length());
908   if (*ip == NULL)
909     return FALSE;
910
911   /* Do reverse lookup if we want hostname too. */
912   if (hostname) {
913     /* Get host by address */
914     if (!silc_net_gethostbyaddr(*ip, host, sizeof(host)))
915       return FALSE;
916
917     *hostname = (char *)silc_memdup(host, strlen(host));
918     SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));
919
920     /* Reverse */
921     if (!silc_net_gethostbyname(*hostname, TRUE, host, sizeof(host)))
922       return FALSE;
923
924     if (strcmp(*ip, host))
925       return FALSE;
926   }
927
928   SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
929   return TRUE;
930 }
931
932 /* Get remote port from socket */
933
934 SilcUInt16 silc_net_get_remote_port(SilcSocket sock)
935 {
936   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
937   TInetAddr addr;
938
939   s->sock->RemoteName(addr);
940   return (SilcUInt16)addr.Port();
941 }
942
943 /* Get local port from socket */
944
945 SilcUInt16 silc_net_get_local_port(SilcSocket sock)
946 {
947   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
948   TInetAddr addr;
949
950   s->sock->LocalName(addr);
951   return (SilcUInt16)addr.Port();
952 }
953
954 } /* extern "C" */