fdpass 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|