]> rtime.felk.cvut.cz Git - frescor/fwp.git/blob - fwp/lib/fwp/fwp_endpoint.c
ebadbba4be7af184579554206cb956355f808099
[frescor/fwp.git] / fwp / lib / fwp / fwp_endpoint.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 FWP (Frescor WLAN Protocol)                      */
26 /*                                                                        */
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.                                              */
37 /*                                                                        */
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"
47 #include "fwp_msgb.h"
48 #include <errno.h>
49
50 #include <pthread.h>
51
52 typedef unsigned int fwp_endpoint_id_t;
53
54 /**
55  * Default fwp endpoint attributes
56  */
57 static fwp_endpoint_attr_t fwp_epoint_attr_default ={
58         .reliability = FWP_EPOINT_BESTEFFORT, 
59         .max_connections = 20,
60 };
61
62 /**
63  * FWP endpoint structure
64  */
65 struct fwp_endpoint{
66         /** Fwp endpoint attributes */
67         fwp_endpoint_attr_t     attr;
68         /* Vres this fwp endpoint is bound to */
69         fwp_vres_d_t            vresd;
70         /** For send enpoint it contains destination address for
71          * receive endpoint it is filled with the msg source address
72          */
73         struct fwp_sockaddr     peer;   
74         /** Source/destination port */
75         unsigned int            port;   
76         /** Destination node */
77         int                     node;
78         /** Socket descriptor.
79          * In case of rebliable epoint it is a listen tcp socket.
80          */
81         int                     sockd; 
82         /** File descriptor array of peers connected 
83          * to this fwp receive endpoint.*/
84         int                     *c_sockd;
85         /**
86          * Number of connections 
87          */
88         unsigned int            nr_connections;
89         /** client fdset */
90         fd_set                  fdset;
91         /** specific operation options*/
92         int                     flags;  
93 };
94
95 /**
96  * Allocates endpoint
97  *
98  * \return On success returns fwp endpoint structure. 
99  * On error, NULL is returned. 
100  *
101  */
102 static fwp_endpoint_t* fwp_endpoint_alloc()
103 {
104         return (fwp_endpoint_t*) calloc(1,sizeof(fwp_endpoint_t));
105 }
106
107 /**
108  * Allocates endpoint
109  *
110  * \return On success returns endpoint structure. 
111  * On error, NULL is returned. 
112  *
113  */
114 static inline void fwp_endpoint_free(fwp_endpoint_t *endpoint)
115 {
116         free(endpoint);
117 }
118
119 /**
120  * Destroy endpoint
121  *
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. 
125  */
126 int fwp_endpoint_destroy(fwp_endpoint_d_t epointd)
127 {
128         if (epointd->sockd > 0) 
129                 close(epointd->sockd);
130         
131         fwp_endpoint_free(epointd);     
132         return 0;
133 }
134
135 /**
136  * Get endpoint parameters
137  *
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. 
144  */
145 int fwp_endpoint_get_params(fwp_endpoint_d_t epointd, unsigned int *node, 
146                                 unsigned int *port, fwp_endpoint_attr_t *attr)
147 {
148         fwp_endpoint_t *epoint = epointd;
149
150         if (node) *node = epoint->node;
151         if (port) *port = epoint->port;
152         if (attr) *attr = epoint->attr;
153         
154         return 0;
155 }
156
157 int fwp_endpoint_attr_init(fwp_endpoint_attr_t *attr)
158 {
159         bzero(attr, sizeof(fwp_endpoint_attr_t));
160         *attr = fwp_epoint_attr_default;
161
162         return 0;
163 }
164
165 /**
166  * Creates send endpoint
167  *
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
172  *
173  * \return Zero on success, -1 on error and sets errno appropriately. 
174  *
175  */
176 int fwp_send_endpoint_create(unsigned int node,
177                                 unsigned int port, 
178                                 fwp_endpoint_attr_t *attr,
179                                 fwp_endpoint_d_t *epointd)
180 {       
181         struct sockaddr_in *addr;
182         fwp_endpoint_t *fwp_epoint;
183
184         fwp_epoint = fwp_endpoint_alloc();      
185         if (!fwp_epoint) {
186                 errno = ENOMEM;
187                 return -1;
188         }
189         
190         /*epoint->type = FWP_SEND_EPOINT;
191         epoint->status = FWP_EPOINT_UNBOUND;
192         epoint->node = node;
193         epoint->port = port;
194         */
195         if (attr)
196                 fwp_epoint->attr  = *attr;
197         else
198                 fwp_epoint->attr = fwp_epoint_attr_default;
199                 
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);
206         
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) {
210                         goto err;
211                 }
212         } else {
213                 fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
214                 if (fwp_epoint->sockd < 0) {
215                         goto err;
216                 }
217         
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));
223                         goto err;
224                 }*/
225         
226         }
227         
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));
232                         goto err;
233         }
234
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"); 
239                 goto err;
240         }
241         
242         FWP_DEBUG("FWP Send endpoint created.\n"); 
243
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)) {
248                 goto err;
249         }
250         
251         fwp_send_endpoint_bind(fwp_epoint, fwp_epoint->vresd);
252 #endif
253         
254         *epointd = fwp_epoint;
255         return 0;               
256 err:
257         fwp_endpoint_destroy(fwp_epoint);
258         return -1;      
259 }
260
261 /**
262  * Creates receive endpoint
263  *
264  * \param[in] port UDP port
265  * \param[in] attr Endpoint attributes
266  * \param[out] epointdp  Pointer to the descriptor of newly created endpoint
267  *
268  * \return Zero on success, -1 on error and errno is set.
269  */
270 int fwp_receive_endpoint_create(unsigned int port,
271                                 fwp_endpoint_attr_t *attr,
272                                 fwp_endpoint_d_t *epointd)
273 {
274         struct sockaddr_in *addr;
275         fwp_endpoint_t *fwp_epoint;
276
277         fwp_epoint = fwp_endpoint_alloc();      
278         if (!fwp_epoint) {
279                 errno = ENOMEM;
280                 return -1;
281         }
282         
283         /*epoint->type = FWP_RECV_EPOINT;
284         epoint->status = FWP_EPOINT_UNBOUND;*/
285         
286         if (attr)
287                 fwp_epoint->attr  = *attr;
288         else
289                 fwp_epoint->attr = fwp_epoint_attr_default;
290
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);
297         
298         if (fwp_epoint->attr.reliability == FWP_EPOINT_RELIABLE) {
299                 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_STREAM, 
300                                                 IPPROTO_TCP)) < 0) {
301                         FWP_ERROR("Unable to open socket: %s", strerror(errno));
302                         goto err;
303                 }       
304                 
305                 int yes = 1;
306                 if (setsockopt(fwp_epoint->sockd,SOL_SOCKET, SO_REUSEADDR,
307                                &yes, sizeof(yes)) == -1) {
308                         FWP_ERROR("setsockopt(SO_REUSEADDR):%s",strerror(errno));
309                         goto err;
310                 }
311
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 */
316                         goto err;
317                 }
318                 
319                 if (listen(fwp_epoint->sockd, fwp_epoint->attr.max_connections)){
320                         perror("Error on listen call\n");
321                         goto err;
322                 }
323                 
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;
331
332                 FWP_DEBUG("Reliable receive endpoint port=%d created.\n", 
333                                 fwp_epoint->port); 
334         } else {
335                 if ((fwp_epoint->sockd = socket(PF_INET, SOCK_DGRAM, 
336                                                 IPPROTO_UDP)) < 0) {
337                         FWP_ERROR("Unable to open socket: %s", strerror(errno));
338                         goto err;
339                 }
340                 
341                 if (bind(fwp_epoint->sockd, 
342                         (struct sockaddr*) &fwp_epoint->peer.addr, 
343                         fwp_epoint->peer.addrlen) == -1) {
344                         
345                         FWP_ERROR("Bind error: %s", strerror(errno));
346                         goto err;
347                 }
348                 FWP_DEBUG("Best-Effort receive endpoint port=%d created.\n", 
349                                 fwp_epoint->port); 
350         }
351                 
352         /*if (setsockopt(epoint->sockd, SOL_SOCKET, SO_RCVBUF, 
353                         &rcvbuf_size, sizeof(rcvbuf_size)) == -1) {
354                 
355                 FWP_ERROR("Unable to set socket buffer size: %s", strerror(errno));
356                 return -1;
357         }else {
358                 FWP_DEBUG("Receive endpoint buffer size is set.\n");
359         }
360         */
361         
362         getsockname(fwp_epoint->sockd, (struct sockaddr*)&fwp_epoint->peer.addr, 
363                         &fwp_epoint->peer.addrlen);
364
365         addr = (struct sockaddr_in*) fwp_epoint->peer.addr;
366         FWP_DEBUG("Recv port= %d\n",ntohs(addr->sin_port));     
367         *epointd = fwp_epoint;  
368         return 0;
369 err:
370         fwp_endpoint_destroy(fwp_epoint);
371         return errno;
372 }
373
374 /**
375  * Binds send endpoint to vres
376  *
377  * \param[in] vres_id identifier of vres
378  * \param[in] epoint_id send endpoint identifier
379  *
380  * \return On success returns 0. On error, -1 and errno is set appropriately.
381  */
382 int fwp_send_endpoint_bind(fwp_endpoint_d_t epointd, fwp_vres_d_t vresd)
383 {
384         int rv = 0;
385 #ifndef FWP_WITHOUT_CONTNEGT
386         fwp_endpoint_t *fwp_epoint = epointd;
387         
388         fwp_epoint->vresd = vresd;      
389         rv = fwp_vres_bind(vresd, fwp_epoint->sockd);
390 #endif
391         /* if send endpoint is already bound 
392         if (epoint->type == FWP_EPOINT_BOUND) {  
393                 fwp_send_endpoint_unbind(epoint);
394         }*/
395         return rv;
396 }
397
398 /**
399  * Unbinds send endpoint from vres
400  *
401  * \param[in] epointd Send endpoint descriptor 
402  * \return On success returns 0. On error, -1 is returned and errno is set appropriately.
403  *
404  */
405 int fwp_send_endpoint_unbind(fwp_endpoint_d_t epointd)
406 {
407         int rv = 0;
408         fwp_endpoint_t *fwp_epoint = epointd;
409
410         /* unlink epoint-vres mutually */
411         if ((rv = fwp_vres_unbind(fwp_epoint->vresd)) < 0) 
412                 return rv;
413
414         return 0;
415 }
416
417 /**
418  * Accepts (TCP) client connection to receive endpoint
419  *
420  * \param[in] epointd Pointer to fwp endpoint
421  * \return
422  * On success, it returns zero.  
423  *
424  */
425 static int fwp_receive_endpoint_accept(fwp_endpoint_t *fwp_epoint)
426 {
427         int csockd;
428 //      fwp_endpoint_t *fwp_epoint = epointd;
429         fwp_sockaddr_t  peer;
430         int i;
431
432         if (fwp_epoint->nr_connections == fwp_epoint->attr.max_connections)
433                 return -1;
434
435         peer.addrlen = sizeof(struct sockaddr_in);
436         csockd = accept(fwp_epoint->sockd, (struct sockaddr*)peer.addr,
437                         &peer.addrlen);
438         
439         if (csockd < 0) {
440                 perror("Error on accept\n");
441                 return errno;   
442         }               
443
444         FWP_DEBUG("New connection accepted\n");
445         /* find free place */           
446         i = 0;
447         while ((fwp_epoint->c_sockd[i])&& (i < fwp_epoint->nr_connections)) 
448                                 i++;
449         fwp_epoint->c_sockd[i] = csockd; 
450         fwp_epoint->nr_connections++;
451                 
452         FD_SET(csockd, &fwp_epoint->fdset);
453         return 0;       
454
455
456 /**
457  * Receives message from stream (TCP)
458  *
459  * \param[in] epointd Descriptor of endpoint
460  * \param[in] buffer Buffer to store message
461  * \param[in] buffer_size Size of buffer
462  *
463  * \return
464  * On success, it returns number of received bytes.  
465  * On error, -1 is returned and errno is set appropriately.
466  *
467  */
468 int fwp_recv_conn(fwp_endpoint_d_t epointd, void *buffer, 
469                                 size_t buffer_size)
470 {
471         fwp_endpoint_t *fwp_epoint = epointd;
472         fwp_sockaddr_t *peer = &fwp_epoint->peer;
473         fd_set fdset = fwp_epoint->fdset;
474         ssize_t len;
475         int i;
476
477         FWP_DEBUG("Checking for tcp data\n");
478         for (i = 0; i < fwp_epoint->nr_connections; i++) {
479                 if (!FD_ISSET(fwp_epoint->c_sockd[i], &fdset)) {
480                         continue;       
481                 }       
482                         
483                 FWP_DEBUG("Prepare to receive tcp data\n");
484                 peer->addrlen = sizeof(struct sockaddr_in);
485                 len = _fwp_recvfrom(fwp_epoint->c_sockd[i], buffer, 
486                                         buffer_size,0, peer);
487
488                 if (len < 0) /* Error */
489                         return len;
490                 
491                 FWP_DEBUG("Received tcp data\n");
492                 if (len)
493                         return len;
494         
495                 /* tcp connection closed */
496                 FWP_DEBUG("Connection closed\n");
497                 FD_CLR(fwp_epoint->c_sockd[i], &fwp_epoint->fdset);
498                 memcpy(fwp_epoint->c_sockd+i, fwp_epoint->c_sockd+i+1, 
499                         sizeof(int)*(fwp_epoint->nr_connections -i-1));
500                 fwp_epoint->nr_connections--;
501                 return 0;
502         }
503         return 0;
504 }
505
506 /**
507  * Receives message
508  *
509  * \param[in] epointd Descriptor of endpoint
510  * \param[in] buffer Buffer to store message
511  * \param[in] buffer_size Size of buffer
512  *
513  * \return
514  * On success, it returns number of received bytes.  
515  * On error, -1 is returned and errno is set appropriately.
516  *
517  */
518 ssize_t fwp_recv(fwp_endpoint_d_t epointd,
519                         void *buffer, const size_t buffer_size,
520                         unsigned int *from, int flags)
521 {
522         fwp_endpoint_t *fwp_epoint = epointd;
523         fwp_sockaddr_t *peer = &fwp_epoint->peer;
524         ssize_t len;
525         fd_set fdset;
526         
527         /*if (!fwp_endpoint_is_valid(epointd)) {
528                 errno = EINVAL;
529                 return -1;
530         }*/
531         
532         if (fwp_epoint->attr.reliability == FWP_EPOINT_BESTEFFORT) {    
533                 len = _fwp_recvfrom(fwp_epoint->sockd, buffer, 
534                                         buffer_size, 0, peer);
535                 return len;
536         }
537         
538         while (1){
539         /* FIXME: What about using a loop here and continue instead of goto???? */
540                 /* FWP_EPOINT_RELIABLE */
541                 fdset = fwp_epoint->fdset;
542                 if (select(FD_SETSIZE, &fdset, (fd_set *)0, 
543                            (fd_set *)0, NULL) < 0) {
544                 
545                         FWP_ERROR("Error in select: %s", strerror(errno));
546                         return -1;
547                 }
548         
549                 if (FD_ISSET(fwp_epoint->sockd, &fdset)) { /* is it listen socket? */
550                         fwp_receive_endpoint_accept(fwp_epoint);
551                         continue;
552                 }
553
554                 /* Check client TCP sockets */
555                 len = fwp_recv_conn(fwp_epoint, buffer, buffer_size);
556                 if (len)
557                         return len;
558         }
559 }
560
561 /**
562  * Sends message through vres
563  *
564  * \param[in] epointd Endpoint descriptor
565  * \param[in] msg Message to sent
566  * \param[in] size Message size
567  *
568  * \return
569  * On success, it returns zero.  
570  * On error, -1 is returned and errno is set appropriately.
571  *
572  */
573 int fwp_send(fwp_endpoint_d_t epointd,const void *msg, const size_t size, 
574                 int flags)
575 {
576         fwp_endpoint_t *fwp_epoint = epointd;
577         struct fwp_msgb *msgb;
578         
579 /*      if (!fwp_endpoint_is_valid(epointd)){
580                 errno = EINVAL;
581                 return -1;
582         }
583         if (!fwp_endpoint_is_bound(epointd)){
584                 errno = EPERM;
585                 return -1;
586         }*/
587
588         /*if (flags && MSG_DONTWAIT) 
589                 msgb = fwp_msgb_alloc(buffer_size);
590         else {*/
591                 if (!(msgb = fwp_msgb_alloc(size))) {
592                         errno = ENOMEM;
593                         return -1;
594                 }
595
596                 /*msgb->peer = &fwp_epoint->peer;*/
597                 /*msgb->data = msg;*/
598                 /*msgb->flags = epoint->flags;*/
599                 
600                 /* data must be copied since msg may change while
601                  * message is waiting in transmission queue 
602                  * */
603                 memcpy(msgb->data, msg, size);
604                 fwp_msgb_put(msgb, size);
605                 /*msgb->tail = msgb->data + size;
606                 msgb->len = size;*/
607
608         /*}*/
609
610         /* TODO: test whether _fwp_vres_send is successful */
611         return fwp_vres_send(fwp_epoint->vresd, msgb);
612 }
613