Added preliminary Symbian support.
[silc.git] / lib / silcutil / symbian / silcsymbiannet.cpp
1 /*\r
2 \r
3   silcsymbiannet.cpp\r
4 \r
5   Author: Pekka Riikonen <priikone@silcnet.org>\r
6 \r
7   Copyright (C) 2006 Pekka Riikonen\r
8 \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
12 \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
17 \r
18 */\r
19 \r
20 #include "silc.h"\r
21 #include "silcsymbiansocketstream.h"\r
22 \r
23 /****************************** TCP Listener ********************************/\r
24 \r
25 class SilcSymbianTCPListener;\r
26 \r
27 /* Deliver new stream to upper layer */\r
28 \r
29 static void silc_net_accept_stream(SilcSocketStreamStatus status,\r
30                                    SilcStream stream, void *context)\r
31 {\r
32   SilcNetListener listener = (SilcNetListener)context;\r
33 \r
34   /* In case of error, the socket has been destroyed already */\r
35   if (status != SILC_SOCKET_OK)\r
36     return;\r
37 \r
38   listener->callback(SILC_NET_OK, stream, listener->context);\r
39 }\r
40 \r
41 /* TCP Listener class */\r
42 \r
43 class SilcSymbianTCPListener : public CActive {\r
44 public:\r
45   /* Constructor */\r
46   SilcSymbianTCPListener() : CActive(CActive::EPriorityStandard)\r
47   {\r
48     CActiveScheduler::Add(this);\r
49   }\r
50 \r
51   /* Destructor */\r
52   ~SilcSymbianTCPListener()\r
53   {\r
54     Cancel();\r
55   }\r
56 \r
57   /* Listen for connection */\r
58   void Listen()\r
59   {\r
60     new_conn = new RSocket;\r
61     if (!new_conn)\r
62       return;\r
63     User::LeaveIfError(new_conn->Open(ss));\r
64 \r
65     /* Start listenning */\r
66     sock.Accept(*new_conn, iStatus);\r
67     SetActive();\r
68   }\r
69 \r
70   /* Listener callback */\r
71   void RunL()\r
72   {\r
73     if (iStatus != KErrNone) {\r
74       if (new_conn)\r
75         delete new_conn;\r
76       new_conn = NULL;\r
77       Listen();\r
78       return;\r
79     }\r
80 \r
81     /* Set socket options */\r
82     new_conn->SetOpt(KSoReuseAddr, KSolInetIp, 1);\r
83 \r
84     /* Create socket stream */\r
85     silc_socket_tcp_stream_create(\r
86                         (SilcSocket)silc_create_symbian_socket(new_conn, NULL),\r
87                         listener->lookup, listener->require_fqdn,\r
88                         listener->schedule, silc_net_accept_stream,\r
89                         (void *)listener);\r
90 \r
91     /* Continue listenning */\r
92     Listen();\r
93   }\r
94 \r
95   /* Cancel */\r
96   void DoCancel()\r
97   {\r
98     sock.CancelAll();\r
99     ss.Close();\r
100     if (new_conn)\r
101       delete new_conn;\r
102   }\r
103 \r
104   RSocket *new_conn;\r
105   RSocket sock;\r
106   RSocketServ ss;\r
107   SilcNetListener listener;\r
108 };\r
109 \r
110 /* Create TCP listener */\r
111 \r
112 SilcNetListener\r
113 silc_net_tcp_create_listener(const char **local_ip_addr,\r
114                              SilcUInt32 local_ip_count, int port,\r
115                              SilcBool lookup, SilcBool require_fqdn,\r
116                              SilcSchedule schedule,\r
117                              SilcNetCallback callback, void *context)\r
118 {\r
119   SilcNetListener listener = NULL;\r
120   SilcSymbianTCPListener *l = NULL;\r
121   TInetAddr server;\r
122   TInt ret;\r
123   TBuf<64> tmp;\r
124   int i;\r
125 \r
126   SILC_LOG_DEBUG(("Creating TCP listener"));\r
127 \r
128   if (port < 0 || !schedule || !callback)\r
129     goto err;\r
130 \r
131   listener = (SilcNetListener)silc_calloc(1, sizeof(*listener));\r
132   if (!listener) {\r
133     callback(SILC_NET_NO_MEMORY, NULL, context);\r
134     return NULL;\r
135   }\r
136   listener->schedule = schedule;\r
137   listener->callback = callback;\r
138   listener->context = context;\r
139   listener->require_fqdn = require_fqdn;\r
140   listener->lookup = lookup;\r
141 \r
142   if (local_ip_count > 0) {\r
143     listener->socks = (SilcSocket *)silc_calloc(local_ip_count,\r
144                                               sizeof(*listener->socks));\r
145     if (!listener->socks) {\r
146       callback(SILC_NET_NO_MEMORY, NULL, context);\r
147       return NULL;\r
148     }\r
149   } else {\r
150     listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks));\r
151     if (!listener->socks) {\r
152       callback(SILC_NET_NO_MEMORY, NULL, context);\r
153       return NULL;\r
154     }\r
155 \r
156     local_ip_count = 1;\r
157   }\r
158 \r
159   /* Bind to local addresses */\r
160   for (i = 0; i < local_ip_count; i++) {\r
161     SILC_LOG_DEBUG(("Binding to local address %s",\r
162                     local_ip_addr ? local_ip_addr[i] : "0.0.0.0"));\r
163 \r
164     l = new SilcSymbianTCPListener;\r
165     if (!l)\r
166       goto err;\r
167 \r
168     /* Connect to socket server */\r
169     ret = l->ss.Connect();\r
170     if (ret != KErrNone)\r
171       goto err;\r
172 \r
173     /* Set listener address */\r
174     if (local_ip_addr) {\r
175       server = TInetAddr(port);\r
176           tmp = (TText *)local_ip_addr[i];\r
177       ret = server.Input(tmp);\r
178       if (ret != KErrNone)\r
179         goto err;\r
180     } else {\r
181       server = TInetAddr(KInetAddrAny, port);\r
182     }\r
183 \r
184     /* Create the socket */\r
185     ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp);\r
186     if (ret != KErrNone) {\r
187       SILC_LOG_ERROR(("Cannot create socket"));\r
188       goto err;\r
189     }\r
190 \r
191     /* Set the socket options */\r
192     ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1);\r
193     if (ret != KErrNone) {\r
194       SILC_LOG_ERROR(("Cannot set socket options"));\r
195       goto err;\r
196     }\r
197 \r
198     /* Bind the listener socket */\r
199     ret = l->sock.Bind(server);\r
200     if (ret != KErrNone) {\r
201       SILC_LOG_DEBUG(("Cannot bind socket"));\r
202       goto err;\r
203     }\r
204 \r
205     /* Specify that we are listenning */\r
206     ret = l->sock.Listen(5);\r
207     if (ret != KErrNone) {\r
208       SILC_LOG_ERROR(("Cannot set socket listenning"));\r
209       goto err;\r
210     }\r
211     l->Listen();\r
212 \r
213     l->listener = listener;\r
214     listener->socks[i] = (SilcSocket)l;\r
215     listener->socks_count++;\r
216   }\r
217 \r
218   SILC_LOG_DEBUG(("TCP listener created"));\r
219 \r
220   return listener;\r
221 \r
222  err:\r
223   if (l)\r
224     delete l;\r
225   if (callback)\r
226     callback(SILC_NET_ERROR, NULL, context);\r
227   if (listener)\r
228     silc_net_close_listener(listener);\r
229   return NULL;\r
230 }\r
231 \r
232 /* Close network listener */\r
233 \r
234 void silc_net_close_listener(SilcNetListener listener)\r
235 {\r
236   int i;\r
237 \r
238   SILC_LOG_DEBUG(("Closing network listener"));\r
239 \r
240   for (i = 0; i < listener->socks_count; i++) {\r
241     SilcSymbianTCPListener *l = (SilcSymbianTCPListener *)listener->socks[i];\r
242     l->sock.CancelAll();\r
243     l->sock.Close();\r
244     l->ss.Close();\r
245     if (l->new_conn)\r
246       delete l->new_conn;\r
247     delete l;\r
248   }\r
249 \r
250   silc_free(listener->socks);\r
251   silc_free(listener);\r
252 }\r
253 \r
254 /**************************** TCP/IP connecting *****************************/\r
255 \r
256 static void silc_net_connect_stream(SilcSocketStreamStatus status,\r
257                                     SilcStream stream, void *context);\r
258 \r
259 /* TCP connecting class */\r
260 \r
261 class SilcSymbianTCPConnect : public CActive {\r
262 public:\r
263   /* Constructor */\r
264   SilcSymbianTCPConnect() : CActive(CActive::EPriorityStandard)\r
265   {\r
266     CActiveScheduler::Add(this);\r
267   }\r
268 \r
269   /* Destructor */\r
270   ~SilcSymbianTCPConnect()\r
271   {\r
272     silc_free(remote);\r
273     if (op)\r
274       silc_async_free(op);\r
275     Cancel();\r
276   }\r
277 \r
278   /* Connect to remote host */\r
279   void Connect(TSockAddr &addr)\r
280   {\r
281     sock->Connect(addr, iStatus);\r
282     SetActive();\r
283   }\r
284 \r
285   /* Connection callback */\r
286   void RunL()\r
287   {\r
288     if (iStatus != KErrNone) {\r
289       if (callback)\r
290         callback(SILC_NET_ERROR, NULL, context);\r
291       sock->CancelConnect();\r
292       delete sock;\r
293       ss->Close();\r
294       delete ss;\r
295       delete this;\r
296     }\r
297 \r
298     /* Create stream */\r
299     if (callback) {\r
300       silc_socket_tcp_stream_create(\r
301                              (SilcSocket)silc_create_symbian_socket(sock, ss),\r
302                              FALSE, FALSE, schedule, silc_net_connect_stream,\r
303                              (void *)this);\r
304     } else {\r
305       sock->Close();\r
306       delete sock;\r
307       ss->Close();\r
308       delete ss;\r
309     }\r
310 \r
311     delete this;\r
312   }\r
313 \r
314   /* Cancel */\r
315   void DoCancel()\r
316   {\r
317     sock->CancelConnect();\r
318     ss->Close();\r
319     delete ss;\r
320     delete sock;\r
321     delete this;\r
322   }\r
323 \r
324   RSocket *sock;\r
325   RSocketServ *ss;\r
326   char *remote;\r
327   char remote_ip[64];\r
328   int port;\r
329   SilcAsyncOperation op;\r
330   SilcSchedule schedule;\r
331   SilcNetCallback callback;\r
332   void *context;\r
333 };\r
334 \r
335 /* Stream creation callback */\r
336 \r
337 static void silc_net_connect_stream(SilcSocketStreamStatus status,\r
338                                     SilcStream stream, void *context)\r
339 {\r
340   SilcSymbianTCPConnect *conn = (SilcSymbianTCPConnect *)context;\r
341   SilcNetStatus net_status = SILC_NET_OK;\r
342 \r
343   if (status != SILC_SOCKET_OK) {\r
344     /* In case of error, the socket has been destroyed already */\r
345     if (status == SILC_SOCKET_UNKNOWN_IP)\r
346       net_status = SILC_NET_UNKNOWN_IP;\r
347     else if (status == SILC_SOCKET_UNKNOWN_HOST)\r
348       net_status = SILC_NET_UNKNOWN_HOST;\r
349     else\r
350       net_status = SILC_NET_ERROR;\r
351   }\r
352 \r
353   /* Set stream information */\r
354   if (stream && conn->callback)\r
355     silc_socket_stream_set_info(stream,\r
356                                 !silc_net_is_ip(conn->remote) ? conn->remote :\r
357                                 conn->remote_ip, conn->remote_ip, conn->port);\r
358 \r
359   /* Call connection callback */\r
360   if (conn->callback)\r
361     conn->callback(net_status, stream, conn->context);\r
362   else if (stream)\r
363     silc_stream_destroy(stream);\r
364 \r
365   delete conn;\r
366 }\r
367 \r
368 /* Connecting abort callback */\r
369 \r
370 static void silc_net_connect_abort(SilcAsyncOperation op, void *context)\r
371 {\r
372   SilcSymbianTCPConnect *conn = (SilcSymbianTCPConnect *)context;\r
373 \r
374   /* Abort */\r
375   conn->callback = NULL;\r
376   conn->op = NULL;\r
377   conn->DoCancel();\r
378 }\r
379 \r
380 /* Create TCP/IP connection */\r
381 \r
382 SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,\r
383                                         const char *remote_ip_addr,\r
384                                         int remote_port,\r
385                                         SilcSchedule schedule,\r
386                                         SilcNetCallback callback,\r
387                                         void *context)\r
388 {\r
389   SilcSymbianTCPConnect *conn;\r
390   TInetAddr local, remote;\r
391   SilcNetStatus status;\r
392   TBuf<64> tmp;\r
393   TInt ret;\r
394 \r
395   if (!remote_ip_addr || remote_port < 1 || !schedule || !callback)\r
396     return NULL;\r
397 \r
398   SILC_LOG_DEBUG(("Creating connection to host %s port %d",\r
399                   remote_ip_addr, remote_port));\r
400 \r
401   conn = new SilcSymbianTCPConnect;\r
402   if (!conn) {\r
403     callback(SILC_NET_NO_MEMORY, NULL, context);\r
404     return NULL;\r
405   }\r
406   conn->schedule = schedule;\r
407   conn->callback = callback;\r
408   conn->context = context;\r
409   conn->port = remote_port;\r
410   conn->remote = strdup(remote_ip_addr);\r
411   if (!conn->remote) {\r
412     status = SILC_NET_NO_MEMORY;\r
413     goto err;\r
414   }\r
415 \r
416   /* Allocate socket */\r
417   conn->sock = new RSocket;\r
418   if (!conn->sock) {\r
419     status = SILC_NET_NO_MEMORY;\r
420     goto err;\r
421   }\r
422 \r
423   /* Allocate socket server */\r
424   conn->ss = new RSocketServ;\r
425   if (!conn->ss) {\r
426     status = SILC_NET_NO_MEMORY;\r
427     goto err;\r
428   }\r
429 \r
430   /* Connect to socket server */\r
431   ret = conn->ss->Connect();\r
432   if (ret != KErrNone) {\r
433     status = SILC_NET_ERROR;\r
434     goto err;\r
435   }\r
436 \r
437   /* Start async operation */\r
438   conn->op = silc_async_alloc(silc_net_connect_abort, NULL, (void *)conn);\r
439   if (!conn->op) {\r
440     status = SILC_NET_NO_MEMORY;\r
441     goto err;\r
442   }\r
443 \r
444   /* Do host lookup */\r
445   if (!silc_net_is_ip(remote_ip_addr)) {\r
446     if (!silc_net_gethostbyname(remote_ip_addr, FALSE, conn->remote_ip,\r
447                                 sizeof(conn->remote_ip))) {\r
448       SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "\r
449                       "host", conn->remote));\r
450       status = SILC_NET_HOST_UNREACHABLE;\r
451       goto err;\r
452     }\r
453   } else {\r
454     strcpy(conn->remote_ip, remote_ip_addr);\r
455   }\r
456 \r
457   /* Create the connection socket */\r
458   ret = conn->sock->Open(*conn->ss, KAfInet, KSockStream, KProtocolInetTcp);\r
459   if (ret != KErrNone) {\r
460     SILC_LOG_ERROR(("Cannot create socket"));\r
461     status = SILC_NET_ERROR;\r
462     goto err;\r
463   }\r
464 \r
465   /* Set appropriate options */\r
466   conn->sock->SetOpt(KSoTcpNoDelay, KSolInetTcp, 1);\r
467   conn->sock->SetOpt(KSoTcpKeepAlive, KSolInetTcp, 1);\r
468 \r
469   /* Bind to the local address if provided */\r
470   if (local_ip_addr) {\r
471     local = TInetAddr(0);\r
472         tmp = (TText *)local_ip_addr;\r
473     ret = local.Input(tmp);\r
474     if (ret == KErrNone)\r
475       ret = conn->sock->Bind(local);\r
476   }\r
477 \r
478   /* Connect to the host */\r
479   remote = TInetAddr(remote_port);\r
480   tmp = (TText *)conn->remote_ip;\r
481   ret = remote.Input(tmp);\r
482   if (ret != KErrNone) {\r
483     SILC_LOG_ERROR(("Cannot connect (cannot set address)"));\r
484     status = SILC_NET_ERROR;\r
485     goto err;\r
486   }\r
487   conn->Connect(remote);\r
488 \r
489   SILC_LOG_DEBUG(("Connection operation in progress"));\r
490 \r
491   return conn->op;\r
492 \r
493  err:\r
494   if (conn->ss) {\r
495     conn->ss->Close();\r
496     delete conn->ss;\r
497   }\r
498   if (conn->sock)\r
499     delete conn->sock;\r
500   if (conn->remote)\r
501     silc_free(conn->remote);\r
502   if (conn->op)\r
503     silc_async_free(conn->op);\r
504   callback(status, NULL, context);\r
505   delete conn;\r
506   return NULL;\r
507 }\r
508 \r
509 /****************************** UDP routines ********************************/\r
510 \r
511 /* Create UDP/IP connection */\r
512 \r
513 SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port,\r
514                                 const char *remote_ip_addr, int remote_port,\r
515                                 SilcSchedule schedule)\r
516 {\r
517   SilcSymbianSocket *s;\r
518   SilcStream stream;\r
519   TInetAddr local, remote;\r
520   TRequestStatus status;\r
521   RSocket *sock = NULL;\r
522   RSocketServ *ss = NULL;\r
523   TBuf<64> tmp;\r
524   TInt ret;\r
525 \r
526   SILC_LOG_DEBUG(("Creating UDP stream"));\r
527 \r
528   if (!schedule)\r
529     goto err;\r
530 \r
531   SILC_LOG_DEBUG(("Binding to local address %s",\r
532                   local_ip_addr ? local_ip_addr : "0.0.0.0"));\r
533 \r
534   sock = new RSocket;\r
535   if (!sock)\r
536     goto err;\r
537 \r
538   ss = new RSocketServ;\r
539   if (!ss)\r
540     goto err;\r
541 \r
542   /* Open socket server */\r
543   ret = ss->Connect();\r
544   if (ret != KErrNone)\r
545     goto err;\r
546 \r
547   /* Get local bind address */\r
548   if (local_ip_addr) {\r
549     local = TInetAddr(local_port);\r
550         tmp = (TText *)local_ip_addr;\r
551     ret = local.Input(tmp);\r
552     if (ret != KErrNone)\r
553       goto err;\r
554   } else {\r
555     local = TInetAddr(KInetAddrAny, local_port);\r
556   }\r
557 \r
558   /* Create the socket */\r
559   ret = sock->Open(*ss, KAfInet, KSockDatagram, KProtocolInetUdp);\r
560   if (ret != KErrNone) {\r
561     SILC_LOG_ERROR(("Cannot create socket"));\r
562     goto err;\r
563   }\r
564 \r
565   /* Set the socket options */\r
566   sock->SetOpt(KSoReuseAddr, KSolInetIp, 1);\r
567 \r
568   /* Bind the listener socket */\r
569   ret = sock->Bind(local);\r
570   if (ret != KErrNone) {\r
571     SILC_LOG_DEBUG(("Cannot bind socket"));\r
572     goto err;\r
573   }\r
574 \r
575   /* Set to connected state if remote address is provided. */\r
576   if (remote_ip_addr && remote_port) {\r
577     remote = TInetAddr(remote_port);\r
578         tmp = (TText *)remote_ip_addr;\r
579     ret = remote.Input(tmp);\r
580     if (ret != KErrNone)\r
581       goto err;\r
582 \r
583     sock->Connect(remote, status);\r
584     if (status != KErrNone) {\r
585       SILC_LOG_DEBUG(("Cannot connect UDP stream"));\r
586       goto err;\r
587     }\r
588   }\r
589 \r
590   /* Encapsulate into socket stream */\r
591   s = silc_create_symbian_socket(sock, ss);\r
592   if (!s)\r
593     goto err;\r
594   stream =\r
595     silc_socket_udp_stream_create((SilcSocket)s, local_ip_addr ?\r
596                                   silc_net_is_ip6(local_ip_addr) : FALSE,\r
597                                   remote_ip_addr ? TRUE : FALSE, schedule);\r
598   if (!stream)\r
599     goto err;\r
600 \r
601   SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));\r
602   return stream;\r
603 \r
604  err:\r
605   if (sock)\r
606     delete sock;\r
607   if (ss) {\r
608     ss->Close();\r
609     delete ss;\r
610   }\r
611   return NULL;\r
612 }\r
613 \r
614 /* Sets socket to non-blocking mode */\r
615 \r
616 int silc_net_set_socket_nonblock(SilcSocket sock)\r
617 {\r
618   /* Nothing to do in Symbian where blocking socket mode is asynchronous\r
619      already (ie. non-blocking). */\r
620   return 0;\r
621 }\r
622 \r
623 /* Converts the IP number string from numbers-and-dots notation to\r
624    binary form. */\r
625 \r
626 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)\r
627 {\r
628   int ret = 0;\r
629 \r
630   struct in_addr tmp;\r
631   ret = inet_aton(addr, &tmp);\r
632   if (bin_len < 4)\r
633     return FALSE;\r
634 \r
635   memcpy(bin, (unsigned char *)&tmp.s_addr, 4);\r
636 \r
637   return ret != 0;\r
638 }\r
639 \r
640 /* Get remote host and IP from socket */\r
641 \r
642 SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,\r
643                                      char **ip)\r
644 {\r
645   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;\r
646   TInetAddr addr;\r
647   char host[256];\r
648   TBuf<64> tmp;\r
649 \r
650   if (hostname)\r
651     *hostname = NULL;\r
652   *ip = NULL;\r
653 \r
654   s->sock->RemoteName(addr);\r
655   addr.Output(tmp);\r
656 \r
657   *ip = (char *)silc_memdup(tmp.Ptr(), tmp.Length());\r
658   if (*ip == NULL)\r
659     return FALSE;\r
660 \r
661   /* Do reverse lookup if we want hostname too. */\r
662   if (hostname) {\r
663     /* Get host by address */\r
664     if (!silc_net_gethostbyaddr(*ip, host, sizeof(host)))\r
665       return FALSE;\r
666 \r
667     *hostname = (char *)silc_memdup(host, strlen(host));\r
668     SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));\r
669 \r
670     /* Reverse */\r
671     if (!silc_net_gethostbyname(*hostname, TRUE, host, sizeof(host)))\r
672       return FALSE;\r
673 \r
674     if (strcmp(*ip, host))\r
675       return FALSE;\r
676   }\r
677 \r
678   SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));\r
679   return TRUE;\r
680 }\r
681 \r
682 /* Get local host and IP from socket */\r
683 \r
684 SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,\r
685                                       char **ip)\r
686 {\r
687   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;\r
688   TInetAddr addr;\r
689   char host[256];\r
690   TBuf<64> tmp;\r
691 \r
692   if (hostname)\r
693     *hostname = NULL;\r
694   *ip = NULL;\r
695 \r
696   s->sock->LocalName(addr);\r
697   addr.Output(tmp);\r
698 \r
699   *ip = (char *)silc_memdup(tmp.Ptr(), tmp.Length());\r
700   if (*ip == NULL)\r
701     return FALSE;\r
702 \r
703   /* Do reverse lookup if we want hostname too. */\r
704   if (hostname) {\r
705     /* Get host by address */\r
706     if (!silc_net_gethostbyaddr(*ip, host, sizeof(host)))\r
707       return FALSE;\r
708 \r
709     *hostname = (char *)silc_memdup(host, strlen(host));\r
710     SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));\r
711 \r
712     /* Reverse */\r
713     if (!silc_net_gethostbyname(*hostname, TRUE, host, sizeof(host)))\r
714       return FALSE;\r
715 \r
716     if (strcmp(*ip, host))\r
717       return FALSE;\r
718   }\r
719 \r
720   SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));\r
721   return TRUE;\r
722 }\r
723 \r
724 /* Get remote port from socket */\r
725 \r
726 SilcUInt16 silc_net_get_remote_port(SilcSocket sock)\r
727 {\r
728   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;\r
729   TInetAddr addr;\r
730 \r
731   s->sock->RemoteName(addr);\r
732   return (SilcUInt16)addr.Port();\r
733 }\r
734 \r
735 /* Get local port from socket */\r
736 \r
737 SilcUInt16 silc_net_get_local_port(SilcSocket sock)\r
738 {\r
739   SilcSymbianSocket *s = (SilcSymbianSocket *)sock;\r
740   TInetAddr addr;\r
741 \r
742   s->sock->LocalName(addr);\r
743   return (SilcUInt16)addr.Port();\r
744 }\r