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));
245 /* TODO: Allow using connect if it is specified in attr */
246 if (connect(fwp_epoint->sockd,
247 (struct sockaddr*) &fwp_epoint->peer.addr,
248 fwp_epoint->peer.addrlen)) {
249 FWP_DEBUG("FWp connect error\n");
253 FWP_DEBUG("FWP Send endpoint created.\n");
255 #ifdef FWP_WITHOUT_CONTNEGT
256 /* Create vres with default parameters */
257 FWP_DEBUG("Creating default vres\n");
258 if (fwp_vres_create(&fwp_vres_params_default, &fwp_epoint->vresd)) {
262 fwp_send_endpoint_bind(fwp_epoint, fwp_epoint->vresd);
265 *epoint = fwp_epoint;
266 return fwp_epoint->sockd;
268 fwp_endpoint_destroy(fwp_epoint);
273 * Creates receive endpoint
275 * \param[in] port UDP port
276 * \param[in] attr Endpoint attributes
277 * \param[out] epointdp Pointer to the descriptor of newly created endpoint
279 * \return Zero on success, -1 on error and errno is set.
281 int fwp_receive_endpoint_create(unsigned int port,
282 fwp_endpoint_attr_t *attr,
283 struct fwp_endpoint **epp)
285 struct sockaddr_in *addr;
286 struct fwp_endpoint *fwp_epoint;
288 fwp_epoint = fwp_endpoint_alloc();
294 /*epoint->type = FWP_RECV_EPOINT;
295 epoint->status = FWP_EPOINT_UNBOUND;*/
298 fwp_epoint->attr = *attr;
300 fwp_epoint->attr = fwp_epoint_attr_default;
302 addr = (struct sockaddr_in *) &(fwp_epoint->peer.addr);
303 addr->sin_family = AF_INET;
304 /* TODO: set listen interface, maybe through config struct*/
305 addr->sin_addr.s_addr = FWP_ANY_NODE;
306 fwp_epoint->port = addr->sin_port = htons(port);
307 fwp_epoint->peer.addrlen = sizeof(struct sockaddr_in);
309 if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
310 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM,
312 FWP_ERROR("Unable to open socket: %s", strerror(errno));
317 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
318 &yes, sizeof(yes)) == -1) {
319 FWP_ERROR("setsockopt(SO_REUSEADDR):%s",strerror(errno));
323 if (bind(fwp_epoint->sockd, (struct sockaddr*) &fwp_epoint->peer.addr,
324 fwp_epoint->peer.addrlen) == -1) {
325 FWP_ERROR("Bind error: %s", strerror(errno));
326 /* TODO: remove all error messages from all libraries */
330 if (listen(fwp_epoint->sockd, fwp_epoint->attr.max_connections)){
331 FWP_ERROR("Error on listen call: %s\n", strerror(errno));
335 FD_ZERO(&fwp_epoint->fdset);
336 /*add listen socket */
337 FD_SET(fwp_epoint->sockd, &fwp_epoint->fdset);
338 fwp_epoint->c_sockd =
339 (int*)malloc(fwp_epoint->attr.max_connections);
340 bzero(fwp_epoint->c_sockd, fwp_epoint->attr.max_connections);
341 fwp_epoint->nr_connections = 0;
343 FWP_DEBUG("Reliable receive endpoint port=%d created.\n",
346 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM,
348 FWP_ERROR("Unable to open socket: %s", strerror(errno));
352 if (bind(fwp_epoint->sockd,
353 (struct sockaddr*) &fwp_epoint->peer.addr,
354 fwp_epoint->peer.addrlen) == -1) {
356 FWP_ERROR("Bind error: %s", strerror(errno));
359 FWP_DEBUG("Best-Effort receive endpoint port=%d created.\n",
363 /*if (setsockopt(epoint->sockd, SOL_SOCKET, SO_RCVBUF,
364 &rcvbuf_size, sizeof(rcvbuf_size)) == -1) {
366 FWP_ERROR("Unable to set socket buffer size: %s", strerror(errno));
369 FWP_DEBUG("Receive endpoint buffer size is set.\n");
373 getsockname(fwp_epoint->sockd, (struct sockaddr*)&fwp_epoint->peer.addr,
374 &fwp_epoint->peer.addrlen);
376 addr = (struct sockaddr_in*) fwp_epoint->peer.addr;
377 fwp_epoint->port = ntohs(addr->sin_port);
378 FWP_DEBUG("Recv port= %d\n",ntohs(addr->sin_port));
382 fwp_endpoint_destroy(fwp_epoint);
387 * Binds send endpoint to vres
389 * \param[in] vres identifier of vres
390 * \param[in] ep send endpoint identifier
392 * \return On success returns 0. On error, -1 and errno is set appropriately.
394 int fwp_send_endpoint_bind(struct fwp_endpoint *ep, fwp_vres_t *vres)
399 return FRSH_ERR_ALREADY_BOUND;
402 rv = fwp_vres_bind(vres, ep, ep->sockd, &ep->src);
408 * Unbinds send endpoint from vres
410 * \param[in] epointd Send endpoint descriptor
411 * \return On success returns 0. On error, -1 is returned and errno is set appropriately.
414 int fwp_send_endpoint_unbind(struct fwp_endpoint *ep)
418 /* unlink epoint-vres mutually */
419 if ((rv = fwp_vres_unbind(ep->vres)) < 0)
426 * Accepts (TCP) client connection to receive endpoint
428 * \param[in] epointd Pointer to fwp endpoint
430 * On success, it returns zero.
433 static int fwp_receive_endpoint_accept(struct fwp_endpoint *fwp_epoint)
436 // struct fwp_endpoint *fwp_epoint = epointd;
440 if (fwp_epoint->nr_connections == fwp_epoint->attr.max_connections)
443 peer.addrlen = sizeof(struct sockaddr_in);
444 csockd = accept(fwp_epoint->sockd, (struct sockaddr*)peer.addr,
448 FWP_ERROR("Error on accept: %s\n", strerror(errno));
452 FWP_DEBUG("New connection accepted\n");
453 /* find free place */
455 while ((fwp_epoint->c_sockd[i])&& (i < fwp_epoint->nr_connections))
457 fwp_epoint->c_sockd[i] = csockd;
458 fwp_epoint->nr_connections++;
460 FD_SET(csockd, &fwp_epoint->fdset);
465 * Receives message from stream (TCP)
467 * \param[in] epointd Descriptor of endpoint
468 * \param[in] buffer Buffer to store message
469 * \param[in] buffer_size Size of buffer
472 * On success, it returns number of received bytes.
473 * On error, -1 is returned and errno is set appropriately.
476 int fwp_recv_conn(struct fwp_endpoint *ep, void *buffer,
479 fwp_sockaddr_t *peer = &ep->peer;
480 fd_set fdset = ep->fdset;
484 FWP_DEBUG("Checking for tcp data\n");
485 for (i = 0; i < ep->nr_connections; i++) {
486 if (!FD_ISSET(ep->c_sockd[i], &fdset)) {
490 FWP_DEBUG("Prepare to receive tcp data\n");
491 peer->addrlen = sizeof(struct sockaddr_in);
493 len = recvfrom(ep->c_sockd[i], buffer, buffer_size, 0,
494 (struct sockaddr*)&peer->addr, &peer->addrlen);
495 if (len < 0) /* Error */
498 FWP_DEBUG("Received tcp data\n");
502 /* tcp connection closed */
503 FWP_DEBUG("Connection closed\n");
504 FD_CLR(ep->c_sockd[i], &ep->fdset);
505 memcpy(ep->c_sockd+i, ep->c_sockd+i+1,
506 sizeof(int)*(ep->nr_connections -i-1));
507 ep->nr_connections--;
516 * \param[in] epointd Descriptor of endpoint
517 * \param[in] buffer Buffer to store message
518 * \param[in] buffer_size Size of buffer
521 * On success, it returns number of received bytes.
522 * On error, -1 is returned and errno is set appropriately.
525 ssize_t fwp_recv(struct fwp_endpoint *ep,
526 void *buffer, const size_t buffer_size,
527 unsigned int *from, int flags)
529 fwp_sockaddr_t *peer = &ep->peer;
530 struct sockaddr_in *addr = (struct sockaddr_in*) ep->peer.addr;
534 /*if (!fwp_endpoint_is_valid(epointd)) {
539 if (ep->attr.reliability == FWP_EPOINT_BESTEFFORT) {
540 len = recvfrom(ep->sockd, buffer, buffer_size, 0,
541 (struct sockaddr*)&peer->addr, &peer->addrlen);
542 *from = addr->sin_addr.s_addr;
547 /* FWP_EPOINT_RELIABLE */
549 if (select(FD_SETSIZE, &fdset, (fd_set *)0,
550 (fd_set *)0, NULL) < 0) {
552 FWP_ERROR("Error in select: %s", strerror(errno));
556 if (FD_ISSET(ep->sockd, &fdset)) { /* is it listen socket? */
557 fwp_receive_endpoint_accept(ep);
561 /* Check client TCP sockets */
562 len = fwp_recv_conn(ep, buffer, buffer_size);
564 *from = addr->sin_addr.s_addr;
570 * Physically send the message.
572 * This function should be called either by fwp_send_sync()/async() of
573 * by VRES to send delayed messaged.
581 ssize_t fwp_endpoint_do_send(struct fwp_endpoint *ep,
582 const void *data, const size_t size)
585 struct msghdr msg = {0};
587 char cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
589 iov.iov_base = (void*)data;
592 msg.msg_name = &ep->peer.addr;
593 msg.msg_namelen = ep->peer.addrlen;
597 if (ep->src.s_addr != 0) {
598 struct cmsghdr *cmsg;
599 struct in_pktinfo *ipi;
601 memset(cmsg_buf, 0, sizeof(cmsg_buf));
603 msg.msg_control = cmsg_buf;
604 msg.msg_controllen = sizeof(cmsg_buf);
606 cmsg = CMSG_FIRSTHDR(&msg);
608 cmsg->cmsg_level = SOL_IP;
609 cmsg->cmsg_type = IP_PKTINFO;
610 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
612 ipi = (struct in_pktinfo*)CMSG_DATA(cmsg);
613 ipi->ipi_spec_dst = ep->src;
615 ret = sendmsg(ep->sockd, &msg, 0);
620 * Sends message through vres
622 * \param[in] epointd Endpoint descriptor
623 * \param[in] msg Message to sent
624 * \param[in] size Message size
627 * On success, it returns zero.
628 * On error, -1 is returned and errno is set appropriately.
631 int fwp_send_async(struct fwp_endpoint *ep, const void *msg, size_t size)
636 return FRSH_ERR_NOT_BOUND;
638 if (fwp_vres_consume_budget(ep->vres, size, false) == 0)
639 ret = fwp_endpoint_do_send(ep, msg, size);
641 ret = fwp_vres_enqueue(ep->vres, ep, msg, size);
645 int fwp_send_sync(struct fwp_endpoint *ep, const void *msg, size_t size)
650 return FRSH_ERR_NOT_BOUND;
652 ret = fwp_vres_consume_budget(ep->vres, size, true);
655 ret = fwp_endpoint_do_send(ep, msg, size);