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"
52 typedef unsigned int fwp_endpoint_id_t;
55 * Default fwp endpoint attributes
57 static fwp_endpoint_attr_t fwp_epoint_attr_default ={
58 .reliability = FWP_EPOINT_BESTEFFORT,
59 .max_connections = 20,
63 * FWP endpoint structure
66 /** Fwp endpoint attributes */
67 fwp_endpoint_attr_t attr;
68 /* Vres this fwp endpoint is bound to */
70 /** For send enpoint it contains destination address for
71 * receive endpoint it is filled with the msg source address
73 struct fwp_sockaddr peer;
74 /** Source/destination port */
76 /** Destination node */
78 /** Socket descriptor.
79 * In case of rebliable epoint it is a listen tcp socket.
82 /** File descriptor array of peers connected
83 * to this fwp receive endpoint.*/
86 * Number of connections
88 unsigned int nr_connections;
91 /** specific operation options*/
98 * \return On success returns fwp endpoint structure.
99 * On error, NULL is returned.
102 static fwp_endpoint_t* fwp_endpoint_alloc()
104 return (fwp_endpoint_t*) calloc(1,sizeof(fwp_endpoint_t));
110 * \return On success returns endpoint structure.
111 * On error, NULL is returned.
114 static inline void fwp_endpoint_free(fwp_endpoint_t *endpoint)
122 * \param[in] epointd Endpoint descriptor
123 * \return On success 0 is returned.
124 * On error, negative error value is returned and errno is set appropriately.
126 int fwp_endpoint_destroy(fwp_endpoint_d_t epointd)
128 if (epointd->sockd > 0)
129 close(epointd->sockd);
131 fwp_endpoint_free(epointd);
136 * Get endpoint parameters
138 * \param[in] epointd Endpoint descriptor
139 * \param[out] node Node identifier
140 * \param[out] port Port
141 * \param[out] attr Endpoint`s attributes
142 * \return On success 0 is returned.
143 * On error, negative error value is returned.
145 int fwp_endpoint_get_params(fwp_endpoint_d_t epointd, unsigned int *node,
146 unsigned int *port, fwp_endpoint_attr_t *attr)
148 fwp_endpoint_t *epoint = epointd;
150 if (node) *node = epoint->node;
151 if (port) *port = epoint->port;
152 if (attr) *attr = epoint->attr;
157 int fwp_endpoint_attr_init(fwp_endpoint_attr_t *attr)
159 bzero(attr, sizeof(fwp_endpoint_attr_t));
160 *attr = fwp_epoint_attr_default;
166 * Creates send endpoint
168 * \param[in] node IP address of destination node
169 * \param[in] port UDP port
170 * \param[in] attr Endpoint attributes
171 * \param[out] epointdp Pointer to the descriptor of newly created endpoint
173 * \return Zero on success, -1 on error and sets errno appropriately.
176 int fwp_send_endpoint_create(unsigned int node,
178 fwp_endpoint_attr_t *attr,
179 fwp_endpoint_d_t *epointd)
181 struct sockaddr_in *addr;
182 fwp_endpoint_t *fwp_epoint;
184 fwp_epoint = fwp_endpoint_alloc();
190 /*epoint->type = FWP_SEND_EPOINT;
191 epoint->status = FWP_EPOINT_UNBOUND;
196 fwp_epoint->attr = *attr;
198 fwp_epoint->attr = fwp_epoint_attr_default;
200 addr = (struct sockaddr_in *)&(fwp_epoint->peer.addr);
201 bzero((char*) addr, sizeof(*addr));
202 addr->sin_family = AF_INET;
203 addr->sin_addr.s_addr = node;
204 addr->sin_port = htons(port);
205 fwp_epoint->peer.addrlen = sizeof(struct sockaddr_in);
207 if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
208 fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
209 if (fwp_epoint->sockd < 0) {
213 fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
214 if (fwp_epoint->sockd < 0) {
218 /* Enable broadcasts */
219 /*unsigned int yes = 1;
220 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_BROADCAST,
221 &yes, sizeof(yes)) == -1) {
222 FWP_DEBUG("setsockopt(SO_BROADCAST): %s", strerror(errno));
228 unsigned int yes = 1;
229 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
230 &yes, sizeof(yes)) == -1) {
231 FWP_DEBUG("setsockopt(SO_REUSEADDR): %s", strerror(errno));
235 if (connect(fwp_epoint->sockd,
236 (struct sockaddr*) &fwp_epoint->peer.addr,
237 fwp_epoint->peer.addrlen)) {
238 FWP_DEBUG("FWp connect error\n");
242 FWP_DEBUG("FWP Send endpoint created.\n");
244 #ifdef FWP_WITHOUT_CONTNEGT
245 /* Create vres with default parameters */
246 FWP_DEBUG("Creating default vres\n");
247 if (fwp_vres_create(&fwp_vres_params_default, &fwp_epoint->vresd)) {
251 fwp_send_endpoint_bind(fwp_epoint, fwp_epoint->vresd);
254 *epointd = fwp_epoint;
255 return fwp_epoint->sockd;
257 fwp_endpoint_destroy(fwp_epoint);
262 * Creates receive endpoint
264 * \param[in] port UDP port
265 * \param[in] attr Endpoint attributes
266 * \param[out] epointdp Pointer to the descriptor of newly created endpoint
268 * \return Zero on success, -1 on error and errno is set.
270 int fwp_receive_endpoint_create(unsigned int port,
271 fwp_endpoint_attr_t *attr,
272 fwp_endpoint_d_t *epointd)
274 struct sockaddr_in *addr;
275 fwp_endpoint_t *fwp_epoint;
277 fwp_epoint = fwp_endpoint_alloc();
283 /*epoint->type = FWP_RECV_EPOINT;
284 epoint->status = FWP_EPOINT_UNBOUND;*/
287 fwp_epoint->attr = *attr;
289 fwp_epoint->attr = fwp_epoint_attr_default;
291 addr = (struct sockaddr_in *) &(fwp_epoint->peer.addr);
292 addr->sin_family = AF_INET;
293 /* TODO: set listen interface, maybe through config struct*/
294 addr->sin_addr.s_addr = FWP_ANY_NODE;
295 fwp_epoint->port = addr->sin_port = htons(port);
296 fwp_epoint->peer.addrlen = sizeof(struct sockaddr_in);
298 if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
299 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM,
301 FWP_ERROR("Unable to open socket: %s", strerror(errno));
306 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
307 &yes, sizeof(yes)) == -1) {
308 FWP_ERROR("setsockopt(SO_REUSEADDR):%s",strerror(errno));
312 if (bind(fwp_epoint->sockd, (struct sockaddr*) &fwp_epoint->peer.addr,
313 fwp_epoint->peer.addrlen) == -1) {
314 FWP_ERROR("Bind error: %s", strerror(errno));
315 /* TODO: remove all error messages from all libraries */
319 if (listen(fwp_epoint->sockd, fwp_epoint->attr.max_connections)){
320 perror("Error on listen call\n");
324 FD_ZERO(&fwp_epoint->fdset);
325 /*add listen socket */
326 FD_SET(fwp_epoint->sockd, &fwp_epoint->fdset);
327 fwp_epoint->c_sockd =
328 (int*)malloc(fwp_epoint->attr.max_connections);
329 bzero(fwp_epoint->c_sockd, fwp_epoint->attr.max_connections);
330 fwp_epoint->nr_connections = 0;
332 FWP_DEBUG("Reliable receive endpoint port=%d created.\n",
335 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM,
337 FWP_ERROR("Unable to open socket: %s", strerror(errno));
341 if (bind(fwp_epoint->sockd,
342 (struct sockaddr*) &fwp_epoint->peer.addr,
343 fwp_epoint->peer.addrlen) == -1) {
345 FWP_ERROR("Bind error: %s", strerror(errno));
348 FWP_DEBUG("Best-Effort receive endpoint port=%d created.\n",
352 /*if (setsockopt(epoint->sockd, SOL_SOCKET, SO_RCVBUF,
353 &rcvbuf_size, sizeof(rcvbuf_size)) == -1) {
355 FWP_ERROR("Unable to set socket buffer size: %s", strerror(errno));
358 FWP_DEBUG("Receive endpoint buffer size is set.\n");
362 getsockname(fwp_epoint->sockd, (struct sockaddr*)&fwp_epoint->peer.addr,
363 &fwp_epoint->peer.addrlen);
365 addr = (struct sockaddr_in*) fwp_epoint->peer.addr;
366 fwp_epoint->port = ntohs(addr->sin_port);
367 FWP_DEBUG("Recv port= %d\n",ntohs(addr->sin_port));
368 *epointd = fwp_epoint;
371 fwp_endpoint_destroy(fwp_epoint);
376 * Binds send endpoint to vres
378 * \param[in] vres_id identifier of vres
379 * \param[in] epoint_id send endpoint identifier
381 * \return On success returns 0. On error, -1 and errno is set appropriately.
383 int fwp_send_endpoint_bind(fwp_endpoint_d_t epointd, fwp_vres_d_t vresd)
386 #ifndef FWP_WITHOUT_CONTNEGT
387 fwp_endpoint_t *fwp_epoint = epointd;
389 fwp_epoint->vresd = vresd;
390 rv = fwp_vres_bind(vresd, fwp_epoint->sockd);
392 /* if send endpoint is already bound
393 if (epoint->type == FWP_EPOINT_BOUND) {
394 fwp_send_endpoint_unbind(epoint);
400 * Unbinds send endpoint from vres
402 * \param[in] epointd Send endpoint descriptor
403 * \return On success returns 0. On error, -1 is returned and errno is set appropriately.
406 int fwp_send_endpoint_unbind(fwp_endpoint_d_t epointd)
409 fwp_endpoint_t *fwp_epoint = epointd;
411 /* unlink epoint-vres mutually */
412 if ((rv = fwp_vres_unbind(fwp_epoint->vresd)) < 0)
419 * Accepts (TCP) client connection to receive endpoint
421 * \param[in] epointd Pointer to fwp endpoint
423 * On success, it returns zero.
426 static int fwp_receive_endpoint_accept(fwp_endpoint_t *fwp_epoint)
429 // fwp_endpoint_t *fwp_epoint = epointd;
433 if (fwp_epoint->nr_connections == fwp_epoint->attr.max_connections)
436 peer.addrlen = sizeof(struct sockaddr_in);
437 csockd = accept(fwp_epoint->sockd, (struct sockaddr*)peer.addr,
441 perror("Error on accept\n");
445 FWP_DEBUG("New connection accepted\n");
446 /* find free place */
448 while ((fwp_epoint->c_sockd[i])&& (i < fwp_epoint->nr_connections))
450 fwp_epoint->c_sockd[i] = csockd;
451 fwp_epoint->nr_connections++;
453 FD_SET(csockd, &fwp_epoint->fdset);
458 * Receives message from stream (TCP)
460 * \param[in] epointd Descriptor of endpoint
461 * \param[in] buffer Buffer to store message
462 * \param[in] buffer_size Size of buffer
465 * On success, it returns number of received bytes.
466 * On error, -1 is returned and errno is set appropriately.
469 int fwp_recv_conn(fwp_endpoint_d_t epointd, void *buffer,
472 fwp_endpoint_t *fwp_epoint = epointd;
473 fwp_sockaddr_t *peer = &fwp_epoint->peer;
474 fd_set fdset = fwp_epoint->fdset;
478 FWP_DEBUG("Checking for tcp data\n");
479 for (i = 0; i < fwp_epoint->nr_connections; i++) {
480 if (!FD_ISSET(fwp_epoint->c_sockd[i], &fdset)) {
484 FWP_DEBUG("Prepare to receive tcp data\n");
485 peer->addrlen = sizeof(struct sockaddr_in);
486 len = _fwp_recvfrom(fwp_epoint->c_sockd[i], buffer,
487 buffer_size,0, peer);
489 if (len < 0) /* Error */
492 FWP_DEBUG("Received tcp data\n");
496 /* tcp connection closed */
497 FWP_DEBUG("Connection closed\n");
498 FD_CLR(fwp_epoint->c_sockd[i], &fwp_epoint->fdset);
499 memcpy(fwp_epoint->c_sockd+i, fwp_epoint->c_sockd+i+1,
500 sizeof(int)*(fwp_epoint->nr_connections -i-1));
501 fwp_epoint->nr_connections--;
510 * \param[in] epointd Descriptor of endpoint
511 * \param[in] buffer Buffer to store message
512 * \param[in] buffer_size Size of buffer
515 * On success, it returns number of received bytes.
516 * On error, -1 is returned and errno is set appropriately.
519 ssize_t fwp_recv(fwp_endpoint_d_t epointd,
520 void *buffer, const size_t buffer_size,
521 unsigned int *from, int flags)
523 fwp_endpoint_t *fwp_epoint = epointd;
524 fwp_sockaddr_t *peer = &fwp_epoint->peer;
525 struct sockaddr_in *addr = (struct sockaddr_in*) fwp_epoint->peer.addr;
529 /*if (!fwp_endpoint_is_valid(epointd)) {
534 if (fwp_epoint->attr.reliability == FWP_EPOINT_BESTEFFORT) {
535 len = _fwp_recvfrom(fwp_epoint->sockd, buffer,
536 buffer_size, 0, peer);
538 *from = addr->sin_addr.s_addr;
543 /* FIXME: What about using a loop here and continue instead of goto???? */
544 /* FWP_EPOINT_RELIABLE */
545 fdset = fwp_epoint->fdset;
546 if (select(FD_SETSIZE, &fdset, (fd_set *)0,
547 (fd_set *)0, NULL) < 0) {
549 FWP_ERROR("Error in select: %s", strerror(errno));
553 if (FD_ISSET(fwp_epoint->sockd, &fdset)) { /* is it listen socket? */
554 fwp_receive_endpoint_accept(fwp_epoint);
558 /* Check client TCP sockets */
559 len = fwp_recv_conn(fwp_epoint, buffer, buffer_size);
561 *from = addr->sin_addr.s_addr;
568 * Sends message through vres
570 * \param[in] epointd Endpoint descriptor
571 * \param[in] msg Message to sent
572 * \param[in] size Message size
575 * On success, it returns zero.
576 * On error, -1 is returned and errno is set appropriately.
579 int fwp_send(fwp_endpoint_d_t epointd,const void *msg, const size_t size,
582 fwp_endpoint_t *fwp_epoint = epointd;
583 struct fwp_msgb *msgb;
585 /* if (!fwp_endpoint_is_valid(epointd)){
589 if (!fwp_endpoint_is_bound(epointd)){
594 /*if (flags && MSG_DONTWAIT)
595 msgb = fwp_msgb_alloc(buffer_size);
597 if (!(msgb = fwp_msgb_alloc(size))) {
602 /*msgb->peer = &fwp_epoint->peer;*/
603 /*msgb->data = msg;*/
604 /*msgb->flags = epoint->flags;*/
606 /* data must be copied since msg may change while
607 * message is waiting in transmission queue
609 memcpy(msgb->data, msg, size);
610 fwp_msgb_put(msgb, size);
611 /*msgb->tail = msgb->data + size;
616 /* TODO: test whether _fwp_vres_send is successful */
617 return fwp_vres_send(fwp_epoint->vresd, msgb);