fdpass 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +35 -0
- data/ext/extconf.rb +3 -0
- data/ext/fdpass.c +25 -0
- data/ext/fdpass.h +26 -0
- data/ext/fdpass_client.c +88 -0
- data/ext/fdpass_server.c +81 -0
- data/ext/fdpass_socket.c +64 -0
- data/ext/fdpass_socket.h +24 -0
- metadata +74 -0
data/README
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
= Libarchive/Ruby
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
This is a library to transmit the file descriptor between the processes.
|
6
|
+
|
7
|
+
== Example
|
8
|
+
=== Server (Reciever)
|
9
|
+
require 'fdpass'
|
10
|
+
|
11
|
+
begin
|
12
|
+
fdpass = FDPass.server('/tmp/fdpass.sock')
|
13
|
+
|
14
|
+
t = Thread.fork {
|
15
|
+
loop do
|
16
|
+
fd = fdpass.recv
|
17
|
+
io = IO.open(fd)
|
18
|
+
io.puts('%s: %s' % [fd, __FILE__])
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
t.join
|
23
|
+
ensure
|
24
|
+
fdpass.close
|
25
|
+
end
|
26
|
+
|
27
|
+
== Client (Sender)
|
28
|
+
require 'fdpass'
|
29
|
+
|
30
|
+
begin
|
31
|
+
fdpass = FDPass.client('/tmp/fdpass.sock')
|
32
|
+
fdpass.send($stderr.fileno)
|
33
|
+
ensure
|
34
|
+
fdpass.close if fdpass.closed?
|
35
|
+
end
|
data/ext/extconf.rb
ADDED
data/ext/fdpass.c
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#include "fdpass.h"
|
2
|
+
|
3
|
+
VALUE rb_mFDPass;
|
4
|
+
VALUE rb_eFDPassError;
|
5
|
+
extern VALUE rb_cFDPassServer;
|
6
|
+
extern VALUE rb_cFDPassClient;
|
7
|
+
|
8
|
+
static VALUE rb_fdpass_server(VALUE self, VALUE path) {
|
9
|
+
return rb_funcall(rb_cFDPassServer, rb_intern("new"), 1, path);
|
10
|
+
}
|
11
|
+
|
12
|
+
static VALUE rb_fdpass_client(VALUE self, VALUE path) {
|
13
|
+
return rb_funcall(rb_cFDPassClient, rb_intern("new"), 1, path);
|
14
|
+
}
|
15
|
+
|
16
|
+
void Init_fdpass() {
|
17
|
+
rb_mFDPass = rb_define_module("FDPass");
|
18
|
+
rb_define_module_function(rb_mFDPass, "server", rb_fdpass_server, 1);
|
19
|
+
rb_define_module_function(rb_mFDPass, "client", rb_fdpass_client, 1);
|
20
|
+
|
21
|
+
rb_eFDPassError = rb_define_class_under(rb_mFDPass, "Error", rb_eStandardError);
|
22
|
+
|
23
|
+
Init_fdpass_server();
|
24
|
+
Init_fdpass_client();
|
25
|
+
}
|
data/ext/fdpass.h
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#ifndef __FDPASS_H__
|
2
|
+
#define __FDPASS_C__
|
3
|
+
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
#include <sys/socket.h>
|
7
|
+
#include <sys/un.h>
|
8
|
+
#include <sys/types.h>
|
9
|
+
#include <sys/stat.h>
|
10
|
+
#include <unistd.h>
|
11
|
+
|
12
|
+
#include <errno.h>
|
13
|
+
|
14
|
+
#include <ruby.h>
|
15
|
+
|
16
|
+
#ifndef RSTRING_PTR
|
17
|
+
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
18
|
+
#endif
|
19
|
+
#ifndef RSTRING_LEN
|
20
|
+
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
21
|
+
#endif
|
22
|
+
|
23
|
+
void Init_fdpass_server();
|
24
|
+
void Init_fdpass_client();
|
25
|
+
|
26
|
+
#endif // __FDPASS_H__
|
data/ext/fdpass_client.c
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
#include "fdpass.h"
|
2
|
+
#include "fdpass_socket.h"
|
3
|
+
|
4
|
+
extern VALUE rb_mFDPass;
|
5
|
+
extern VALUE rb_eFDPassError;
|
6
|
+
VALUE rb_cFDPassClient;
|
7
|
+
|
8
|
+
static VALUE rd_fdpass_client_initialize(VALUE self, VALUE path) {
|
9
|
+
struct fdpass_socket *p;
|
10
|
+
char *cpath;
|
11
|
+
int sock;
|
12
|
+
struct sockaddr_un addr;
|
13
|
+
|
14
|
+
Data_Get_Struct(self, struct fdpass_socket, p);
|
15
|
+
|
16
|
+
Check_Type(path, T_STRING);
|
17
|
+
cpath = RSTRING_PTR(path);
|
18
|
+
|
19
|
+
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
20
|
+
|
21
|
+
if (sock < 0) {
|
22
|
+
rb_raise(rb_eFDPassError, "%s", strerror(errno));
|
23
|
+
}
|
24
|
+
|
25
|
+
memset(&addr, 0, sizeof(addr));
|
26
|
+
addr.sun_family = AF_UNIX;
|
27
|
+
strncpy(addr.sun_path, cpath, sizeof(addr.sun_path) - 1);
|
28
|
+
addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
|
29
|
+
|
30
|
+
if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
31
|
+
rb_raise(rb_eFDPassError, "%s", strerror(errno));
|
32
|
+
}
|
33
|
+
|
34
|
+
p->sock = sock;
|
35
|
+
p->closed = 0;
|
36
|
+
p->path = path;
|
37
|
+
p->is_server = 0;
|
38
|
+
|
39
|
+
return Qnil;
|
40
|
+
}
|
41
|
+
|
42
|
+
static VALUE rb_fdpass_client_send(VALUE self, VALUE fd) {
|
43
|
+
struct fdpass_socket *p;
|
44
|
+
struct msghdr msg = { 0 };
|
45
|
+
struct cmsghdr *cmsg;
|
46
|
+
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
47
|
+
int ifd, *cmsg_data;
|
48
|
+
struct iovec iov;
|
49
|
+
|
50
|
+
ifd = NUM2INT(fd);
|
51
|
+
|
52
|
+
Data_Get_Struct(self, struct fdpass_socket, p);
|
53
|
+
Check_Socket(p);
|
54
|
+
|
55
|
+
iov.iov_base = "\0";
|
56
|
+
iov.iov_len = 1;
|
57
|
+
|
58
|
+
msg.msg_name = NULL;
|
59
|
+
msg.msg_namelen = 0;
|
60
|
+
msg.msg_iov = &iov;
|
61
|
+
msg.msg_iovlen = 1;
|
62
|
+
msg.msg_control = cmsgbuf;
|
63
|
+
msg.msg_controllen = sizeof(cmsgbuf);
|
64
|
+
|
65
|
+
cmsg = CMSG_FIRSTHDR(&msg);
|
66
|
+
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
67
|
+
cmsg->cmsg_level = SOL_SOCKET;
|
68
|
+
cmsg->cmsg_type = SCM_RIGHTS;
|
69
|
+
|
70
|
+
cmsg_data = (int *) CMSG_DATA(cmsg);
|
71
|
+
*cmsg_data = ifd;
|
72
|
+
msg.msg_controllen = cmsg->cmsg_len;
|
73
|
+
|
74
|
+
if (sendmsg(p->sock, &msg, 0) < 0) {
|
75
|
+
rb_raise(rb_eFDPassError, "%s", strerror(errno));
|
76
|
+
}
|
77
|
+
|
78
|
+
return Qnil;
|
79
|
+
}
|
80
|
+
|
81
|
+
void Init_fdpass_client() {
|
82
|
+
rb_cFDPassClient = rb_define_class_under(rb_mFDPass, "Client", rb_cObject);
|
83
|
+
rb_define_alloc_func(rb_cFDPassClient, fdpass_socket_alloc);
|
84
|
+
rb_define_private_method(rb_cFDPassClient, "initialize", rd_fdpass_client_initialize, 1);
|
85
|
+
rb_define_method(rb_cFDPassClient, "close", rd_fdpass_socket_close, 0);
|
86
|
+
rb_define_method(rb_cFDPassClient, "closed?", rd_fdpass_socket_is_closed, 0);
|
87
|
+
rb_define_method(rb_cFDPassClient, "send", rb_fdpass_client_send, 1);
|
88
|
+
}
|
data/ext/fdpass_server.c
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#include "fdpass.h"
|
2
|
+
#include "fdpass_socket.h"
|
3
|
+
|
4
|
+
extern VALUE rb_mFDPass;
|
5
|
+
extern VALUE rb_eFDPassError;
|
6
|
+
VALUE rb_cFDPassServer;
|
7
|
+
|
8
|
+
static VALUE rd_fdpass_server_initialize(VALUE self, VALUE path) {
|
9
|
+
struct fdpass_socket *p;
|
10
|
+
char *cpath;
|
11
|
+
int sock;
|
12
|
+
struct sockaddr_un addr;
|
13
|
+
|
14
|
+
Data_Get_Struct(self, struct fdpass_socket, p);
|
15
|
+
|
16
|
+
Check_Type(path, T_STRING);
|
17
|
+
cpath = RSTRING_PTR(path);
|
18
|
+
|
19
|
+
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
20
|
+
|
21
|
+
if (sock < 0) {
|
22
|
+
rb_raise(rb_eFDPassError, "%s", strerror(errno));
|
23
|
+
}
|
24
|
+
|
25
|
+
memset(&addr, 0, sizeof(addr));
|
26
|
+
addr.sun_family = AF_UNIX;
|
27
|
+
strncpy(addr.sun_path, cpath, sizeof(addr.sun_path) - 1);
|
28
|
+
addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
|
29
|
+
|
30
|
+
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
31
|
+
rb_raise(rb_eFDPassError, "%s", strerror(errno));
|
32
|
+
}
|
33
|
+
|
34
|
+
p->sock = sock;
|
35
|
+
p->closed = 0;
|
36
|
+
p->path = path;
|
37
|
+
p->is_server = 1;
|
38
|
+
|
39
|
+
return Qnil;
|
40
|
+
}
|
41
|
+
|
42
|
+
static VALUE rb_fdpass_server_recv(VALUE self) {
|
43
|
+
struct fdpass_socket *p;
|
44
|
+
struct msghdr msg = { 0 };
|
45
|
+
struct cmsghdr *cmsg;
|
46
|
+
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
47
|
+
int *cmsg_data;
|
48
|
+
struct iovec iov;
|
49
|
+
char iov_data[1];
|
50
|
+
|
51
|
+
Data_Get_Struct(self, struct fdpass_socket, p);
|
52
|
+
Check_Socket(p);
|
53
|
+
|
54
|
+
iov.iov_base = iov_data;
|
55
|
+
iov.iov_len = sizeof(iov_data);
|
56
|
+
|
57
|
+
msg.msg_name = NULL;
|
58
|
+
msg.msg_namelen = 0;
|
59
|
+
msg.msg_iov = &iov;
|
60
|
+
msg.msg_iovlen = 1;
|
61
|
+
msg.msg_control = cmsgbuf;
|
62
|
+
msg.msg_controllen = sizeof(cmsgbuf);
|
63
|
+
|
64
|
+
if (recvmsg(p->sock, &msg, MSG_WAITALL) < 0) {
|
65
|
+
rb_raise(rb_eFDPassError, "%s", strerror(errno));
|
66
|
+
}
|
67
|
+
|
68
|
+
cmsg = CMSG_FIRSTHDR(&msg);
|
69
|
+
cmsg_data = (int *) CMSG_DATA(cmsg);
|
70
|
+
|
71
|
+
return INT2NUM(*cmsg_data);
|
72
|
+
}
|
73
|
+
|
74
|
+
void Init_fdpass_server() {
|
75
|
+
rb_cFDPassServer = rb_define_class_under(rb_mFDPass, "Server", rb_cObject);
|
76
|
+
rb_define_alloc_func(rb_cFDPassServer, fdpass_socket_alloc);
|
77
|
+
rb_define_private_method(rb_cFDPassServer, "initialize", rd_fdpass_server_initialize, 1);
|
78
|
+
rb_define_method(rb_cFDPassServer, "close", rd_fdpass_socket_close, 0);
|
79
|
+
rb_define_method(rb_cFDPassServer, "closed?", rd_fdpass_socket_is_closed, 0);
|
80
|
+
rb_define_method(rb_cFDPassServer, "recv", rb_fdpass_server_recv, 0);
|
81
|
+
}
|
data/ext/fdpass_socket.c
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#include "fdpass_socket.h"
|
2
|
+
|
3
|
+
extern VALUE rb_eFDPassError;
|
4
|
+
|
5
|
+
static void unlink_socket(struct fdpass_socket *p) {
|
6
|
+
#ifdef S_ISSOCK
|
7
|
+
char *cpath;
|
8
|
+
struct stat st;
|
9
|
+
|
10
|
+
if (!p->is_server || NIL_P(p->path)) {
|
11
|
+
return;
|
12
|
+
}
|
13
|
+
|
14
|
+
Check_Type(p->path, T_STRING);
|
15
|
+
cpath = RSTRING_PTR(p->path);
|
16
|
+
|
17
|
+
if (stat(cpath, &st) == 0 && S_ISSOCK(st.st_mode)) {
|
18
|
+
unlink(cpath);
|
19
|
+
}
|
20
|
+
#endif
|
21
|
+
}
|
22
|
+
|
23
|
+
static void fdpass_socket_mark(struct fdpass_socket *p) {
|
24
|
+
rb_gc_mark(p->path);
|
25
|
+
}
|
26
|
+
|
27
|
+
static void fdpass_socket_free(struct fdpass_socket *p) {
|
28
|
+
if (!p->closed) {
|
29
|
+
close(p->sock);
|
30
|
+
unlink_socket(p);
|
31
|
+
}
|
32
|
+
|
33
|
+
xfree(p);
|
34
|
+
}
|
35
|
+
|
36
|
+
VALUE fdpass_socket_alloc(VALUE klass) {
|
37
|
+
struct fdpass_socket *p = ALLOC(struct fdpass_socket);
|
38
|
+
p->sock = -1;
|
39
|
+
p->closed = 1;
|
40
|
+
p->path = Qnil;
|
41
|
+
return Data_Wrap_Struct(klass, fdpass_socket_mark, fdpass_socket_free, p);
|
42
|
+
}
|
43
|
+
|
44
|
+
VALUE rd_fdpass_socket_close(VALUE self) {
|
45
|
+
struct fdpass_socket *p;
|
46
|
+
|
47
|
+
Data_Get_Struct(self, struct fdpass_socket, p);
|
48
|
+
|
49
|
+
if (!p->closed) {
|
50
|
+
close(p->sock);
|
51
|
+
unlink_socket(p);
|
52
|
+
p->sock = -1;
|
53
|
+
p->closed = 1;
|
54
|
+
p->path = Qnil;
|
55
|
+
}
|
56
|
+
|
57
|
+
return Qnil;
|
58
|
+
}
|
59
|
+
|
60
|
+
VALUE rd_fdpass_socket_is_closed(VALUE self) {
|
61
|
+
struct fdpass_socket *p;
|
62
|
+
Data_Get_Struct(self, struct fdpass_socket, p);
|
63
|
+
return p->closed ? Qtrue : Qfalse;
|
64
|
+
}
|
data/ext/fdpass_socket.h
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#ifndef __FDPASS_SOCKET_H__
|
2
|
+
#define __FDPASS_SOCKET_C__
|
3
|
+
|
4
|
+
#include "fdpass.h"
|
5
|
+
|
6
|
+
struct fdpass_socket {
|
7
|
+
int sock;
|
8
|
+
int closed;
|
9
|
+
VALUE path;
|
10
|
+
int is_server;
|
11
|
+
};
|
12
|
+
|
13
|
+
#define Check_Socket(p) do { \
|
14
|
+
if ((p)->sock < 0 || (p)->closed || NIL_P((p)->path)) { \
|
15
|
+
rb_raise(rb_eFDPassError, "Invalid socket"); \
|
16
|
+
} \
|
17
|
+
Check_Type((p)->path, T_STRING); \
|
18
|
+
} while(0)
|
19
|
+
|
20
|
+
VALUE fdpass_socket_alloc(VALUE klass);
|
21
|
+
VALUE rd_fdpass_socket_close(VALUE self);
|
22
|
+
VALUE rd_fdpass_socket_is_closed(VALUE self);
|
23
|
+
|
24
|
+
#endif // __FDPASS_SOCKET_H__
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fdpass
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- winebarrel
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-01 00:00:00 +09:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email: sgwr_dts@yahoo.co.jp
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions:
|
27
|
+
- ext/extconf.rb
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- ext/fdpass.c
|
32
|
+
- ext/fdpass_client.c
|
33
|
+
- ext/fdpass_server.c
|
34
|
+
- ext/fdpass_socket.c
|
35
|
+
- ext/fdpass.h
|
36
|
+
- ext/fdpass_socket.h
|
37
|
+
- ext/extconf.rb
|
38
|
+
- README
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: https://github.com/winebarrel/fdpass
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
hash: 3
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 3
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.3.7
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: This is a library to transmit the file descriptor between the processes.
|
73
|
+
test_files: []
|
74
|
+
|