1 #include <VP_Com/vp_com_socket.h>
2 #include <VP_Com/vp_com_error.h>
4 #include <VP_Os/vp_os_malloc.h>
5 #include <VP_Os/vp_os_print.h>
6 #include <VP_Os/vp_os_signal.h>
12 #include <sys/socket.h>
13 #include <sys/ioctl.h>
14 #include <netinet/in.h>
15 #include <netinet/tcp.h>
21 #if defined(USE_MINGW32) || defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR)
23 #define MSG_NOSIGNAL 0
26 #endif // USE_MINGW32 || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
31 extern int inet_addr(const char *);
34 C_RESULT vp_com_open_socket(vp_com_socket_t* sck, Read* read, Write* write)
36 C_RESULT res = VP_COM_OK;
39 struct sockaddr_in name = { 0 };
41 switch( sck->protocol )
44 s = socket( AF_INET, SOCK_STREAM, 0 );
45 res = ( s < 0 ) ? VP_COM_ERROR : VP_COM_OK;
50 s = socket( AF_INET, SOCK_DGRAM, 0 );
51 sck->scn = inet_addr(sck->serverHost); // Cache destination in int format
52 res = ( s < 0 ) ? VP_COM_ERROR : VP_COM_OK;
53 type = VP_COM_SERVER; // Make sure we will bind the socket in the connection-less protocol
58 res = VP_COM_PARAMERROR;
64 PRINT("\nSocket opening failed\n");
69 name.sin_family = AF_INET;
70 name.sin_port = htons( sck->port );
74 name.sin_addr.s_addr = inet_addr(sck->serverHost);
75 if ( connect( s, (struct sockaddr*)&name, sizeof( name ) ) == -1 )
80 name.sin_addr.s_addr = INADDR_ANY;
82 if ( bind( s, (struct sockaddr*)&name, sizeof(struct sockaddr)) < 0 )
85 if ( sck->is_multicast == 1 )
88 if ( sck->multicast_base_addr == 0 )
90 PRINT("Error : multicast base address is not defined\n");
95 in_addr_t multicast_address, drone_address;
96 vp_com_wifi_config_t *wifi_cfg = (vp_com_wifi_config_t*) wifi_config();
98 // compute remote address according to local address
99 drone_address = inet_addr(wifi_cfg->server);
100 multicast_address = htonl( sck->multicast_base_addr | (ntohl(drone_address) & 0xFF) );
103 mreq.imr_interface.s_addr = inet_addr(wifi_cfg->localHost);
104 mreq.imr_multiaddr.s_addr = multicast_address;
106 if ( setsockopt( s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) ) < 0) {
107 PRINT("!!! Error enabling multicast !!!\n");
114 res = VP_COM_PARAMERROR;
120 sck->priv = (void*) s;
122 switch( sck->protocol )
125 if(read) *read = (Read) vp_com_read_socket;
126 if(write) *write = (Write) vp_com_write_socket;
130 if(read) *read = (Read) vp_com_read_udp_socket;
131 if(write) *write = (Write) vp_com_write_udp_socket;
135 if(read) *read = NULL;
136 if(write) *write = NULL;
145 if (sck->block != VP_COM_DEFAULT &&
146 sck->block != VP_COM_WAITALL &&
147 sck->block != VP_COM_DONTWAIT)
149 sck->block = VP_COM_DEFAULT;
155 C_RESULT vp_com_close_socket(vp_com_socket_t* socket)
158 return VP_COM_PARAMERROR;
160 // shutdown( (int) socket->priv, SHUT_RDWR );
161 close( (int) socket->priv );
168 C_RESULT vp_com_wait_socket(vp_com_socket_t* server, vp_com_socket_t* client, int32_t queue_length)
170 C_RESULT res = VP_COM_OK;
173 return VP_COM_PARAMERROR;
175 int s = (int) server->priv;
177 socklen_t l = sizeof(struct sockaddr_in);
178 struct sockaddr_in raddr = { 0 }; // remote address
180 server->queue_length = queue_length;
182 listen(s, queue_length);
183 c = accept( s, (struct sockaddr*)&raddr, &l );
189 vp_os_memcpy( client, server, sizeof(vp_com_socket_t) );
190 client->priv = (void*) c;
198 C_RESULT vp_com_sockopt_ip(vp_com_t* vp_com, vp_com_socket_t* socket, VP_COM_SOCKET_OPTIONS options)
203 C_RESULT res = VP_COM_ERROR;
205 int s = (int) socket->priv;
207 if( options & VP_COM_NON_BLOCKING )
212 PRINT("Setting socket %d to non blocking\n", s);
213 res = ioctl( s, FIONBIO, &arg ) < 0 ? C_FAIL : C_OK;
217 PRINT("error setting non blocking\n");
220 if( options & VP_COM_NO_DELAY )
222 PRINT("Disabling the Nagle (TCP No Delay) algorithm for socket %d\n", s);
224 res = setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one) ) < 0 ? C_FAIL : C_OK;
227 PRINT("error disabling the Nagle algorithm\n");
230 if ( options & VP_COM_MULTICAST_ON )
232 res = setsockopt( s, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero) );
234 PRINT("Error : cannot set IP_MULTICAST_LOOP to 0\n");
236 struct in_addr interface_addr;
237 interface_addr.s_addr = INADDR_ANY;
238 res = setsockopt( s, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr) );
240 PRINT("Error : cannot enable multicast.\n");
247 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
251 C_RESULT vp_com_read_udp_socket(vp_com_socket_t* sck, int8_t* buffer, int32_t* size)
254 int s = (int) sck->priv;
255 struct sockaddr_in from;
257 socklen_t from_len = sizeof(from);
259 int flags = MSG_NOSIGNAL;
260 if (VP_COM_DONTWAIT == sck->block)
261 flags |= MSG_DONTWAIT;
262 else if (VP_COM_WAITALL == sck->block)
263 flags |= MSG_WAITALL;
269 *size = recvfrom(s, (char*)buffer, *size, flags, (struct sockaddr*)&from, &from_len );
275 switch( WSAGetLastError() )
278 PRINT("MSG_NOSIGNAL is not supported on this platform\n");
289 PRINT("Connection with peer is not enabled\n");
302 PRINT("MSG_NOSIGNAL is not supported on this platform\n");
309 PRINT("Connection with peer is not enabled\n");
314 PRINT("recvfrom fails with error: %s\n", strerror(errno));
318 #endif // USE_MINGW32
322 sck->scn = from.sin_addr.s_addr;
323 sck->port = ntohs(from.sin_port);
334 C_RESULT vp_com_make_udp_target( vp_com_socket_t* sck )
336 C_RESULT res = C_FAIL;
338 if( sck->protocol == VP_COM_UDP )
340 sck->scn = inet_addr(sck->serverHost); // We use scn field to store ip in order to avoid a call to inet_addr each time we call write
347 C_RESULT vp_com_write_udp_socket(vp_com_socket_t* sck, const int8_t* buffer, int32_t* size)
350 int s = (int) sck->priv;
351 struct sockaddr_in to;
354 if (VP_COM_DONTWAIT == sck->block)
355 flags |= MSG_DONTWAIT;
356 else if (VP_COM_WAITALL == sck->block)
357 flags |= MSG_WAITALL;
363 vp_os_memset( (char*)&to, 0, sizeof(to) );
364 to.sin_family = AF_INET;
365 to.sin_addr.s_addr = sck->scn;
366 if ( sck -> remotePort )
367 to.sin_port = htons(sck->remotePort);
369 to.sin_port = htons(sck->port);
371 *size = sendto( s, (char*)buffer, *size, flags, (struct sockaddr*)&to, sizeof(to) );
377 switch( WSAGetLastError() )
380 PRINT("MSG_NOSIGNAL is not supported on this platform\n");
391 PRINT("Connection with peer is not enabled\n");
397 if( errno == EAGAIN )
406 PRINT("MSG_NOSIGNAL is not supported on this platform\n");
412 PRINT("Connection with peer is not enabled\n");
416 PRINT("sendto fails with error: %d - %s\n", errno, strerror(errno));
422 #endif // USE_MINGW32
433 C_RESULT vp_com_read_socket(vp_com_socket_t* socket, int8_t* buffer, int32_t* size)
436 int s = (int) socket->priv;
439 if (VP_COM_DONTWAIT == socket->block)
440 flags |= MSG_DONTWAIT;
441 else if (VP_COM_WAITALL == socket->block)
442 flags |= MSG_WAITALL;
447 *size = recv(s, buffer, *size, flags);
450 if( errno == EAGAIN )
468 C_RESULT vp_com_write_socket(vp_com_socket_t* socket, const int8_t* buffer, int32_t* size)
471 int s = (int) socket->priv;
474 if (VP_COM_DONTWAIT == socket->block)
475 flags |= MSG_DONTWAIT;
476 else if (VP_COM_WAITALL == socket->block)
477 flags |= MSG_WAITALL;
482 *size = send(s, buffer, *size, flags);
485 if( errno == EAGAIN )
505 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
507 static vp_os_mutex_t server_initialisation_mutex;
508 static vp_os_cond_t server_initialisation_wait;
509 static bool_t server_init_not_finished = FALSE;
511 C_RESULT vp_com_init_server(void)
513 server_init_not_finished = TRUE;
514 vp_os_mutex_init(&server_initialisation_mutex);
515 vp_os_cond_init(&server_initialisation_wait, &server_initialisation_mutex);
520 C_RESULT vp_com_wait_for_server_up(void)
522 if( server_init_not_finished )
524 vp_os_mutex_lock(&server_initialisation_mutex);
525 vp_os_cond_wait(&server_initialisation_wait);
526 vp_os_mutex_unlock(&server_initialisation_mutex);
532 C_RESULT vp_com_timed_wait_for_server_up(uint32_t ms)
536 if( server_init_not_finished )
538 vp_os_mutex_lock(&server_initialisation_mutex);
539 res = vp_os_cond_timed_wait(&server_initialisation_wait, ms);
540 vp_os_mutex_unlock(&server_initialisation_mutex);
546 extern int32_t vp_com_fill_read_fs(vp_com_socket_t* sockets, int32_t num_sockets, int32_t max, fd_set* read_fs );
547 extern void vp_com_close_client_sockets(vp_com_socket_t* client_sockets, int32_t num_client_sockets);
548 extern C_RESULT vp_com_client_open_socket(vp_com_socket_t* server_socket, vp_com_socket_t* client_socket);
549 extern void vp_com_client_receive( vp_com_socket_t *client_socket );
551 DEFINE_THREAD_ROUTINE_STACK( vp_com_server, thread_params, VP_COM_THREAD_SERVER_STACK_SIZE )
554 vp_com_socket_t client_sockets[VP_COM_THREAD_NUM_MAX_CLIENTS];
555 struct timeval tv, *ptv;
557 // This thread setup connection then loop & wait for a socket event
558 vp_com_server_thread_param_t* params = (vp_com_server_thread_param_t*) thread_params;
560 int32_t i, rc, ncs, s, max = 0, num_server_sockets = params->num_servers, num_client_sockets = 0;
561 vp_com_socket_t* server_sockets = params->servers;
564 vp_os_memset( client_sockets, 0, sizeof( client_sockets ));
566 if(FAILED(vp_com_init(params->com)))
568 DEBUG_PRINT_SDK("[VP_COM_SERVER] Failed to init com\n");
569 vp_com_shutdown(params->com);
571 else if(FAILED(vp_com_local_config(params->com, params->config)))
573 DEBUG_PRINT_SDK("[VP_COM_SERVER] Failed to configure com\n");
574 vp_com_shutdown(params->com);
576 else if(FAILED(vp_com_connect(params->com, params->connection, 1)))
578 DEBUG_PRINT_SDK("[VP_COM_SERVER] Failed to connect\n");
579 vp_com_shutdown(params->com);
583 vp_os_mutex_lock(&server_initialisation_mutex);
584 vp_os_cond_signal(&server_initialisation_wait);
585 vp_os_mutex_unlock(&server_initialisation_mutex);
587 server_init_not_finished = FALSE;
589 for( i = 0; i < num_server_sockets; i++ )
591 if(FAILED( vp_com_open_socket(&server_sockets[i], NULL, NULL) ))
593 DEBUG_PRINT_SDK("[VP_COM_SERVER] Unable to open server socket\n");
594 server_sockets[i].is_disable = TRUE;
598 listen((int32_t)server_sockets[i].priv, server_sockets[i].queue_length);
604 while( params->run == TRUE )
606 if( params->timer_enable == FALSE || ( params->wait_sec == 0 && params->wait_usec == 0 ) )
612 tv.tv_sec = params->wait_sec;
613 tv.tv_usec = params->wait_usec;
618 max = vp_com_fill_read_fs( &server_sockets[0], num_server_sockets, 0, &read_fs );
619 max = vp_com_fill_read_fs( &client_sockets[0], num_client_sockets, max, &read_fs );
621 rc = select( max + 1, &read_fs, NULL, NULL, ptv );
622 if( rc == -1 && ( errno == EINTR || errno == EAGAIN ) )
627 DEBUG_PRINT_SDK("[VP_COM_SERVER] select timeout\n");
629 vp_com_close_client_sockets(&client_sockets[0], num_client_sockets);
630 num_client_sockets = 0;
632 params->timer_enable = FALSE;
633 vp_os_memset( client_sockets, 0, sizeof( client_sockets ));
636 for( i = 0; i < num_server_sockets && rc != 0; i++ )
638 s = (int32_t) server_sockets[i].priv;
640 if( ( !server_sockets[i].is_disable ) && FD_ISSET( s, &read_fs) )
644 // Recycle previously released sockets
645 for( ncs = 0; ncs < num_client_sockets && client_sockets[ncs].priv != NULL; ncs++ );
647 if( ncs < VP_COM_THREAD_NUM_MAX_CLIENTS)
649 if( SUCCEED(vp_com_client_open_socket(&server_sockets[i], &client_sockets[ncs])) && ( ncs == num_client_sockets ) )
650 num_client_sockets ++;
655 for( i = 0; i < num_client_sockets && rc != 0; i++ )
657 s = (int32_t) client_sockets[i].priv;
658 if( ( !client_sockets[i].is_disable ) && FD_ISSET( s, &read_fs) )
662 vp_com_client_receive( &client_sockets[i] );
667 for( i = 0; i < num_server_sockets; i++ )
669 vp_com_close_socket(&server_sockets[i]);
673 vp_com_disconnect(params->com);
674 vp_com_shutdown(params->com);