]> rtime.felk.cvut.cz Git - frescor/forb.git/blob - src/proto_unix.c
Merge branch 'master' of rtime.felk.cvut.cz:/frescor/frsh-forb
[frescor/forb.git] / src / proto_unix.c
1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                 */
4 /*                                                                        */
5 /*   Universidad de Cantabria,              SPAIN                         */
6 /*   University of York,                    UK                            */
7 /*   Scuola Superiore Sant'Anna,            ITALY                         */
8 /*   Kaiserslautern University,             GERMANY                       */
9 /*   Univ. Politécnica  Valencia,           SPAIN                        */
10 /*   Czech Technical University in Prague,  CZECH REPUBLIC                */
11 /*   ENEA                                   SWEDEN                        */
12 /*   Thales Communication S.A.              FRANCE                        */
13 /*   Visual Tools S.A.                      SPAIN                         */
14 /*   Rapita Systems Ltd                     UK                            */
15 /*   Evidence                               ITALY                         */
16 /*                                                                        */
17 /*   See http://www.frescor.org for a link to partners' websites          */
18 /*                                                                        */
19 /*          FRESCOR project (FP6/2005/IST/5-034026) is funded             */
20 /*       in part by the European Union Sixth Framework Programme          */
21 /*       The European Union is not liable of any use that may be          */
22 /*       made of this code.                                               */
23 /*                                                                        */
24 /*                                                                        */
25 /*  This file is part of FORB (Frescor Object Request Broker)             */
26 /*                                                                        */
27 /* FORB is free software; you can redistribute it and/or modify it        */
28 /* under terms of the GNU General Public License as published by the      */
29 /* Free Software Foundation; either version 2, or (at your option) any    */
30 /* later version.  FORB is distributed in the hope that it will be        */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
33 /* General Public License for more details. You should have received a    */
34 /* copy of the GNU General Public License along with FORB; see file       */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
36 /* Cambridge, MA 02139, USA.                                              */
37 /*                                                                        */
38 /* As a special exception, including FORB header files in a file,         */
39 /* instantiating FORB generics or templates, or linking other files       */
40 /* with FORB objects to produce an executable application, does not       */
41 /* by itself cause the resulting executable application to be covered     */
42 /* by the GNU General Public License. This exception does not             */
43 /* however invalidate any other reasons why the executable file might be  */
44 /* covered by the GNU Public License.                                     */
45 /**************************************************************************/
46
47 #include <dirent.h>
48 #include "proto.h"
49 #include <forb/proto_unix.h>
50 #include <stdio.h>
51 #include <sys/socket.h>
52 #include <sys/types.h>
53 #include <sys/un.h>
54 #include <sys/stat.h>
55
56 /**
57  * @file   proto_unix.c
58  * @author Michal Sojka <sojkam1@fel.cvut.cz>
59  * @date   Sun Oct 12 16:10:23 2008
60  * 
61  * @brief  FORB transport protocol based on UNIX DGRAM sockets.
62  * 
63  * The sockets are created in filesystem in #FORB_TMP_DIR directory.
64  */
65
66
67 typedef struct sockaddr_un unix_addr_t;
68
69 /** UNIX protocol data for ports. */
70 struct unix_port {
71         int socket;
72         unix_addr_t addr;
73 };
74
75 static struct unix_port*
76 peer_to_uport(forb_peer_t *peer) { return peer->port->desc.proto_priv; }
77
78 static void
79 unix_server_to_addr(unix_addr_t *addr, const forb_server_id *server)
80 {
81         char str[65];
82         addr->sun_family = AF_UNIX;
83         sprintf(addr->sun_path, FORB_TMP_DIR "/sock.%s",
84                 forb_uuid_to_string(str, (forb_uuid_t*)server->uuid, sizeof(str)));
85 }
86
87 static ssize_t
88 unix_send(forb_peer_t *peer, const void *buf, size_t len)
89 {
90         unix_addr_t addr;
91         struct unix_port *p = peer_to_uport(peer);
92         //printf("send to %s\n", c->addr.sun_path);
93         unix_server_to_addr(&addr, &peer->server_id);
94         return sendto(p->socket, buf, len, 0,
95                       (struct sockaddr*)&addr, sizeof(addr));
96 }
97
98 static ssize_t
99 unix_recv(forb_port_t *port, void *buf, size_t len)
100 {
101         struct unix_port *p = port->desc.proto_priv;
102         return recv(p->socket, buf, len, 0);
103 }
104
105 static int
106 unix_port_destroy(forb_port_t * port)
107 {
108         struct unix_port *pd = port->desc.proto_priv;
109         unix_addr_t addr;
110         socklen_t len = sizeof(addr);
111         getsockname(pd->socket, (struct sockaddr*)&addr, &len);
112         if (addr.sun_family == AF_UNIX)
113                 unlink(addr.sun_path);
114         close(pd->socket);
115         forb_free(pd);
116         return 0;
117 }
118
119 static ssize_t
120 unix_broadcast(forb_port_t *port, const void *buf, size_t len)
121 {
122         struct unix_port *p = port->desc.proto_priv;
123         DIR *dir;
124         struct dirent *dirent;
125         unix_addr_t addr;
126         int ret;
127         int success = 0;
128         
129         dir = opendir(FORB_TMP_DIR);
130         if (!dir) return -errno;
131
132         addr.sun_family = AF_UNIX;
133         
134         while ((dirent = readdir(dir))) {
135                 bool forb_socket = 
136 #ifdef _DIRENT_HAVE_D_TYPE
137                         (dirent->d_type == DT_SOCK ||
138                          dirent->d_type == DT_UNKNOWN) &&
139 #else
140 #warning This system does not support _DIRENT_HAVE_D_TYPE
141 #endif
142                         (strncmp(dirent->d_name, "sock.", 5) == 0);
143                 
144 /*              printf("d_name=%s d_type=%d (%d)\n", dirent->d_name, dirent->d_type, DT_SOCK); */
145                 if (forb_socket)
146                 {
147                         strcpy(addr.sun_path, FORB_TMP_DIR "/");
148                         strncat(addr.sun_path, dirent->d_name, sizeof(addr.sun_path));
149 /*                      printf("Broadcasting to %s\n", addr.sun_path); */
150                         ret = sendto(p->socket, buf, len, 0,
151                                      (struct sockaddr*)&addr, sizeof(addr));
152                         /* We do not care about errors in brodcasts -
153                          * the socket may nomore be active */
154                         if (ret == len) {
155                                 success++;
156                         } else if (ret < 0 && errno == ECONNREFUSED) {
157                                 /* Try to unlink stale socket */
158                                 unlink(addr.sun_path);
159                         } else {
160 /*                              perror("unix_broadcast"); */
161 /*                              return ret; */
162                         }
163                 }
164                         
165         }
166         closedir(dir);
167         if (success) {
168                 ret = len;
169         } else {
170                 ret = -1;
171         }
172         return ret;
173 }
174
175 static const forb_proto_t proto_unix = {
176         .hello_interval = 40 /* seconds */,
177         .port_destroy = unix_port_destroy,
178         .peer_destroy = NULL,
179         .send = unix_send,
180         .recv = unix_recv,
181         .broadcast = unix_broadcast,
182         /* We do not need the following functions, sice the address
183          * can be derived from server_id */
184         .serialize_addr = NULL,
185         .deserialize_addr = NULL,
186 };
187
188 /** 
189  * Initializes UNIX protocol port.
190  * 
191  * @param port Port to initialize.
192  * @param server Server this port belongs to.
193  * 
194  * @return Zero on success, -1 on error and errno is set
195  * appropriately.
196  */
197 int
198 forb_unix_port_init(struct forb_port_desc *port_desc, const forb_server_id *server)
199 {
200         
201         int ret;       
202         struct unix_port *pd;
203
204         ret = forb_init_tmp_dir();
205
206         pd = forb_malloc(sizeof(*pd));
207         if (!pd)
208                 return -1;
209         
210         pd->socket = socket(PF_UNIX, SOCK_DGRAM, 0);
211         if (pd->socket == -1) goto err1;
212
213         unix_server_to_addr(&pd->addr, server);
214         /* unlink(pd->addr.sun_path); */ /* TODO: What to do when the socket already exist? */
215         ret = bind(pd->socket, (struct sockaddr*)&pd->addr, sizeof(pd->addr));
216         chmod(pd->addr.sun_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
217         if (ret == -1) goto err;
218
219         port_desc->proto = &proto_unix;
220         port_desc->proto_priv = pd;
221         return 0;
222 err:
223         ret = errno;
224         close(pd->socket);
225         errno = ret;
226 err1:
227         ret = errno;
228         forb_free(pd);
229         errno = ret;
230         return -1;
231 }