1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners: */
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 */
12 /* Thales Communication S.A. FRANCE */
13 /* Visual Tools S.A. SPAIN */
14 /* Rapita Systems Ltd UK */
17 /* See http://www.frescor.org for a link to partners' websites */
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. */
25 /* This file is part of FWP (Frescor WLAN Protocol) */
27 /* FWP 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. FWP 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 FWP; see file */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
36 /* Cambridge, MA 02139, USA. */
38 /* As a special exception, including FWP header files in a file, */
39 /* instantiating FWP generics or templates, or linking other files */
40 /* with FWP 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 #include "fwp_endpoint.h"
51 #include <netinet/in.h>
52 #include "fwp_utils.h"
54 #include <frsh_error.h>
57 #include "fwp_debug.h"
60 typedef unsigned int fwp_endpoint_id_t;
63 * Default fwp endpoint attributes
65 static fwp_endpoint_attr_t fwp_epoint_attr_default ={
66 .reliability = FWP_EPOINT_BESTEFFORT,
67 .max_connections = 20,
71 * FWP endpoint structure
74 /** Fwp endpoint attributes */
75 fwp_endpoint_attr_t attr;
76 /* Vres this fwp endpoint is bound to */
78 /** For send enpoint it contains destination address for
79 * receive endpoint it is filled with the msg source address
81 struct fwp_sockaddr peer;
82 /** Source/destination port */
84 /** Destination node */
86 /** Socket descriptor.
87 * In case of rebliable epoint it is a listen tcp socket.
90 /** File descriptor array of peers connected
91 * to this fwp receive endpoint.*/
94 * Number of connections
96 unsigned int nr_connections;
99 /** specific operation options*/
101 /** Forced source address. If non-zero, packets are sent over
102 * the specified interface. */
109 * \return On success returns fwp endpoint structure.
110 * On error, NULL is returned.
113 static struct fwp_endpoint* fwp_endpoint_alloc()
115 return (struct fwp_endpoint*) calloc(1,sizeof(struct fwp_endpoint));
121 * \return On success returns endpoint structure.
122 * On error, NULL is returned.
125 static inline void fwp_endpoint_free(struct fwp_endpoint *endpoint)
133 * \param[in] epd Endpoint descriptor
134 * \return On success 0 is returned.
135 * On error, negative error value is returned and errno is set appropriately.
137 int fwp_endpoint_destroy(struct fwp_endpoint *ep)
142 fwp_endpoint_free(ep);
147 * Get endpoint parameters
149 * \param[in] ep Endpoint descriptor
150 * \param[out] node Node identifier
151 * \param[out] port Port
152 * \param[out] attr Endpoint`s attributes
153 * \return On success 0 is returned.
154 * On error, negative error value is returned.
156 int fwp_endpoint_get_params(struct fwp_endpoint *ep, unsigned int *node,
157 unsigned int *port, fwp_endpoint_attr_t *attr)
159 if (node) *node = ep->node;
160 if (port) *port = ep->port;
161 if (attr) *attr = ep->attr;
166 int fwp_endpoint_attr_init(fwp_endpoint_attr_t *attr)
168 bzero(attr, sizeof(fwp_endpoint_attr_t));
169 *attr = fwp_epoint_attr_default;
175 * Creates send endpoint
177 * \param[in] node IP address of destination node
178 * \param[in] port UDP port
179 * \param[in] attr Endpoint attributes
180 * \param[out] epp Pointer to the descriptor of newly created endpoint
182 * \return Zero on success, -1 on error and sets errno appropriately.
185 int fwp_send_endpoint_create(unsigned int node,
187 fwp_endpoint_attr_t *attr,
188 struct fwp_endpoint **epoint)
190 struct sockaddr_in *addr;
191 struct fwp_endpoint *fwp_epoint;
193 fwp_epoint = fwp_endpoint_alloc();
199 /*epoint->type = FWP_SEND_EPOINT;
200 epoint->status = FWP_EPOINT_UNBOUND;
205 fwp_epoint->attr = *attr;
207 fwp_epoint->attr = fwp_epoint_attr_default;
209 addr = (struct sockaddr_in *)&(fwp_epoint->peer.addr);
210 bzero((char*) addr, sizeof(*addr));
211 addr->sin_family = AF_INET;
212 addr->sin_addr.s_addr = node;
213 addr->sin_port = htons(port);
214 fwp_epoint->peer.addrlen = sizeof(struct sockaddr_in);
216 if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
217 fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
218 if (fwp_epoint->sockd < 0) {
222 fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
223 if (fwp_epoint->sockd < 0) {
227 /* Enable broadcasts */
228 /*unsigned int yes = 1;
229 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_BROADCAST,
230 &yes, sizeof(yes)) == -1) {
231 FWP_DEBUG("setsockopt(SO_BROADCAST): %s", strerror(errno));
237 unsigned int yes = 1;
238 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
239 &yes, sizeof(yes)) == -1) {
240 FWP_DEBUG("setsockopt(SO_REUSEADDR): %s", strerror(errno));
244 if (connect(fwp_epoint->sockd,
245 (struct sockaddr*) &fwp_epoint->peer.addr,
246 fwp_epoint->peer.addrlen)) {
247 FWP_DEBUG("FWp connect error\n");
251 FWP_DEBUG("FWP Send endpoint created.\n");
253 #ifdef FWP_WITHOUT_CONTNEGT
254 /* Create vres with default parameters */
255 FWP_DEBUG("Creating default vres\n");
256 if (fwp_vres_create(&fwp_vres_params_default, &fwp_epoint->vresd)) {
260 fwp_send_endpoint_bind(fwp_epoint, fwp_epoint->vresd);
263 *epoint = fwp_epoint;
264 return fwp_epoint->sockd;
266 fwp_endpoint_destroy(fwp_epoint);
271 * Creates receive endpoint
273 * \param[in] port UDP port
274 * \param[in] attr Endpoint attributes
275 * \param[out] epointdp Pointer to the descriptor of newly created endpoint
277 * \return Zero on success, -1 on error and errno is set.
279 int fwp_receive_endpoint_create(unsigned int port,
280 fwp_endpoint_attr_t *attr,
281 struct fwp_endpoint **epp)
283 struct sockaddr_in *addr;
284 struct fwp_endpoint *fwp_epoint;
286 fwp_epoint = fwp_endpoint_alloc();
292 /*epoint->type = FWP_RECV_EPOINT;
293 epoint->status = FWP_EPOINT_UNBOUND;*/
296 fwp_epoint->attr = *attr;
298 fwp_epoint->attr = fwp_epoint_attr_default;
300 addr = (struct sockaddr_in *) &(fwp_epoint->peer.addr);
301 addr->sin_family = AF_INET;
302 /* TODO: set listen interface, maybe through config struct*/
303 addr->sin_addr.s_addr = FWP_ANY_NODE;
304 fwp_epoint->port = addr->sin_port = htons(port);
305 fwp_epoint->peer.addrlen = sizeof(struct sockaddr_in);
307 if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
308 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM,
310 FWP_ERROR("Unable to open socket: %s", strerror(errno));
315 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
316 &yes, sizeof(yes)) == -1) {
317 FWP_ERROR("setsockopt(SO_REUSEADDR):%s",strerror(errno));
321 if (bind(fwp_epoint->sockd, (struct sockaddr*) &fwp_epoint->peer.addr,
322 fwp_epoint->peer.addrlen) == -1) {
323 FWP_ERROR("Bind error: %s", strerror(errno));
324 /* TODO: remove all error messages from all libraries */
328 if (listen(fwp_epoint->sockd, fwp_epoint->attr.max_connections)){
329 FWP_ERROR("Error on listen call: %s\n", strerror(errno));
333 FD_ZERO(&fwp_epoint->fdset);
334 /*add listen socket */
335 FD_SET(fwp_epoint->sockd, &fwp_epoint->fdset);
336 fwp_epoint->c_sockd =
337 (int*)malloc(fwp_epoint->attr.max_connections);
338 bzero(fwp_epoint->c_sockd, fwp_epoint->attr.max_connections);
339 fwp_epoint->nr_connections = 0;
341 FWP_DEBUG("Reliable receive endpoint port=%d created.\n",
344 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM,
346 FWP_ERROR("Unable to open socket: %s", strerror(errno));
350 if (bind(fwp_epoint->sockd,
351 (struct sockaddr*) &fwp_epoint->peer.addr,
352 fwp_epoint->peer.addrlen) == -1) {
354 FWP_ERROR("Bind error: %s", strerror(errno));
357 FWP_DEBUG("Best-Effort receive endpoint port=%d created.\n",
361 /*if (setsockopt(epoint->sockd, SOL_SOCKET, SO_RCVBUF,
362 &rcvbuf_size, sizeof(rcvbuf_size)) == -1) {
364 FWP_ERROR("Unable to set socket buffer size: %s", strerror(errno));
367 FWP_DEBUG("Receive endpoint buffer size is set.\n");
371 getsockname(fwp_epoint->sockd, (struct sockaddr*)&fwp_epoint->peer.addr,
372 &fwp_epoint->peer.addrlen);
374 addr = (struct sockaddr_in*) fwp_epoint->peer.addr;
375 fwp_epoint->port = ntohs(addr->sin_port);
376 FWP_DEBUG("Recv port= %d\n",ntohs(addr->sin_port));
380 fwp_endpoint_destroy(fwp_epoint);
385 * Binds send endpoint to vres
387 * \param[in] vres identifier of vres
388 * \param[in] ep send endpoint identifier
390 * \return On success returns 0. On error, -1 and errno is set appropriately.
392 int fwp_send_endpoint_bind(struct fwp_endpoint *ep, fwp_vres_t *vres)
397 return FRSH_ERR_ALREADY_BOUND;
400 rv = fwp_vres_bind(vres, ep, ep->sockd, &ep->src);
406 * Unbinds send endpoint from vres
408 * \param[in] epointd Send endpoint descriptor
409 * \return On success returns 0. On error, -1 is returned and errno is set appropriately.
412 int fwp_send_endpoint_unbind(struct fwp_endpoint *ep)
416 /* unlink epoint-vres mutually */
417 if ((rv = fwp_vres_unbind(ep->vres)) < 0)
424 * Accepts (TCP) client connection to receive endpoint
426 * \param[in] epointd Pointer to fwp endpoint
428 * On success, it returns zero.
431 static int fwp_receive_endpoint_accept(struct fwp_endpoint *fwp_epoint)
434 // struct fwp_endpoint *fwp_epoint = epointd;
438 if (fwp_epoint->nr_connections == fwp_epoint->attr.max_connections)
441 peer.addrlen = sizeof(struct sockaddr_in);
442 csockd = accept(fwp_epoint->sockd, (struct sockaddr*)peer.addr,
446 FWP_ERROR("Error on accept: %s\n", strerror(errno));
450 FWP_DEBUG("New connection accepted\n");
451 /* find free place */
453 while ((fwp_epoint->c_sockd[i])&& (i < fwp_epoint->nr_connections))
455 fwp_epoint->c_sockd[i] = csockd;
456 fwp_epoint->nr_connections++;
458 FD_SET(csockd, &fwp_epoint->fdset);
463 * Receives message from stream (TCP)
465 * \param[in] epointd Descriptor of endpoint
466 * \param[in] buffer Buffer to store message
467 * \param[in] buffer_size Size of buffer
470 * On success, it returns number of received bytes.
471 * On error, -1 is returned and errno is set appropriately.
474 int fwp_recv_conn(struct fwp_endpoint *ep, void *buffer,
477 fwp_sockaddr_t *peer = &ep->peer;
478 fd_set fdset = ep->fdset;
482 FWP_DEBUG("Checking for tcp data\n");
483 for (i = 0; i < ep->nr_connections; i++) {
484 if (!FD_ISSET(ep->c_sockd[i], &fdset)) {
488 FWP_DEBUG("Prepare to receive tcp data\n");
489 peer->addrlen = sizeof(struct sockaddr_in);
491 len = recvfrom(ep->c_sockd[i], buffer, buffer_size, 0,
492 (struct sockaddr*)&peer->addr, &peer->addrlen);
493 if (len < 0) /* Error */
496 FWP_DEBUG("Received tcp data\n");
500 /* tcp connection closed */
501 FWP_DEBUG("Connection closed\n");
502 FD_CLR(ep->c_sockd[i], &ep->fdset);
503 memcpy(ep->c_sockd+i, ep->c_sockd+i+1,
504 sizeof(int)*(ep->nr_connections -i-1));
505 ep->nr_connections--;
514 * \param[in] epointd Descriptor of endpoint
515 * \param[in] buffer Buffer to store message
516 * \param[in] buffer_size Size of buffer
519 * On success, it returns number of received bytes.
520 * On error, -1 is returned and errno is set appropriately.
523 ssize_t fwp_recv(struct fwp_endpoint *ep,
524 void *buffer, const size_t buffer_size,
525 unsigned int *from, int flags)
527 fwp_sockaddr_t *peer = &ep->peer;
528 struct sockaddr_in *addr = (struct sockaddr_in*) ep->peer.addr;
532 /*if (!fwp_endpoint_is_valid(epointd)) {
537 if (ep->attr.reliability == FWP_EPOINT_BESTEFFORT) {
538 len = recvfrom(ep->sockd, buffer, buffer_size, 0,
539 (struct sockaddr*)&peer->addr, &peer->addrlen);
540 *from = addr->sin_addr.s_addr;
545 /* FWP_EPOINT_RELIABLE */
547 if (select(FD_SETSIZE, &fdset, (fd_set *)0,
548 (fd_set *)0, NULL) < 0) {
550 FWP_ERROR("Error in select: %s", strerror(errno));
554 if (FD_ISSET(ep->sockd, &fdset)) { /* is it listen socket? */
555 fwp_receive_endpoint_accept(ep);
559 /* Check client TCP sockets */
560 len = fwp_recv_conn(ep, buffer, buffer_size);
562 *from = addr->sin_addr.s_addr;
568 * Physically send the message.
570 * This function should be called either by fwp_send_sync()/async() of
571 * by VRES to send delayed messaged.
579 ssize_t fwp_endpoint_do_send(struct fwp_endpoint *ep,
580 const void *data, const size_t size)
583 struct msghdr msg = {0};
585 char cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
587 iov.iov_base = (void*)data;
593 if (ep->src.s_addr != 0) {
594 struct cmsghdr *cmsg;
595 struct in_pktinfo *ipi;
597 memset(cmsg_buf, 0, sizeof(cmsg_buf));
599 msg.msg_control = cmsg_buf;
600 msg.msg_controllen = sizeof(cmsg_buf);
602 cmsg = CMSG_FIRSTHDR(&msg);
604 cmsg->cmsg_level = SOL_IP;
605 cmsg->cmsg_type = IP_PKTINFO;
606 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
608 ipi = (struct in_pktinfo*)CMSG_DATA(cmsg);
609 ipi->ipi_spec_dst = ep->src;
611 ret = sendmsg(ep->sockd, &msg, 0);
616 * Sends message through vres
618 * \param[in] epointd Endpoint descriptor
619 * \param[in] msg Message to sent
620 * \param[in] size Message size
623 * On success, it returns zero.
624 * On error, -1 is returned and errno is set appropriately.
627 int fwp_send_async(struct fwp_endpoint *ep, const void *msg, size_t size)
632 return FRSH_ERR_NOT_BOUND;
634 if (fwp_vres_consume_budget(ep->vres, size, false) == 0)
635 ret = fwp_endpoint_do_send(ep, msg, size);
637 ret = fwp_vres_enqueue(ep->vres, ep, msg, size);
641 int fwp_send_sync(struct fwp_endpoint *ep, const void *msg, size_t size)
646 return FRSH_ERR_NOT_BOUND;
648 ret = fwp_vres_consume_budget(ep->vres, size, true);
651 ret = fwp_endpoint_do_send(ep, msg, size);