Added SilcLocalNetSecurity flags for Local Net Stream Listener.
[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                                                SilcLocalNetSecurity security,
64                                                SilcSchedule schedule,
65                                                SilcNetCallback callback,
66                                                void *context)
67 {
68   SilcLocalNetListener listener;
69   SilcUInt16 *local_port;
70   const char *addr = "127.0.0.1";
71   char port[8];
72   int mode = 0;
73
74   SILC_LOG_DEBUG(("Creating local network stream listener %s", filepath));
75
76   if (!filepath || !callback) {
77     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
78     return NULL;
79   }
80
81   /* Make sure file doesn't exist */
82   if (silc_file_stat(filepath, FALSE, NULL)) {
83     silc_set_errno(SILC_ERR_ALREADY_EXISTS);
84     return NULL;
85   }
86
87   listener = silc_calloc(1, sizeof(*listener));
88   if (!listener)
89     return NULL;
90   listener->callback = callback;
91   listener->context = context;
92
93   listener->filepath = silc_strdup(filepath);
94   if (!listener->filepath) {
95     silc_free(listener);
96     return NULL;
97   }
98
99   /* Create local TCP listener */
100   listener->listener =
101     silc_net_tcp_create_listener(&addr, 1, 0, TRUE, FALSE, schedule,
102                                  silc_local_net_accept, listener);
103   if (!listener) {
104     silc_free(listener);
105     return NULL;
106   }
107
108   /* Get the bound port */
109   local_port = silc_net_listener_get_port(listener->listener, NULL);
110   if (!local_port) {
111     silc_net_close_listener(listener->listener);
112     silc_free(listener);
113     return NULL;
114   }
115
116   /* Set mode */
117   if (!security)
118     mode = 0644;
119   if (security & SILC_LOCAL_NET_USER)
120     mode = 0600;
121   if (security & SILC_LOCAL_NET_GROUP)
122     mode += 040;
123
124   /* Create the file */
125   silc_snprintf(port, sizeof(port), "%d", *local_port);
126   if (silc_file_writefile_mode(filepath, port, strlen(port) + 1, mode)) {
127     silc_free(local_port);
128     silc_net_close_listener(listener->listener);
129     silc_free(listener);
130     return NULL;
131   }
132
133   SILC_LOG_DEBUG(("Created local network stream listener %p", listener));
134
135   silc_free(local_port);
136
137   return (SilcNetListener)listener;
138 }
139
140 /* Close listener */
141
142 void silc_local_net_close_listener(SilcNetListener local_listener)
143 {
144   SilcLocalNetListener listener = (SilcLocalNetListener)local_listener;
145
146   SILC_LOG_DEBUG(("Closing local network stream listener %p, %s",
147                   listener, listener->filepath));
148
149   unlink(listener->filepath);
150   silc_net_close_listener(listener->listener);
151   silc_free(listener->filepath);
152   silc_free(listener);
153 }
154
155 /* Connect to the local network listener */
156
157 SilcAsyncOperation silc_local_net_connect(const char *filepath,
158                                           SilcSchedule schedule,
159                                           SilcNetCallback callback,
160                                           void *context)
161 {
162   unsigned char *port_data;
163   int port;
164
165   SILC_LOG_DEBUG(("Connecting to local network listner %s", filepath));
166
167   if (!filepath) {
168     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
169     if (callback)
170       callback(silc_errno, NULL, context);
171     return NULL;
172   }
173
174   /* Read the port from file */
175   port_data = silc_file_readfile(filepath, NULL, NULL);
176   if (!port_data) {
177     if (callback)
178       callback(silc_errno, NULL, context);
179     return NULL;
180   }
181   port = atoi(port_data);
182
183   silc_free(port_data);
184
185   /* Connect */
186   return silc_net_tcp_connect("127.0.0.1", "127.0.0.1", port, schedule,
187                               callback, context);
188 }