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"
55 #include "fwp_debug.h"
57 typedef unsigned int fwp_endpoint_id_t;
60 * Default fwp endpoint attributes
62 static fwp_endpoint_attr_t fwp_epoint_attr_default ={
63 .reliability = FWP_EPOINT_BESTEFFORT,
64 .max_connections = 20,
68 * FWP endpoint structure
71 /** Fwp endpoint attributes */
72 fwp_endpoint_attr_t attr;
73 /* Vres this fwp endpoint is bound to */
75 /** For send enpoint it contains destination address for
76 * receive endpoint it is filled with the msg source address
78 struct fwp_sockaddr peer;
79 /** Source/destination port */
81 /** Destination node */
83 /** Socket descriptor.
84 * In case of rebliable epoint it is a listen tcp socket.
87 /** File descriptor array of peers connected
88 * to this fwp receive endpoint.*/
91 * Number of connections
93 unsigned int nr_connections;
96 /** specific operation options*/
103 * \return On success returns fwp endpoint structure.
104 * On error, NULL is returned.
107 static fwp_endpoint_t* fwp_endpoint_alloc()
109 return (fwp_endpoint_t*) calloc(1,sizeof(fwp_endpoint_t));
115 * \return On success returns endpoint structure.
116 * On error, NULL is returned.
119 static inline void fwp_endpoint_free(fwp_endpoint_t *endpoint)
127 * \param[in] epointd Endpoint descriptor
128 * \return On success 0 is returned.
129 * On error, negative error value is returned and errno is set appropriately.
131 int fwp_endpoint_destroy(fwp_endpoint_d_t epointd)
133 if (epointd->sockd > 0)
134 close(epointd->sockd);
136 fwp_endpoint_free(epointd);
141 * Get endpoint parameters
143 * \param[in] epointd Endpoint descriptor
144 * \param[out] node Node identifier
145 * \param[out] port Port
146 * \param[out] attr Endpoint`s attributes
147 * \return On success 0 is returned.
148 * On error, negative error value is returned.
150 int fwp_endpoint_get_params(fwp_endpoint_d_t epointd, unsigned int *node,
151 unsigned int *port, fwp_endpoint_attr_t *attr)
153 fwp_endpoint_t *epoint = epointd;
155 if (node) *node = epoint->node;
156 if (port) *port = epoint->port;
157 if (attr) *attr = epoint->attr;
162 int fwp_endpoint_attr_init(fwp_endpoint_attr_t *attr)
164 bzero(attr, sizeof(fwp_endpoint_attr_t));
165 *attr = fwp_epoint_attr_default;
171 * Creates send endpoint
173 * \param[in] node IP address of destination node
174 * \param[in] port UDP port
175 * \param[in] attr Endpoint attributes
176 * \param[out] epointdp Pointer to the descriptor of newly created endpoint
178 * \return Zero on success, -1 on error and sets errno appropriately.
181 int fwp_send_endpoint_create(unsigned int node,
183 fwp_endpoint_attr_t *attr,
184 fwp_endpoint_d_t *epointd)
186 struct sockaddr_in *addr;
187 fwp_endpoint_t *fwp_epoint;
189 fwp_epoint = fwp_endpoint_alloc();
195 /*epoint->type = FWP_SEND_EPOINT;
196 epoint->status = FWP_EPOINT_UNBOUND;
201 fwp_epoint->attr = *attr;
203 fwp_epoint->attr = fwp_epoint_attr_default;
205 addr = (struct sockaddr_in *)&(fwp_epoint->peer.addr);
206 bzero((char*) addr, sizeof(*addr));
207 addr->sin_family = AF_INET;
208 addr->sin_addr.s_addr = node;
209 addr->sin_port = htons(port);
210 fwp_epoint->peer.addrlen = sizeof(struct sockaddr_in);
212 if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
213 fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
214 if (fwp_epoint->sockd < 0) {
218 fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
219 if (fwp_epoint->sockd < 0) {
223 /* Enable broadcasts */
224 /*unsigned int yes = 1;
225 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_BROADCAST,
226 &yes, sizeof(yes)) == -1) {
227 FWP_DEBUG("setsockopt(SO_BROADCAST): %s", strerror(errno));
233 unsigned int yes = 1;
234 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
235 &yes, sizeof(yes)) == -1) {
236 FWP_DEBUG("setsockopt(SO_REUSEADDR): %s", strerror(errno));
240 if (connect(fwp_epoint->sockd,
241 (struct sockaddr*) &fwp_epoint->peer.addr,
242 fwp_epoint->peer.addrlen)) {
243 FWP_DEBUG("FWp connect error\n");
247 FWP_DEBUG("FWP Send endpoint created.\n");
249 #ifdef FWP_WITHOUT_CONTNEGT
250 /* Create vres with default parameters */
251 FWP_DEBUG("Creating default vres\n");
252 if (fwp_vres_create(&fwp_vres_params_default, &fwp_epoint->vresd)) {
256 fwp_send_endpoint_bind(fwp_epoint, fwp_epoint->vresd);
259 *epointd = fwp_epoint;
260 return fwp_epoint->sockd;
262 fwp_endpoint_destroy(fwp_epoint);
267 * Creates receive endpoint
269 * \param[in] port UDP port
270 * \param[in] attr Endpoint attributes
271 * \param[out] epointdp Pointer to the descriptor of newly created endpoint
273 * \return Zero on success, -1 on error and errno is set.
275 int fwp_receive_endpoint_create(unsigned int port,
276 fwp_endpoint_attr_t *attr,
277 fwp_endpoint_d_t *epointd)
279 struct sockaddr_in *addr;
280 fwp_endpoint_t *fwp_epoint;
282 fwp_epoint = fwp_endpoint_alloc();
288 /*epoint->type = FWP_RECV_EPOINT;
289 epoint->status = FWP_EPOINT_UNBOUND;*/
292 fwp_epoint->attr = *attr;
294 fwp_epoint->attr = fwp_epoint_attr_default;
296 addr = (struct sockaddr_in *) &(fwp_epoint->peer.addr);
297 addr->sin_family = AF_INET;
298 /* TODO: set listen interface, maybe through config struct*/
299 addr->sin_addr.s_addr = FWP_ANY_NODE;
300 fwp_epoint->port = addr->sin_port = htons(port);
301 fwp_epoint->peer.addrlen = sizeof(struct sockaddr_in);
303 if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
304 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM,
306 FWP_ERROR("Unable to open socket: %s", strerror(errno));
311 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
312 &yes, sizeof(yes)) == -1) {
313 FWP_ERROR("setsockopt(SO_REUSEADDR):%s",strerror(errno));
317 if (bind(fwp_epoint->sockd, (struct sockaddr*) &fwp_epoint->peer.addr,
318 fwp_epoint->peer.addrlen) == -1) {
319 FWP_ERROR("Bind error: %s", strerror(errno));
320 /* TODO: remove all error messages from all libraries */
324 if (listen(fwp_epoint->sockd, fwp_epoint->attr.max_connections)){
325 FWP_ERROR("Error on listen call: %s\n", strerror(errno));
329 FD_ZERO(&fwp_epoint->fdset);
330 /*add listen socket */
331 FD_SET(fwp_epoint->sockd, &fwp_epoint->fdset);
332 fwp_epoint->c_sockd =
333 (int*)malloc(fwp_epoint->attr.max_connections);
334 bzero(fwp_epoint->c_sockd, fwp_epoint->attr.max_connections);
335 fwp_epoint->nr_connections = 0;
337 FWP_DEBUG("Reliable receive endpoint port=%d created.\n",
340 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM,
342 FWP_ERROR("Unable to open socket: %s", strerror(errno));
346 if (bind(fwp_epoint->sockd,
347 (struct sockaddr*) &fwp_epoint->peer.addr,
348 fwp_epoint->peer.addrlen) == -1) {
350 FWP_ERROR("Bind error: %s", strerror(errno));
353 FWP_DEBUG("Best-Effort receive endpoint port=%d created.\n",
357 /*if (setsockopt(epoint->sockd, SOL_SOCKET, SO_RCVBUF,
358 &rcvbuf_size, sizeof(rcvbuf_size)) == -1) {
360 FWP_ERROR("Unable to set socket buffer size: %s", strerror(errno));
363 FWP_DEBUG("Receive endpoint buffer size is set.\n");
367 getsockname(fwp_epoint->sockd, (struct sockaddr*)&fwp_epoint->peer.addr,
368 &fwp_epoint->peer.addrlen);
370 addr = (struct sockaddr_in*) fwp_epoint->peer.addr;
371 fwp_epoint->port = ntohs(addr->sin_port);
372 FWP_DEBUG("Recv port= %d\n",ntohs(addr->sin_port));
373 *epointd = fwp_epoint;
376 fwp_endpoint_destroy(fwp_epoint);
381 * Binds send endpoint to vres
383 * \param[in] vres_id identifier of vres
384 * \param[in] epoint_id send endpoint identifier
386 * \return On success returns 0. On error, -1 and errno is set appropriately.
388 int fwp_send_endpoint_bind(fwp_endpoint_d_t epointd, fwp_vres_d_t vresd)
391 #ifndef FWP_WITHOUT_CONTNEGT
392 fwp_endpoint_t *fwp_epoint = epointd;
394 fwp_epoint->vresd = vresd;
395 rv = fwp_vres_bind(vresd, fwp_epoint->sockd);
397 /* if send endpoint is already bound
398 if (epoint->type == FWP_EPOINT_BOUND) {
399 fwp_send_endpoint_unbind(epoint);
405 * Unbinds send endpoint from vres
407 * \param[in] epointd Send endpoint descriptor
408 * \return On success returns 0. On error, -1 is returned and errno is set appropriately.
411 int fwp_send_endpoint_unbind(fwp_endpoint_d_t epointd)
414 fwp_endpoint_t *fwp_epoint = epointd;
416 /* unlink epoint-vres mutually */
417 if ((rv = fwp_vres_unbind(fwp_epoint->vresd)) < 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(fwp_endpoint_t *fwp_epoint)
434 // fwp_endpoint_t *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(fwp_endpoint_d_t epointd, void *buffer,
477 fwp_endpoint_t *fwp_epoint = epointd;
478 fwp_sockaddr_t *peer = &fwp_epoint->peer;
479 fd_set fdset = fwp_epoint->fdset;
483 FWP_DEBUG("Checking for tcp data\n");
484 for (i = 0; i < fwp_epoint->nr_connections; i++) {
485 if (!FD_ISSET(fwp_epoint->c_sockd[i], &fdset)) {
489 FWP_DEBUG("Prepare to receive tcp data\n");
490 peer->addrlen = sizeof(struct sockaddr_in);
491 len = _fwp_recvfrom(fwp_epoint->c_sockd[i], buffer,
492 buffer_size,0, peer);
494 if (len < 0) /* Error */
497 FWP_DEBUG("Received tcp data\n");
501 /* tcp connection closed */
502 FWP_DEBUG("Connection closed\n");
503 FD_CLR(fwp_epoint->c_sockd[i], &fwp_epoint->fdset);
504 memcpy(fwp_epoint->c_sockd+i, fwp_epoint->c_sockd+i+1,
505 sizeof(int)*(fwp_epoint->nr_connections -i-1));
506 fwp_epoint->nr_connections--;
515 * \param[in] epointd Descriptor of endpoint
516 * \param[in] buffer Buffer to store message
517 * \param[in] buffer_size Size of buffer
520 * On success, it returns number of received bytes.
521 * On error, -1 is returned and errno is set appropriately.
524 ssize_t fwp_recv(fwp_endpoint_d_t epointd,
525 void *buffer, const size_t buffer_size,
526 unsigned int *from, int flags)
528 fwp_endpoint_t *fwp_epoint = epointd;
529 fwp_sockaddr_t *peer = &fwp_epoint->peer;
530 struct sockaddr_in *addr = (struct sockaddr_in*) fwp_epoint->peer.addr;
534 /*if (!fwp_endpoint_is_valid(epointd)) {
539 if (fwp_epoint->attr.reliability == FWP_EPOINT_BESTEFFORT) {
540 len = _fwp_recvfrom(fwp_epoint->sockd, buffer,
541 buffer_size, 0, peer);
543 *from = addr->sin_addr.s_addr;
548 /* FWP_EPOINT_RELIABLE */
549 fdset = fwp_epoint->fdset;
550 if (select(FD_SETSIZE, &fdset, (fd_set *)0,
551 (fd_set *)0, NULL) < 0) {
553 FWP_ERROR("Error in select: %s", strerror(errno));
557 if (FD_ISSET(fwp_epoint->sockd, &fdset)) { /* is it listen socket? */
558 fwp_receive_endpoint_accept(fwp_epoint);
562 /* Check client TCP sockets */
563 len = fwp_recv_conn(fwp_epoint, buffer, buffer_size);
565 *from = addr->sin_addr.s_addr;
572 * Sends message through vres
574 * \param[in] epointd Endpoint descriptor
575 * \param[in] msg Message to sent
576 * \param[in] size Message size
579 * On success, it returns zero.
580 * On error, -1 is returned and errno is set appropriately.
583 int fwp_send(fwp_endpoint_d_t epointd,const void *msg, const size_t size,
586 fwp_endpoint_t *fwp_epoint = epointd;
587 struct fwp_msgb *msgb;
589 /* if (!fwp_endpoint_is_valid(epointd)){
593 if (!fwp_endpoint_is_bound(epointd)){
598 /*if (flags && MSG_DONTWAIT)
599 msgb = fwp_msgb_alloc(buffer_size);
601 if (!(msgb = fwp_msgb_alloc(size))) {
606 /*msgb->peer = &fwp_epoint->peer;*/
607 /*msgb->data = msg;*/
608 /*msgb->flags = epoint->flags;*/
610 /* data must be copied since msg may change while
611 * message is waiting in transmission queue
613 memcpy(msgb->data, msg, size);
614 fwp_msgb_put(msgb, size);
615 /*msgb->tail = msgb->data + size;
620 /* TODO: test whether _fwp_vres_send is successful */
621 return fwp_vres_send(fwp_epoint->vresd, msgb);