Skip to content
Newer
Older
100644 333 lines (251 sloc) 8.86 KB
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
1 /* Copyright (c) 2010, Michael Santos <michael.santos@gmail.com>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of the author nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include "erl_nif.h"
33 #include "ancillary.h"
34 #include "procket.h"
35
00214e3 @msantos Make the NIF stateless!
authored
36 #define BACKLOG 5
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
37
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
38 static ERL_NIF_TERM error_tuple(ErlNifEnv *env, char *err);
39 static ERL_NIF_TERM error_message(ErlNifEnv *env, char *err, char *msg);
40
41 static ERL_NIF_TERM atom_ok;
42 static ERL_NIF_TERM atom_error;
43 static ERL_NIF_TERM atom_nodata;
44
45
46 static int
47 load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
48 {
49 atom_ok = enif_make_atom(env, "ok");
50 atom_error = enif_make_atom(env, "error");
51 atom_nodata = enif_make_atom(env, "nodata");
52
53 return (0);
54 }
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
55
56
57 static ERL_NIF_TERM
953b601 @msantos Remove spurious and paranoid errno checks
authored
58 nif_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
59 {
00214e3 @msantos Make the NIF stateless!
authored
60 int sock_fd = -1;
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
61 struct sockaddr_un sa = { 0 };
62 int flags = 0;
63
64
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
65 if (enif_get_string(env, argv[0], sa.sun_path, sizeof(sa.sun_path), ERL_NIF_LATIN1) < 1)
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
66 return enif_make_badarg(env);
67
68 sa.sun_family = PF_LOCAL;
69
00214e3 @msantos Make the NIF stateless!
authored
70 sock_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
71 if (sock_fd < 0)
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
72 return error_message(env, "socket", strerror(errno));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
73
00214e3 @msantos Make the NIF stateless!
authored
74 flags = fcntl(sock_fd, F_GETFL, 0);
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
75 flags |= O_NONBLOCK;
00214e3 @msantos Make the NIF stateless!
authored
76 (void)fcntl(sock_fd, F_SETFL, flags);
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
77
00214e3 @msantos Make the NIF stateless!
authored
78 if (bind(sock_fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
79 return error_message(env, "bind", strerror(errno));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
80
00214e3 @msantos Make the NIF stateless!
authored
81 if (listen(sock_fd, BACKLOG) < 0)
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
82 return error_message(env, "listen", strerror(errno));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
83
00214e3 @msantos Make the NIF stateless!
authored
84 return enif_make_tuple(env, 2,
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
85 atom_ok,
00214e3 @msantos Make the NIF stateless!
authored
86 enif_make_int(env, sock_fd));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
87 }
88
89
90 static ERL_NIF_TERM
953b601 @msantos Remove spurious and paranoid errno checks
authored
91 nif_poll(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
92 {
00214e3 @msantos Make the NIF stateless!
authored
93 int sock_fd = -1; /* listening socket */
94 int fd = -1; /* connected socket */
95 int s = -1; /* socket received from pipe */
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
96 struct sockaddr_un sa = { 0 };
97 socklen_t socklen = 0;
98
99
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
100 if (!enif_get_int(env, argv[0], &sock_fd))
00214e3 @msantos Make the NIF stateless!
authored
101 return enif_make_badarg(env);
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
102
00214e3 @msantos Make the NIF stateless!
authored
103 fd = accept(sock_fd, (struct sockaddr *)&sa, &socklen);
104 if (fd < 0)
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
105 return error_message(env, "accept", strerror(errno));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
106
00214e3 @msantos Make the NIF stateless!
authored
107 if (ancil_recv_fd(fd, &s) < 0) {
108 (void)close (fd);
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
109 return error_message(env, "recvmsg", strerror(errno));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
110 }
111
00214e3 @msantos Make the NIF stateless!
authored
112 (void)close (fd);
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
113
114 return enif_make_tuple(env, 2,
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
115 atom_ok,
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
116 enif_make_int(env, s));
117 }
118
119
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
120 /* 0: path to socket
121 * 1: file descriptor
122 */
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
123 static ERL_NIF_TERM
953b601 @msantos Remove spurious and paranoid errno checks
authored
124 nif_close(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
125 {
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
126 struct sockaddr_un sa = { 0 };
00214e3 @msantos Make the NIF stateless!
authored
127 int sockfd = -1;
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
128
129
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
130 if (enif_get_string(env, argv[0], sa.sun_path, sizeof(sa.sun_path), ERL_NIF_LATIN1) < 1)
00214e3 @msantos Make the NIF stateless!
authored
131 return enif_make_badarg(env);
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
132
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
133 if (!enif_get_int(env, argv[1], &sockfd))
00214e3 @msantos Make the NIF stateless!
authored
134 return enif_make_badarg(env);
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
135
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
136 if (unlink(sa.sun_path) < 0)
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
137 return error_message(env, "unlink", strerror(errno));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
138
00214e3 @msantos Make the NIF stateless!
authored
139 (void)close(sockfd);
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
140
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
141 return atom_ok;
142 }
143
144
145 /* 0: socket, 1: length */
146 static ERL_NIF_TERM
147 nif_recvfrom(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
148 {
149 int sockfd = -1;
150 int len = 0;
50f5494 @msantos Return only the part of the buffer used for holding the packet
authored
151 ssize_t bufsz = 0;
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
152 ErlNifBinary buf;
153
154 if (!enif_get_int(env, argv[0], &sockfd))
155 return enif_make_badarg(env);
156 if (!enif_get_int(env, argv[1], &len))
157 return enif_make_badarg(env);
158
b71aa6d @msantos Update NIF for R14A
authored
159 if (!enif_alloc_binary(len, &buf))
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
160 return error_tuple(env, "out_of_memory");
161
50f5494 @msantos Return only the part of the buffer used for holding the packet
authored
162 if ( (bufsz = recvfrom(sockfd, buf.data, buf.size, 0, NULL, NULL)) == -1) {
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
163 switch (errno) {
164 case EAGAIN:
165 case EINTR:
dc2cb0d @msantos Now with (fewer) memory leaks!
authored
166 enif_release_binary(&buf);
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
167 return atom_nodata;
168 default:
dc2cb0d @msantos Now with (fewer) memory leaks!
authored
169 enif_release_binary(&buf);
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
170 return error_tuple(env, strerror(errno));
171 }
172 }
173
50f5494 @msantos Return only the part of the buffer used for holding the packet
authored
174 if (bufsz != buf.size)
b71aa6d @msantos Update NIF for R14A
authored
175 enif_realloc_binary(&buf, bufsz);
50f5494 @msantos Return only the part of the buffer used for holding the packet
authored
176
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
177 return enif_make_tuple(env, 2,
178 atom_ok,
179 enif_make_binary(env, &buf));
180 }
181
182
74a854e @msantos Add sendto/4 and bind/2
authored
183 /* 0: socket, 1: buffer, 2: flags, 3: struct sockaddr */
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
184 static ERL_NIF_TERM
185 nif_sendto(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
186 {
187 int sockfd = -1;
188 int flags = 0;
189
190 ErlNifBinary buf;
74a854e @msantos Add sendto/4 and bind/2
authored
191 ErlNifBinary sa;
192
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
193
194 if (!enif_get_int(env, argv[0], &sockfd))
195 return enif_make_badarg(env);
196
74a854e @msantos Add sendto/4 and bind/2
authored
197 if (!enif_inspect_binary(env, argv[1], &buf))
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
198 return enif_make_badarg(env);
199
200 if (!enif_get_int(env, argv[2], &flags))
201 return enif_make_badarg(env);
202
74a854e @msantos Add sendto/4 and bind/2
authored
203 if (!enif_inspect_binary(env, argv[3], &sa))
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
204 return enif_make_badarg(env);
205
74a854e @msantos Add sendto/4 and bind/2
authored
206 if (sendto(sockfd, buf.data, buf.size, flags, (struct sockaddr *)sa.data, sa.size) == -1)
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
207 return enif_make_tuple(env, 2,
208 atom_error,
209 enif_make_tuple(env, 2,
210 enif_make_int(env, errno),
211 enif_make_string(env, strerror(errno), ERL_NIF_LATIN1)));
212
213 return atom_ok;
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
214 }
215
216
74a854e @msantos Add sendto/4 and bind/2
authored
217 /* 0: socket descriptor, 1: struct sockaddr */
218 static ERL_NIF_TERM
219 nif_bind(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
220 {
221 int s = -1;
222 ErlNifBinary sa;
223
224
225 if (!enif_get_int(env, argv[0], &s))
226 return enif_make_badarg(env);
227
228 if (!enif_inspect_binary(env, argv[1], &sa))
229 return enif_make_badarg(env);
230
231 if (bind(s, (struct sockaddr *)sa.data, sa.size) < 0)
232 return error_tuple(env, strerror(errno));
233
234 return atom_ok;
235 }
236
65a61dc @msantos Add an NIF interface to ioctl()
authored
237 /* 0: (int)socket descriptor, 1: (int)device dependent request,
238 * 2: (char *)argp, pointer to structure
239 */
240 static ERL_NIF_TERM
241 nif_ioctl(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
242 {
243 int s = -1;
244 int req = 0;
245 ErlNifBinary ifr;
246
247
248 if (!enif_get_int(env, argv[0], &s))
249 return enif_make_badarg(env);
250
251 if (!enif_get_int(env, argv[1], &req))
252 return enif_make_badarg(env);
253
254 if (!enif_inspect_binary(env, argv[2], &ifr))
255 return enif_make_badarg(env);
256
b71aa6d @msantos Update NIF for R14A
authored
257 if (!enif_realloc_binary(&ifr, ifr.size))
65a61dc @msantos Add an NIF interface to ioctl()
authored
258 return enif_make_badarg(env);
259
260 if (ioctl(s, req, ifr.data) < 0)
261 return error_tuple(env, strerror(errno));
262
263 return enif_make_tuple(env, 2,
264 atom_ok,
265 enif_make_binary(env, &ifr));
266 }
267
74a854e @msantos Add sendto/4 and bind/2
authored
268
3649b5c @msantos Add an NIF setsockopt for promiscous mode
authored
269 /* 0: int socket descriptor, 1: int level,
270 * 2: int optname, 3: void *optval
271 */
272 static ERL_NIF_TERM
273 nif_setsockopt(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
274 {
275 int s = -1;
276 int level = 0;
277 int name = 0;
278 ErlNifBinary val;
279
280 if (!enif_get_int(env, argv[0], &s))
281 return enif_make_badarg(env);
282
283 if (!enif_get_int(env, argv[1], &level))
284 return enif_make_badarg(env);
285
286 if (!enif_get_int(env, argv[2], &name))
287 return enif_make_badarg(env);
288
289 if (!enif_inspect_binary(env, argv[3], &val))
290 return enif_make_badarg(env);
291
292 if (setsockopt(s, level, name, (void *)val.data, val.size) < 0)
293 return error_tuple(env, strerror(errno));
294
295 return atom_ok;
296 }
297
298
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
299 static ERL_NIF_TERM
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
300 error_tuple(ErlNifEnv *env, char *err)
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
301 {
302 return enif_make_tuple(env, 2,
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
303 atom_error,
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
304 enif_make_atom(env, err));
305 }
306
307
308 static ERL_NIF_TERM
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
309 error_message(ErlNifEnv *env, char *err, char *msg)
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
310 {
6a15ed0 @msantos Return a tuple instead of a 3 element tuple. Consistency is good.
authored
311 return enif_make_tuple(env, 2,
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
312 atom_error,
6a15ed0 @msantos Return a tuple instead of a 3 element tuple. Consistency is good.
authored
313 enif_make_tuple(env, 2,
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
314 enif_make_atom(env, err),
ea8f4ff @msantos Changes for the R13B04 nif interface.
authored
315 enif_make_string(env, msg, ERL_NIF_LATIN1)));
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
316 }
317
318
319 static ErlNifFunc nif_funcs[] = {
953b601 @msantos Remove spurious and paranoid errno checks
authored
320 {"open", 1, nif_open},
321 {"poll", 1, nif_poll},
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
322 {"close", 2, nif_close},
74a854e @msantos Add sendto/4 and bind/2
authored
323 {"bind", 2, nif_bind},
324 {"recvfrom", 2, nif_recvfrom},
65a61dc @msantos Add an NIF interface to ioctl()
authored
325 {"ioctl", 3, nif_ioctl},
3649b5c @msantos Add an NIF setsockopt for promiscous mode
authored
326 {"sendto", 4, nif_sendto},
327 {"setsockopt", 4, nif_setsockopt}
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
328 };
329
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
330 ERL_NIF_INIT(procket, nif_funcs, load, NULL, NULL, NULL)
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
331
332
Something went wrong with that request. Please try again.