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