]> rtime.felk.cvut.cz Git - frescor/fwp.git/blob - fwp/lib/fwp/fwp_endpoint.c
fwp_endpoint_create returns socket descriptor
[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 fwp_epoint->sockd;               
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_epoint->port = ntohs(addr->sin_port);
367         FWP_DEBUG("Recv port= %d\n",ntohs(addr->sin_port));     
368         *epointd = fwp_epoint;  
369         return 0;
370 err:
371         fwp_endpoint_destroy(fwp_epoint);
372         return errno;
373 }
374
375 /**
376  * Binds send endpoint to vres
377  *
378  * \param[in] vres_id identifier of vres
379  * \param[in] epoint_id send endpoint identifier
380  *
381  * \return On success returns 0. On error, -1 and errno is set appropriately.
382  */
383 int fwp_send_endpoint_bind(fwp_endpoint_d_t epointd, fwp_vres_d_t vresd)
384 {
385         int rv = 0;
386 #ifndef FWP_WITHOUT_CONTNEGT
387         fwp_endpoint_t *fwp_epoint = epointd;
388         
389         fwp_epoint->vresd = vresd;      
390         rv = fwp_vres_bind(vresd, fwp_epoint->sockd);
391 #endif
392         /* if send endpoint is already bound 
393         if (epoint->type == FWP_EPOINT_BOUND) {  
394                 fwp_send_endpoint_unbind(epoint);
395         }*/
396         return rv;
397 }
398
399 /**
400  * Unbinds send endpoint from vres
401  *
402  * \param[in] epointd Send endpoint descriptor 
403  * \return On success returns 0. On error, -1 is returned and errno is set appropriately.
404  *
405  */
406 int fwp_send_endpoint_unbind(fwp_endpoint_d_t epointd)
407 {
408         int rv = 0;
409         fwp_endpoint_t *fwp_epoint = epointd;
410
411         /* unlink epoint-vres mutually */
412         if ((rv = fwp_vres_unbind(fwp_epoint->vresd)) < 0) 
413                 return rv;
414
415         return 0;
416 }
417
418 /**
419  * Accepts (TCP) client connection to receive endpoint
420  *
421  * \param[in] epointd Pointer to fwp endpoint
422  * \return
423  * On success, it returns zero.  
424  *
425  */
426 static int fwp_receive_endpoint_accept(fwp_endpoint_t *fwp_epoint)
427 {
428         int csockd;
429 //      fwp_endpoint_t *fwp_epoint = epointd;
430         fwp_sockaddr_t  peer;
431         int i;
432
433         if (fwp_epoint->nr_connections == fwp_epoint->attr.max_connections)
434                 return -1;
435
436         peer.addrlen = sizeof(struct sockaddr_in);
437         csockd = accept(fwp_epoint->sockd, (struct sockaddr*)peer.addr,
438                         &peer.addrlen);
439         
440         if (csockd < 0) {
441                 perror("Error on accept\n");
442                 return errno;   
443         }               
444
445         FWP_DEBUG("New connection accepted\n");
446         /* find free place */           
447         i = 0;
448         while ((fwp_epoint->c_sockd[i])&& (i < fwp_epoint->nr_connections)) 
449                                 i++;
450         fwp_epoint->c_sockd[i] = csockd; 
451         fwp_epoint->nr_connections++;
452                 
453         FD_SET(csockd, &fwp_epoint->fdset);
454         return 0;       
455
456
457 /**
458  * Receives message from stream (TCP)
459  *
460  * \param[in] epointd Descriptor of endpoint
461  * \param[in] buffer Buffer to store message
462  * \param[in] buffer_size Size of buffer
463  *
464  * \return
465  * On success, it returns number of received bytes.  
466  * On error, -1 is returned and errno is set appropriately.
467  *
468  */
469 int fwp_recv_conn(fwp_endpoint_d_t epointd, void *buffer, 
470                         size_t buffer_size)
471 {
472         fwp_endpoint_t *fwp_epoint = epointd;
473         fwp_sockaddr_t *peer = &fwp_epoint->peer;
474         fd_set fdset = fwp_epoint->fdset;
475         ssize_t len;
476         int i;
477
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)) {
481                         continue;       
482                 }       
483                         
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);
488
489                 if (len < 0) /* Error */
490                         return len;
491                 
492                 FWP_DEBUG("Received tcp data\n");
493                 if (len)
494                         return len;
495         
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--;
502                 return 0;
503         }
504         return 0;
505 }
506
507 /**
508  * Receives message
509  *
510  * \param[in] epointd Descriptor of endpoint
511  * \param[in] buffer Buffer to store message
512  * \param[in] buffer_size Size of buffer
513  *
514  * \return
515  * On success, it returns number of received bytes.  
516  * On error, -1 is returned and errno is set appropriately.
517  *
518  */
519 ssize_t fwp_recv(fwp_endpoint_d_t epointd,
520                         void *buffer, const size_t buffer_size,
521                         unsigned int *from, int flags)
522 {
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;
526         ssize_t len;
527         fd_set fdset;
528         
529         /*if (!fwp_endpoint_is_valid(epointd)) {
530                 errno = EINVAL;
531                 return -1;
532         }*/
533         
534         if (fwp_epoint->attr.reliability == FWP_EPOINT_BESTEFFORT) {    
535                 len = _fwp_recvfrom(fwp_epoint->sockd, buffer, 
536                                         buffer_size, 0, peer);
537                 
538                 *from = addr->sin_addr.s_addr;
539                 return len;
540         }
541         
542         while (1){
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) {
548                 
549                         FWP_ERROR("Error in select: %s", strerror(errno));
550                         return -1;
551                 }
552         
553                 if (FD_ISSET(fwp_epoint->sockd, &fdset)) { /* is it listen socket? */
554                         fwp_receive_endpoint_accept(fwp_epoint);
555                         continue;
556                 }
557
558                 /* Check client TCP sockets */
559                 len = fwp_recv_conn(fwp_epoint, buffer, buffer_size);
560                 if (len) {
561                         *from = addr->sin_addr.s_addr;
562                         return len;
563                 }
564         }
565 }
566
567 /**
568  * Sends message through vres
569  *
570  * \param[in] epointd Endpoint descriptor
571  * \param[in] msg Message to sent
572  * \param[in] size Message size
573  *
574  * \return
575  * On success, it returns zero.  
576  * On error, -1 is returned and errno is set appropriately.
577  *
578  */
579 int fwp_send(fwp_endpoint_d_t epointd,const void *msg, const size_t size, 
580                 int flags)
581 {
582         fwp_endpoint_t *fwp_epoint = epointd;
583         struct fwp_msgb *msgb;
584         
585 /*      if (!fwp_endpoint_is_valid(epointd)){
586                 errno = EINVAL;
587                 return -1;
588         }
589         if (!fwp_endpoint_is_bound(epointd)){
590                 errno = EPERM;
591                 return -1;
592         }*/
593
594         /*if (flags && MSG_DONTWAIT) 
595                 msgb = fwp_msgb_alloc(buffer_size);
596         else {*/
597                 if (!(msgb = fwp_msgb_alloc(size))) {
598                         errno = ENOMEM;
599                         return -1;
600                 }
601
602                 /*msgb->peer = &fwp_epoint->peer;*/
603                 /*msgb->data = msg;*/
604                 /*msgb->flags = epoint->flags;*/
605                 
606                 /* data must be copied since msg may change while
607                  * message is waiting in transmission queue 
608                  * */
609                 memcpy(msgb->data, msg, size);
610                 fwp_msgb_put(msgb, size);
611                 /*msgb->tail = msgb->data + size;
612                 msgb->len = size;*/
613
614         /*}*/
615
616         /* TODO: test whether _fwp_vres_send is successful */
617         return fwp_vres_send(fwp_epoint->vresd, msgb);
618 }
619