Added SILC errno API. Added SilcResult, generic error code and
[silc.git] / lib / silcutil / silcnet.h
1 /*
2
3   silcnet.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 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 /****h* silcutil/SILC Net Interface
21  *
22  * DESCRIPTION
23  *
24  * SILC Net API provides various network routines for applications. It
25  * can be used to create TCP/IP and UDP/IP connections and listeners.
26  * Various utility functions for resolving various information is also
27  * provided.
28  *
29  ***/
30
31 #ifndef SILCNET_H
32 #define SILCNET_H
33
34 /* Prototypes */
35
36 /****s* silcutil/SilcNetAPI/SilcNetListener
37  *
38  * NAME
39  *
40  *    typedef struct SilcNetListenerStruct *SilcNetListener;
41  *
42  * DESCRIPTION
43  *
44  *    The network listenr context.  This context is created with the
45  *    silc_net_create_listener function and destroyed with
46  *    silc_net_close_listener function.
47  *
48  ***/
49 typedef struct SilcNetListenerStruct *SilcNetListener;
50
51 /****f* silcutil/SilcNetAPI/SilcNetCallback
52  *
53  * SYNOPSIS
54  *
55  *    typedef void (*SilcNetCallback)(SilcResult status,
56  *                                    SilcStream stream, void *context);
57  *
58  * DESCRIPTION
59  *
60  *    A callback of this type is returned by silc_net_tcp_create_listener
61  *    and silc_net_tcp_connect functions.  For silc_net_tcp_create_listener
62  *    this callback means that new incoming connection was accepted, and the
63  *    `stream' is the socket stream representing the socket connection.
64  *
65  *    For silc_net_tcp_connect this means that we have connected to the
66  *    remote host and the `stream' is the socket stream for the socket
67  *    connection.  The SILC Stream API (such as silc_stream_read, etc.) can
68  *    be used to read and write to the stream.  The created stream is socket
69  *    stream so various SilcSocketStream API functions can be used with
70  *    the `stream'.
71  *
72  ***/
73 typedef void (*SilcNetCallback)(SilcResult status,
74                                 SilcStream stream, void *context);
75
76 /****f* silcutil/SilcNetAPI/silc_net_tcp_create_listener
77  *
78  * SYNOPSIS
79  *
80  *    SilcNetListener
81  *    silc_net_tcp_create_listener(const char **local_ip_addr,
82  *                                 SilcUInt32 local_ip_count, int port,
83  *                                 SilcBool lookup, SilcBool require_fqdn,
84  *                                 SilcSchedule schedule,
85  *                                 SilcNetCallback callback, void *context);
86  *
87  * DESCRIPTION
88  *
89  *    This function creates TCP listener.  This is used to create network
90  *    listener for incoming connections, and `callback' will be called
91  *    everytime new connection is received.  If `local_ip_addr' is NULL 'any'
92  *    address is used.  If provided it can be used bind the listener to
93  *    `local_ip_count' many IP addresses provided in `local_ip_addr' table.
94  *    On success returns the SilcNetListener context, or NULL on error.
95  *    If `require_fqdn' is TRUE the listener will require that the incoming
96  *    connection has FQDN to be able to connect.  If the `lookup' is TRUE
97  *    then the incoming connection hostname will be resolved.  If the `port'
98  *    is zero (0), operating system will define it automatically.
99  *
100  *    The `callback' always delivers valid new stream.  It is not called
101  *    with an error status.
102  *
103  ***/
104 SilcNetListener
105 silc_net_tcp_create_listener(const char **local_ip_addr,
106                              SilcUInt32 local_ip_count, int port,
107                              SilcBool lookup, SilcBool require_fqdn,
108                              SilcSchedule schedule,
109                              SilcNetCallback callback, void *context);
110
111 /****f* silcutil/SilcNetAPI/silc_net_tcp_create_listener2
112  *
113  * SYNOPSIS
114  *
115  *    SilcNetListener
116  *    silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports,
117  *                                  SilcUInt32 port_count,
118  *                                  SilcBool ignore_port_error,
119  *                                  SilcBool lookup, SilcBool require_fqdn,
120  *                                  SilcSchedule schedule,
121  *                                  SilcNetCallback callback, void *context);
122  *
123  * DESCRIPTION
124  *
125  *    This function creates TCP listener.  This is used to create network
126  *    listener for incoming connections, and `callback' will be called
127  *    everytime new connection is received.  If `local_ip_addr' is NULL 'any'
128  *    address is used.  If `ports' is NULL or it contains a zero (0) port,
129  *    operating system will define it automatically.  This function can be
130  *    used to bind to many ports at the same time.  If `ignore_port_error'
131  *    is TRUE this won't return NULL if at least one of the ports could
132  *    be bound.  Otherwise, NULL will be returned on error.
133  *
134  *    If `require_fqdn' is TRUE the listener will require that the incoming
135  *    connection has FQDN to be able to connect.  If the `lookup' is TRUE
136  *    then the incoming connection hostname will be resolved.
137  *
138  *    The `callback' always delivers valid new stream.  It is not called
139  *    with an error status.
140  *
141  ***/
142 SilcNetListener
143 silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports,
144                               SilcUInt32 port_count,
145                               SilcBool ignore_port_error,
146                               SilcBool lookup, SilcBool require_fqdn,
147                               SilcSchedule schedule,
148                               SilcNetCallback callback, void *context);
149
150 /****f* silcutil/SilcNetAPI/silc_net_listener_get_port
151  *
152  * SYNOPSIS
153  *
154  *    SilcUInt16 silc_net_listener_get_port(SilcNetListener listener);
155  *
156  * DESCRIPTION
157  *
158  *    Returns the ports to where the `listener' is bound.  This can be used
159  *    to get the port if none was specified in silc_net_tcp_create_listener.
160  *    Returns an array of ports of size of `port_count'.  The caller must
161  *    free the array with silc_free.  There are as many ports in the array
162  *    as there were IP addresses provided in silc_net_tcp_create_listener,
163  *    as there were ports provided in silc_net_tcp_create_listener2.
164  *
165  ***/
166 SilcUInt16 *silc_net_listener_get_port(SilcNetListener listener,
167                                        SilcUInt32 *port_count);
168
169 /****f* silcutil/SilcNetAPI/silc_net_listener_get_ip
170  *
171  * SYNOPSIS
172  *
173  *    char **silc_net_listener_get_ip(SilcNetListener listener,
174  *                                    SilcUInt32 *ip_count);
175  *
176  * DESCRIPTION
177  *
178  *    Returns the IP's to where the `listener' is bound.  Returns an array
179  *    of IP addresses of size of `port_count'.  The caller must free the
180  *    array and its strings with silc_free.
181  *
182  ***/
183 char **silc_net_listener_get_ip(SilcNetListener listener,
184                                 SilcUInt32 *ip_count);
185
186 /****f* silcutil/SilcNetAPI/silc_net_listener_get_hostname
187  *
188  * SYNOPSIS
189  *
190  *    char **silc_net_listener_get_hostname(SilcNetListener listener,
191  *                                          SilcUInt32 *hostname_count);
192  *
193  * DESCRIPTION
194  *
195  *    Returns the hostnames to where the `listener' is bound.  Returns an
196  *    array of hostnames of size of `port_count'.  The caller must free the
197  *    array and its strings with silc_free.
198  *
199  ***/
200 char **silc_net_listener_get_hostname(SilcNetListener listener,
201                                       SilcUInt32 *hostname_count);
202
203 /****f* silcutil/SilcNetAPI/silc_net_close_listener
204  *
205  * SYNOPSIS
206  *
207  *    void silc_net_close_listener(SilcNetListener listener);
208  *
209  * DESCRIPTION
210  *
211  *    Closes the network listener indicated by `listener'.
212  *
213  ***/
214 void silc_net_close_listener(SilcNetListener listener);
215
216 /****f* silcutil/SilcNetAPI/silc_net_tcp_connect
217  *
218  * SYNOPSIS
219  *
220  *    SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
221  *                                            const char *remote_ip_addr,
222  *                                            int remote_port,
223  *                                            SilcSchedule schedule,
224  *                                            SilcNetCallback callback,
225  *                                            void *context);
226  *
227  * DESCRIPTION
228  *
229  *    Creates TCP/IP connection to the remote host indicated by `remote_host'
230  *    which may be hostname or IP address, on the port indicated by
231  *    `remote_port'.  If the `local_ip_addr' is provided the local host is
232  *    bound to that address before creating the connection.  This is
233  *    asynchronous call, and this function returns before the connection is
234  *    actually established.  The `callback' will be called after the
235  *    connection is created to deliver the SilcStream for the created
236  *    connection.  This function supports IPv6 if the platform supports it.
237  *
238  *    The returned SilcAsyncOperation context can be used to control the
239  *    asynchronous connecting, such as to abort it.  If it is aborted
240  *    using silc_async_abort the `callback' will not be called.  If NULL
241  *    is returned the operation cannot be aborted.
242  *
243  ***/
244 SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
245                                         const char *remote_ip_addr,
246                                         int remote_port,
247                                         SilcSchedule schedule,
248                                         SilcNetCallback callback,
249                                         void *context);
250
251 /****f* silcutil/SilcNetAPI/silc_net_udp_connect
252  *
253  * SYNOPSIS
254  *
255  *    SilcStream
256  *    silc_net_udp_connect(const char *local_ip_addr, int local_port,
257  *                         const char *remote_ip_addr, int remote_port,
258  *                         SilcSchedule schedule);
259  *
260  * DESCRIPTION
261  *
262  *    This function creates UDP stream.  The UDP stream is bound to the
263  *    `local_ip_addr' if it is specified.  If `local_port' is non-zero the
264  *    stream is bound to that port.  If the `remote_ip_addr' and `remote_port'
265  *    is also provided, packets may be sent to that address using
266  *    silc_stream_write function and packets may be received using
267  *    silc_stream_read function.
268  *
269  *    If the remote address is not provided the stream is in connectionless
270  *    state.  This means that packets can be received only by using
271  *    silc_net_udp_receive and sent only by using the function
272  *    silc_net_udp_send.
273  *
274  *    To receive packets the silc_stream_set_notifier must be called for the
275  *    returned SilcStream.  The packets are always received in the notifier
276  *    callback when the SILC_STREAM_CAN_READ is returned to the callback
277  *    To read the packet use silc_stream_read if the remote address was
278  *    provided, and silc_net_udp_receive if it was not.
279  *
280  *    Supports IPv6 if the platform supports it.
281  *
282  * EXAMPLE
283  *
284  *    SilcStream udpstream;
285  *
286  *    // Create UDP stream and prepare to receive packets
287  *    udpstream = silc_net_udp_connect("10.2.1.7", 5000,
288  *                                     "10.2.1.100, 5000, schedule);
289  *    silc_stream_set_notifier(udpstream, schedule, receive_callback, context);
290  *
291  *    // Send packet to remote host
292  *    silc_stream_write(udpstream, data, data_len);
293  *
294  *    Create UDP listener:
295  *
296  *    udpstream = silc_net_udp_connect("0.0.0.0", 500, NULL, 0, schedule);
297  *    silc_stream_set_notifier(udpstream, schedule, receive_callback, context);
298  *
299  ***/
300 SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port,
301                                 const char *remote_ip_addr, int remote_port,
302                                 SilcSchedule schedule);
303
304 /****f* silcutil/SilcNetAPI/silc_net_udp_receive
305  *
306  * SYNOPSIS
307  *
308  *    int
309  *    silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
310  *                         SilcUInt32 remote_ip_addr_size, int *remote_port,
311  *                         unsigned char *ret_data, SilcUInt32 data_size)
312  *
313  * DESCRIPTION
314  *
315  *    Receive a UDP packet from the `stream'.  The IP address and port of
316  *    the sender is returned into `remote_ip_addr' buffer and `remote_port'
317  *    pointer.  The packet data is returned into the `ret_data' buffer.
318  *
319  *    Returns the length of the packet, or -1 on error or 0 in case of EOF.
320  *
321  ***/
322 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
323                          SilcUInt32 remote_ip_addr_size, int *remote_port,
324                          unsigned char *ret_data, SilcUInt32 data_size);
325
326 /****f* silcutil/SilcNetAPI/silc_net_udp_send
327  *
328  * SYNOPSIS
329  *
330  *    int silc_net_udp_send(SilcStream stream,
331  *                          const char *remote_ip_addr, int remote_port,
332  *                          const unsigned char *data, SilcUInt32 data_len);
333  *
334  * DESCRIPTION
335  *
336  *    Sends an UDP packet to remote host `remote_ip_addr' on `remote_port'.
337  *    This may be used with UDP streams that are not connected to any
338  *    specific remote host.  With those stream silc_stream_write cannot be
339  *    used.  In those cases, this function must be used.  This may also be
340  *    used even if the stream is connected.
341  *
342  *    Returns the amount of data written, -1 if data could not be written
343  *    at this moment, or -2 if error occurred.  If -1 is returned the
344  *    notifier callback will later be called with SILC_STREAM_CAN_WRITE
345  *    status when stream is again ready for writing.
346  *
347  ***/
348 int silc_net_udp_send(SilcStream stream,
349                       const char *remote_ip_addr, int remote_port,
350                       const unsigned char *data, SilcUInt32 data_len);
351
352 /****f* silcutil/SilcNetAPI/silc_net_close_connection
353  *
354  * SYNOPSIS
355  *
356  *    void silc_net_close_connection(int sock);
357  *
358  * DESCRIPTION
359  *
360  *    Closes the connection by closing the socket connection.  This routine
361  *    can only be used with POSIX compliant systems.
362  *
363  ***/
364 void silc_net_close_connection(int sock);
365
366 /****f* silcutil/SilcNetAPI/silc_net_accept_connection
367  *
368  * SYNOPSIS
369  *
370  *    int silc_net_accept_connection(int sock);
371  *
372  * DESCRIPTION
373  *
374  *    Accepts a connection from a particular socket.  This routine can only
375  *    be used with POSIX compliant systems.  This call is equivalent to
376  *    accept(2).
377  *
378  ***/
379 int silc_net_accept_connection(int sock);
380
381 /****f* silcutil/SilcNetAPI/silc_net_set_socket_opt
382  *
383  * SYNOPSIS
384  *
385  *    int silc_net_set_socket_opt(int sock, int level, int option, int on);
386  *
387  * DESCRIPTION
388  *
389  *    Sets a option for a socket.  This function can be used to set
390  *    various options for the socket.  Some of the options might be
391  *    system specific.  This routine can only be used with POSIX compliant
392  *    systems.  This call is equivalent to setsockopt(2);
393  *
394  ***/
395 int silc_net_set_socket_opt(int sock, int level, int option, int on);
396
397 /****f* silcutil/SilcNetAPI/silc_net_get_socket_opt
398  *
399  * SYNOPSIS
400  *
401  *    int silc_net_get_socket_opt(int sock, int level, int option,
402  *                                void *optval, int *opt_len);
403  *
404  * DESCRIPTION
405  *
406  *    Return socket options to the `optval' and `opt_len'.  This routine
407  *    can only be used with POSIX compliant systems.  This call is
408  *    equivalent to getsockopt(2).
409  *
410  ***/
411 int silc_net_get_socket_opt(int sock, int level, int option,
412                             void *optval, int *opt_len);
413
414 /****f* silcutil/SilcNetAPI/silc_net_set_socket_nonblock
415  *
416  * SYNOPSIS
417  *
418  *    int silc_net_set_socket_nonblock(SilcSocket sock);
419  *
420  * DESCRIPTION
421  *
422  *    Sets the socket `sock' to non-blocking mode.
423  *
424  ***/
425 int silc_net_set_socket_nonblock(SilcSocket sock);
426
427 /****f* silcutil/SilcNetAPI/silc_net_is_ip4
428  *
429  * SYNOPSIS
430  *
431  *    SilcBool silc_net_is_ip4(const char *addr);
432  *
433  * DESCRIPTION
434  *
435  *    Checks whether IP address sent as argument is valid IPv4 address.
436  *
437  ***/
438 SilcBool silc_net_is_ip4(const char *addr);
439
440 /****f* silcutil/SilcNetAPI/silc_net_is_ip6
441  *
442  * SYNOPSIS
443  *
444  *    SilcBool silc_net_is_ip6(const char *addr);
445  *
446  * DESCRIPTION
447  *
448  *    Checks whether IP address sent as argument is valid IPv6 address.
449  *
450  ***/
451 SilcBool silc_net_is_ip6(const char *addr);
452
453 /****f* silcutil/SilcNetAPI/silc_net_is_ip
454  *
455  * SYNOPSIS
456  *
457  *    SilcBool silc_net_is_ip(const char *addr);
458  *
459  * DESCRIPTION
460  *
461  *    Checks whether IP address sent as argument is valid IP address.
462  *    This supports both IPv4 and IPv6 addresses.
463  *
464  ***/
465 SilcBool silc_net_is_ip(const char *addr);
466
467 /****f* silcutil/SilcNetAPI/silc_net_addr2bin
468  *
469  * SYNOPSIS
470  *
471  *    SilcBool silc_net_addr2bin(const char *addr, void *bin,
472  *                               SilcUInt32 bin_len);
473  *
474  * DESCRIPTION
475  *
476  *    Converts the IP number string from numbers-and-dots notation to
477  *    binary form in network byte order.  The address can be either
478  *    IPv4 or IPv6 address.
479  *
480  ***/
481 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len);
482
483 /****f* silcutil/SilcNetAPI/SilcNetResolveCallback
484  *
485  * SYNOPSIS
486  *
487  *    typedef void (*SilcNetResolveCallback)(const char *result,
488  *                                           void *context);
489  *
490  * DESCRIPTION
491  *
492  *    A callback function of this type is called after the asynchronous
493  *    resolving operation has been completed.  This callback is used
494  *    when asynchronously resolving IP addresses and hostnames.
495  *
496  ***/
497 typedef void (*SilcNetResolveCallback)(const char *result, void *context);
498
499 /****f* silcutil/SilcNetAPI/silc_net_gethostbyname
500  *
501  * SYNOPSIS
502  *
503  *    SilcBool silc_net_gethostbyname(const char *name, SilcBool prefer_ipv6,
504  *                                    char *address, SilcUInt32 address_len);
505  *
506  * DESCRIPTION
507  *
508  *    Resolves the IP address of the hostname indicated by the `name'.
509  *    This returns TRUE and the IP address of the host to the `address'
510  *    buffer, or FALSE if the address could not be resolved.  This is
511  *    synchronous function and will block the calling process.  If the
512  *    `prefer_ipv6' is TRUE then this will return IPv6 address if it
513  *    finds.  If FALSE if returns IPv4 address even if it found IPv6
514  *    address also.
515  *
516  ***/
517 SilcBool silc_net_gethostbyname(const char *name, SilcBool prefer_ipv6,
518                                 char *address, SilcUInt32 address_len);
519
520 /****f* silcutil/SilcNetAPI/silc_net_gethostbyname_async
521  *
522  * SYNOPSIS
523  *
524  *    void silc_net_gethostbyname_async(const char *name,
525  *                                      SilcBool prefer_ipv6,
526  *                                      SilcSchedule schedule,
527  *                                      SilcNetResolveCallback completion,
528  *                                      void *context)
529  *
530  * DESCRIPTION
531  *
532  *    Asynchronously resolves the IP address of the hostname indicated
533  *    by the `name'.  This function returns immediately, and the
534  *    `completion' callback will be called after the resolving is
535  *    completed.
536  *
537  *    If the `prefer_ipv6' is TRUE then this will return IPv6 address if it
538  *    finds.  If FALSE if returns IPv4 address even if it found IPv6
539  *    address also.
540  *
541  ***/
542 void silc_net_gethostbyname_async(const char *name,
543                                   SilcBool prefer_ipv6,
544                                   SilcSchedule schedule,
545                                   SilcNetResolveCallback completion,
546                                   void *context);
547
548 /****f* silcutil/SilcNetAPI/silc_net_gethostbyaddr
549  *
550  * SYNOPSIS
551  *
552  *   SilcBool silc_net_gethostbyaddr(const char *addr, char *name,
553  *                                   SilcUInt32 name_len);
554  *
555 x * DESCRIPTION
556  *
557  *    Resolves the hostname for the IP address indicated by the `addr'
558  *    This returns TRUE and the resolved hostname to the `name' buffer,
559  *    or FALSE on error. The `addr' may be either IPv4 or IPv6 address.
560  *    This is synchronous function and will block the calling process.
561  *
562  ***/
563 SilcBool silc_net_gethostbyaddr(const char *addr, char *name,
564                                 SilcUInt32 name_len);
565
566 /****f* silcutil/SilcNetAPI/silc_net_gethostbyaddr_async
567  *
568  * SYNOPSIS
569  *
570  *    void silc_net_gethostbyaddr_async(const char *addr,
571  *                                      SilcSchedule schedule,
572  *                                      SilcNetResolveCallback completion,
573  *                                      void *context)
574  *
575  * DESCRIPTION
576  *
577  *    Asynchronously resolves the hostname for the IP address indicated
578  *    by the `addr'.  This function returns immediately, and the
579  *    `completion' callback will be called after the resolving is
580  *    completed.
581  *
582  ***/
583 void silc_net_gethostbyaddr_async(const char *addr,
584                                   SilcSchedule schedule,
585                                   SilcNetResolveCallback completion,
586                                   void *context);
587
588 /****f* silcutil/SilcNetAPI/silc_net_check_host_by_sock
589  *
590  * SYNOPSIS
591  *
592  *    SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,
593  *                                         char **ip);
594  *
595  * DESCRIPTION
596  *
597  *    Performs lookups for remote name and IP address. This peforms reverse
598  *    lookup as well to verify that the IP has FQDN.
599  *
600  ***/
601 SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,
602                                      char **ip);
603
604 /****f* silcutil/SilcNetAPI/silc_net_check_local_by_sock
605  *
606  * SYNOPSIS
607  *
608  *    SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,
609  *                                          char **ip);
610  *
611  * DESCRIPTION
612  *
613  *    Performs lookups for local name and IP address. This peforms reverse
614  *    lookup as well to verify that the IP has FQDN.
615  *
616  ***/
617 SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,
618                                       char **ip);
619
620 /****f* silcutil/SilcNetAPI/silc_net_get_remote_port
621  *
622  * SYNOPSIS
623  *
624  *    SilcUInt16 silc_net_get_remote_port(SilcSocket sock);
625  *
626  * DESCRIPTION
627  *
628  *    Return remote port by socket.
629  *
630  ***/
631 SilcUInt16 silc_net_get_remote_port(SilcSocket sock);
632
633 /****f* silcutil/SilcNetAPI/silc_net_get_local_port
634  *
635  * SYNOPSIS
636  *
637  *    SilcUInt16 silc_net_get_local_port(SilcSocket sock);
638  *
639  * DESCRIPTION
640  *
641  *    Return local port by socket.
642  *
643  ***/
644 SilcUInt16 silc_net_get_local_port(SilcSocket sock);
645
646 /****f* silcutil/SilcNetAPI/silc_net_localhost
647  *
648  * SYNOPSIS
649  *
650  *    char *silc_net_localhost(void);
651  *
652  * DESCRIPTION
653  *
654  *    Return name of localhost.  This will also attempt to resolve
655  *    the real hostname by the local host's IP address.  If unsuccessful
656  *    the first found hostname is returned.  The caller must free
657  *    returned hostname.
658  *
659  ***/
660 char *silc_net_localhost(void);
661
662 /****f* silcutil/SilcNetAPI/silc_net_localip
663  *
664  * SYNOPSIS
665  *
666  *    char *silc_net_localip(void)
667  *
668  * DESCRIPTION
669  *
670  *    Return IP of localhost.  The caller must free the returned IP.
671  *
672  ***/
673 char *silc_net_localip(void);
674
675 #include "silcnet_i.h"
676
677 #endif /* SILCNET_H */