Added SILC Local Network Stream API
[runtime.git] / lib / silcutil / silclocalnetstream.c
1 /*
2
3   silclocalnetstream.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2008 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 <silcruntime.h>
21
22 /************************** Types and definitions ***************************/
23
24 /* Local net listener context */
25 typedef struct {
26   SilcNetListener listener;
27   char *filepath;
28   SilcNetCallback callback;
29   void *context;
30 } *SilcLocalNetListener;
31
32 /************************ Static utility functions **************************/
33
34 /* Connection accept callback */
35
36 static void silc_local_net_accept(SilcResult result, SilcStream stream,
37                                   void *context)
38 {
39   SilcLocalNetListener listener = context;
40   const char *remote_ip;
41
42   if (!silc_socket_stream_get_info(stream, NULL, NULL, &remote_ip, NULL)) {
43     silc_stream_destroy(stream);
44     return;
45   }
46
47   /* Make sure the connection comes from local host */
48   if (strcmp(remote_ip, "127.0.0.1")) {
49     SILC_LOG_DEBUG(("Connection is coming from %s, will not accept",
50                     remote_ip));
51     silc_stream_destroy(stream);
52     return;
53   }
54
55   listener->callback(result, stream, listener->context);
56 }
57
58 /****************************** Public API **********************************/
59
60 /* Create listener */
61
62 SilcNetListener silc_local_net_create_listener(const char *filepath,
63                                                SilcSchedule schedule,
64                                                SilcNetCallback callback,
65                                                void *context)
66 {
67   SilcLocalNetListener listener;
68   SilcUInt16 *local_port;
69   const char *addr = "127.0.0.1";
70   char port[8];
71
72   SILC_LOG_DEBUG(("Creating local network stream listener %s", filepath));
73
74   if (!filepath || !callback) {
75     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
76     return NULL;
77   }
78
79   /* Make sure file doesn't exist */
80   if (silc_file_stat(filepath, FALSE, NULL)) {
81     silc_set_errno(SILC_ERR_ALREADY_EXISTS);
82     return NULL;
83   }
84
85   listener = silc_calloc(1, sizeof(*listener));
86   if (!listener)
87     return NULL;
88   listener->callback = callback;
89   listener->context = context;
90
91   listener->filepath = silc_strdup(filepath);
92   if (!listener->filepath) {
93     silc_free(listener);
94     return NULL;
95   }
96
97   /* Create local TCP listener */
98   listener->listener =
99     silc_net_tcp_create_listener(&addr, 1, 0, TRUE, FALSE, schedule,
100                                  silc_local_net_accept, listener);
101   if (!listener) {
102     silc_free(listener);
103     return NULL;
104   }
105
106   /* Get the bound port */
107   local_port = silc_net_listener_get_port(listener->listener, NULL);
108   if (!local_port) {
109     silc_net_close_listener(listener->listener);
110     silc_free(listener);
111     return NULL;
112   }
113
114   /* Create the file */
115   silc_snprintf(port, sizeof(port), "%d", *local_port);
116   if (silc_file_writefile(filepath, port, strlen(port) + 1)) {
117     silc_free(local_port);
118     silc_net_close_listener(listener->listener);
119     silc_free(listener);
120     return NULL;
121   }
122
123   SILC_LOG_DEBUG(("Created local network stream listener %p", listener));
124
125   silc_free(local_port);
126
127   return (SilcNetListener)listener;
128 }
129
130 /* Close listener */
131
132 void silc_local_net_close_listener(SilcNetListener local_listener)
133 {
134   SilcLocalNetListener listener = (SilcLocalNetListener)local_listener;
135
136   SILC_LOG_DEBUG(("Closing local network stream listener %p, %s",
137                   listener, listener->filepath));
138
139   unlink(listener->filepath);
140   silc_net_close_listener(listener->listener);
141   silc_free(listener);
142 }
143
144 /* Connect to the local network listener */
145
146 SilcAsyncOperation silc_local_net_connect(const char *filepath,
147                                           SilcSchedule schedule,
148                                           SilcNetCallback callback,
149                                           void *context)
150 {
151   unsigned char *port_data;
152   int port;
153
154   SILC_LOG_DEBUG(("Connecting to local network listner %s", filepath));
155
156   if (!filepath) {
157     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
158     if (callback)
159       callback(silc_errno, NULL, context);
160     return NULL;
161   }
162
163   /* Read the port from file */
164   port_data = silc_file_readfile(filepath, NULL, NULL);
165   if (!port_data) {
166     if (callback)
167       callback(silc_errno, NULL, context);
168     return NULL;
169   }
170   port = atoi(port_data);
171
172   silc_free(port_data);
173
174   /* Connect */
175   return silc_net_tcp_connect("127.0.0.1", "127.0.0.1", port, schedule,
176                               callback, context);
177 }