Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "Socket.h"
00011 #include <cstring>
00012 #include <cerrno>
00013 #include <fcntl.h>
00014 #include <iostream>
00015 #include <stdio.h>
00016 #include <sstream>
00017 #include <SocketException.h>
00018
00019 #include <ros/ros.h>
00020
00021 UdpMulticastSocket::UdpMulticastSocket( const int local_port, const std::string multicast_ip )
00022 {
00023
00024 ROS_INFO( "Creating socket..." );
00025 m_socket = socket( AF_INET, SOCK_DGRAM, 0 );
00026 if( m_socket < 0 )
00027 throw SocketException( strerror( errno ) );
00028
00029
00030 ROS_INFO( "Setting socket options..." );
00031 int option_value = 1;
00032 int result = setsockopt( m_socket, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value, sizeof( int ) );
00033 if( result == -1 )
00034 {
00035 std::stringstream error;
00036 error << "Failed to set socket option: ";
00037 switch( errno )
00038 {
00039 case EBADF:
00040 error << "EBADF";
00041 break;
00042 case EFAULT:
00043 error << "EFAULT";
00044 break;
00045 case EINVAL:
00046 error << "EINVAL";
00047 break;
00048 case ENOPROTOOPT:
00049 error << "ENOPROTOOPT";
00050 break;
00051 case ENOTSOCK:
00052 error << "ENOTSOCK";
00053 break;
00054 default:
00055 error << "unknown error";
00056 break;
00057 }
00058 throw SocketException( error.str().c_str() );
00059 }
00060
00061
00062 memset ( &m_local_addr, 0, sizeof ( m_local_addr ) );
00063 m_local_addr.sin_family = AF_INET;
00064 m_local_addr.sin_addr.s_addr = htonl( INADDR_ANY );
00065 m_local_addr.sin_port = htons( local_port );
00066 ROS_INFO( "Local address: %s:%i", inet_ntoa( m_local_addr.sin_addr ), ntohs( m_local_addr.sin_port ) );
00067
00068
00069 ROS_INFO( "Binding socket to local address..." );
00070 result = bind( m_socket, (sockaddr*)&m_local_addr, sizeof( m_local_addr ) );
00071 if( result == -1 )
00072 {
00073 std::stringstream error;
00074 error << "Failed to bind socket to local address:" << strerror( errno );
00075 throw SocketException( error.str().c_str() );
00076 }
00077
00078
00079 struct ip_mreq mreq;
00080 mreq.imr_multiaddr.s_addr = inet_addr( multicast_ip.c_str() );
00081 mreq.imr_interface = m_local_addr.sin_addr;
00082 ROS_INFO( "Joining multicast group %s...", inet_ntoa( mreq.imr_multiaddr ) );
00083
00084 result = setsockopt(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
00085 if( result == -1 )
00086 {
00087 std::stringstream error;
00088 error << "Failed to set socket option: ";
00089 switch( errno )
00090 {
00091 case EBADF:
00092 error << "EBADF";
00093 break;
00094 case EFAULT:
00095 error << "EFAULT";
00096 break;
00097 case EINVAL:
00098 error << "EINVAL";
00099 break;
00100 case ENOPROTOOPT:
00101 error << "ENOPROTOOPT";
00102 break;
00103 case ENOTSOCK:
00104 error << "ENOTSOCK";
00105 break;
00106 default:
00107 error << "unknown error";
00108 break;
00109 }
00110 throw SocketException( error.str().c_str() );
00111 }
00112
00113
00114 ROS_INFO( "Enabling non-blocking I/O" );
00115 int flags = fcntl( m_socket, F_GETFL , 0 );
00116 result = fcntl(m_socket, F_SETFL, flags | O_NONBLOCK);
00117 if( result == -1 )
00118 {
00119 std::stringstream error;
00120 error << "Failed to enable non-blocking I/O: " << strerror( errno );
00121 throw SocketException( error.str().c_str() );
00122 }
00123 }
00124
00125 UdpMulticastSocket::~UdpMulticastSocket()
00126 {
00127 close( m_socket );
00128 }
00129
00130 int UdpMulticastSocket::recv()
00131 {
00132 memset ( buf, 0, MAXRECV + 1 );
00133
00134 sockaddr_in remote_addr;
00135 int addr_len = sizeof(struct sockaddr);
00136 int status = recvfrom(
00137 m_socket,
00138 buf,
00139 MAXRECV,
00140 0,
00141 (sockaddr *)&remote_addr,
00142 (socklen_t*)&addr_len);
00143
00144 if( status > 0 )
00145 ROS_INFO( "%4i bytes received from %s:%i", status, inet_ntoa( remote_addr.sin_addr ), ntohs( remote_addr.sin_port ) );
00146 else if( status == 0 )
00147 ROS_INFO( "Connection closed by peer" );
00148
00149 return status;
00150 }