Merge branch 'pu'
[jungerl.git] / lib / fd_server / c_src / fdsend_drv.c
blob3c1a4a343f2cf30b62ee2510e8015d7c2f0a910f
1 /*
2 * Created: klacke@erix.ericsson.se
3 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <strings.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/uio.h>
14 #include <sys/un.h>
16 #include "erl_driver.h"
17 #ifndef ERL_DRV_NIL
18 #include "erl_driver_compat.h"
19 #endif
21 #include "fdlib.h"
23 /* forward declarations */
24 static ErlDrvData start(ErlDrvPort port, char *buf);
25 static void stop(ErlDrvData drv_data);
26 static void from_erlang(ErlDrvData drv_data, char* buf, int len);
28 /* driver global variables */
29 static int instance = -1;
31 static ErlDrvEntry fdsend_drv_entry;
33 #define MAXSLAVES 64
35 #define LISTEN 'L'
36 #define ACCEPT 'A'
38 struct slave {
39 int fd;
40 char *path;
41 char type;
42 } slaves[MAXSLAVES];
45 static int find_free_slave()
47 int i;
48 for(i=0; i<MAXSLAVES; i++) {
49 if (slaves[i].fd == -1)
50 return i;
52 return -1;
55 static int find_slave(int fd)
57 int i;
58 for(i=0; i<MAXSLAVES; i++) {
59 if (slaves[i].fd == fd)
60 return i;
62 return -1;
65 DRIVER_INIT(fdsend_drv)
67 fdsend_drv_entry.init = NULL;
68 fdsend_drv_entry.start = start;
69 fdsend_drv_entry.stop = stop;
70 fdsend_drv_entry.output = from_erlang;
71 fdsend_drv_entry.ready_input = NULL;
72 fdsend_drv_entry.ready_output = NULL;
73 fdsend_drv_entry.driver_name = "fdsend_drv";
74 fdsend_drv_entry.finish = NULL;
75 fdsend_drv_entry.outputv = NULL;
76 return &fdsend_drv_entry;
81 * Called when erlang side does "open_port()".
83 static ErlDrvData start(ErlDrvPort port, char *buf)
85 int i;
86 if (instance != -1) /* only allow one copy at the time */
87 return (ErlDrvData) -1;
88 for (i =0; i< MAXSLAVES; i++) {
89 slaves[i].fd = -1;
90 slaves[i].path = NULL;
92 return (ErlDrvData)port;
96 static void from_erlang(ErlDrvData drv_data, char* buf, int n)
98 ErlDrvPort port = (ErlDrvPort) drv_data;
99 char *tp;
100 int i, j;
101 int slavefd, fd, afd;
103 switch (*buf++) {
104 case 'L': /* Bind and listen to new af_unix socket to path */
105 fd = fd_listen_path(port, buf);
107 if ((i = find_free_slave()) == -1) {
108 reply_err(port);
109 return;
112 if (fd > 0) {
113 if ((tp = (char*) driver_alloc(n)) != NULL) {
114 slaves[i].type = LISTEN;
115 slaves[i].path = tp;
116 strcpy(slaves[i].path, buf);
117 slaves[i].fd = fd;
118 reply_int(port, fd);
119 return;
122 reply_err(port);
123 return;
125 case 'A': /* accept the af_unix path socket */
126 fd = get_int32(buf);
128 if ((i = find_slave(fd)) == -1) {
129 reply_err(port);
130 return;
132 if ((j = find_free_slave()) == -1) {
133 reply_err(port);
134 return;
136 tp = slaves[i].path;
137 if ((afd = fd_accept_path(port, fd, tp)) > 0) {
139 slaves[j].path = tp;
140 slaves[j].type = ACCEPT;
141 slaves[j].fd = afd;
142 reply_int(port, afd);
144 else {
145 reply_err(port);
147 return;
148 case 'l':
149 case 'S': /* send a socket to slave */
150 fd = get_int32(buf);
151 slavefd = get_int32(buf+4);
153 if (send_fd(&fd, slavefd) == -1)
154 reply_err(port);
155 else {
156 reply_ok(port);
158 return;
159 case 'C': /* close */
160 fd = get_int32(buf);
161 if ((i = find_slave(fd)) == -1) {
162 reply_err(port);
163 return;
165 if (slaves[i].path && slaves[i].type == LISTEN)
166 driver_free(slaves[i].path);
167 slaves[i].path = NULL;
168 close(fd);
169 slaves[i].fd = -1;
170 reply_ok(port);
171 return;
173 return;
179 * Called when the Erlang port is closed.
181 static void stop(ErlDrvData drv_data)
183 int i;
184 for (i=0; i< MAXSLAVES; i++) {
185 if (slaves[i].fd > 0) {
186 if (slaves[i].type == LISTEN)
187 driver_free(slaves[i].path);
188 slaves[i].path = NULL;
189 close(slaves[i].fd);
192 instance = -1;