/* Copyright (C) 2008 Romain Moret at Grame This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "JackNetWinSocket.h" namespace Jack { //utility ********************************************************************************************************* SERVER_EXPORT int GetHostName ( char * name, int size ) { if ( gethostname ( name, size ) == SOCKET_ERROR ) { jack_error ( "Can't get 'hostname' : %s", strerror ( NET_ERROR_CODE ) ); strcpy ( name, "default" ); return -1; } return 0; } struct { int code; char* msg; } NetErrorList[] = { E ( 0, "No error" ), E ( WSAEINTR, "Interrupted system call" ), E ( WSAEBADF, "Bad file number" ), E ( WSAEACCES, "Permission denied" ), E ( WSAEFAULT, "Bad address" ), E ( WSAEINVAL, "Invalid argument" ), E ( WSAEMFILE, "Too many open sockets" ), E ( WSAEWOULDBLOCK, "Operation would block" ), E ( WSAEINPROGRESS, "Operation now in progress" ), E ( WSAEALREADY, "Operation already in progress" ), E ( WSAENOTSOCK, "Socket operation on non-socket" ), E ( WSAEDESTADDRREQ, "Destination address required" ), E ( WSAEMSGSIZE, "Message too long" ), E ( WSAEPROTOTYPE, "Protocol wrong type for socket" ), E ( WSAENOPROTOOPT, "Bad protocol option" ), E ( WSAEPROTONOSUPPORT, "Protocol not supported" ), E ( WSAESOCKTNOSUPPORT, "Socket type not supported" ), E ( WSAEOPNOTSUPP, "Operation not supported on socket" ), E ( WSAEPFNOSUPPORT, "Protocol family not supported" ), E ( WSAEAFNOSUPPORT, "Address family not supported" ), E ( WSAEADDRINUSE, "Address already in use" ), E ( WSAEADDRNOTAVAIL, "Can't assign requested address" ), E ( WSAENETDOWN, "Network is down" ), E ( WSAENETUNREACH, "Network is unreachable" ), E ( WSAENETRESET, "Net connection reset" ), E ( WSAECONNABORTED, "Software caused connection abort" ), E ( WSAECONNRESET, "Connection reset by peer" ), E ( WSAENOBUFS, "No buffer space available" ), E ( WSAEISCONN, "Socket is already connected" ), E ( WSAENOTCONN, "Socket is not connected" ), E ( WSAESHUTDOWN, "Can't send after socket shutdown" ), E ( WSAETOOMANYREFS, "Too many references, can't splice" ), E ( WSAETIMEDOUT, "Connection timed out" ), E ( WSAECONNREFUSED, "Connection refused" ), E ( WSAELOOP, "Too many levels of symbolic links" ), E ( WSAENAMETOOLONG, "File name too long" ), E ( WSAEHOSTDOWN, "Host is down" ), E ( WSAEHOSTUNREACH, "No route to host" ), E ( WSAENOTEMPTY, "Directory not empty" ), E ( WSAEPROCLIM, "Too many processes" ), E ( WSAEUSERS, "Too many users" ), E ( WSAEDQUOT, "Disc quota exceeded" ), E ( WSAESTALE, "Stale NFS file handle" ), E ( WSAEREMOTE, "Too many levels of remote in path" ), E ( WSASYSNOTREADY, "Network system is unavailable" ), E ( WSAVERNOTSUPPORTED, "Winsock version out of range" ), E ( WSANOTINITIALISED, "WSAStartup not yet called" ), E ( WSAEDISCON, "Graceful shutdown in progress" ), E ( WSAHOST_NOT_FOUND, "Host not found" ), E ( WSANO_DATA, "No host data of that type was found" ), { -1, NULL }, }; SERVER_EXPORT const char* PrintError ( int error ) { int i; for ( i = 0; NetErrorList[i].code >= 0; ++i ) { if ( error == NetErrorList[i].code ) return NetErrorList[i].msg; } return strerror ( error ); } //construct/destruct*********************************************************************************************** JackNetWinSocket::JackNetWinSocket() { fSockfd = 0; fSendAddr.sin_family = AF_INET; fSendAddr.sin_addr.s_addr = htonl ( INADDR_ANY ); memset ( &fSendAddr.sin_zero, 0, 8 ); fRecvAddr.sin_family = AF_INET; fRecvAddr.sin_addr.s_addr = htonl ( INADDR_ANY ); memset ( &fRecvAddr.sin_zero, 0, 8 ); } JackNetWinSocket::JackNetWinSocket ( const char* ip, int port ) { fSockfd = 0; fPort = port; fSendAddr.sin_family = AF_INET; fSendAddr.sin_port = htons ( port ); fSendAddr.sin_addr.s_addr = inet_addr ( ip ); memset ( &fSendAddr.sin_zero, 0, 8 ); fRecvAddr.sin_family = AF_INET; fRecvAddr.sin_port = htons ( port ); fRecvAddr.sin_addr.s_addr = htonl ( INADDR_ANY ); memset ( &fRecvAddr.sin_zero, 0, 8 ); } JackNetWinSocket::JackNetWinSocket ( const JackNetWinSocket& socket ) { fSockfd = 0; fPort = socket.fPort; fSendAddr = socket.fSendAddr; fRecvAddr = socket.fRecvAddr; } JackNetWinSocket::~JackNetWinSocket() { Close(); } JackNetWinSocket& JackNetWinSocket::operator= ( const JackNetWinSocket& socket ) { if ( this != &socket ) { fSockfd = 0; fPort = socket.fPort; fSendAddr = socket.fSendAddr; fRecvAddr = socket.fRecvAddr; } return *this; } //socket*********************************************************************************************************** int JackNetWinSocket::NewSocket() { if ( fSockfd ) { Close(); Reset(); } fSockfd = socket ( AF_INET, SOCK_DGRAM, 0 ); return fSockfd; } int JackNetWinSocket::Bind() { return bind ( fSockfd, reinterpret_cast ( &fRecvAddr ), sizeof ( SOCKADDR ) ); } int JackNetWinSocket::BindWith ( const char* ip ) { fRecvAddr.sin_addr.s_addr = inet_addr ( ip ); return Bind(); } int JackNetWinSocket::BindWith ( int port ) { fRecvAddr.sin_port = htons ( port ); return Bind(); } int JackNetWinSocket::Connect() { return connect ( fSockfd, reinterpret_cast ( &fSendAddr ), sizeof ( SOCKADDR ) ); } int JackNetWinSocket::ConnectTo ( const char* ip ) { fSendAddr.sin_addr.s_addr = inet_addr ( ip ); return Connect(); } void JackNetWinSocket::Close() { if ( fSockfd ) closesocket ( fSockfd ); fSockfd = 0; } void JackNetWinSocket::Reset() { fSendAddr.sin_family = AF_INET; fSendAddr.sin_port = htons ( fPort ); fSendAddr.sin_addr.s_addr = htonl ( INADDR_ANY ); memset ( &fSendAddr.sin_zero, 0, 8 ); fRecvAddr.sin_family = AF_INET; fRecvAddr.sin_port = htons ( fPort ); fRecvAddr.sin_addr.s_addr = htonl ( INADDR_ANY ); memset ( &fRecvAddr.sin_zero, 0, 8 ); } bool JackNetWinSocket::IsSocket() { return ( fSockfd ) ? true : false; } //IP/PORT*********************************************************************************************************** void JackNetWinSocket::SetPort ( int port ) { fPort = port; fSendAddr.sin_port = htons ( port ); fRecvAddr.sin_port = htons ( port ); } int JackNetWinSocket::GetPort() { return fPort; } //address*********************************************************************************************************** int JackNetWinSocket::SetAddress ( const char* ip, int port ) { fSendAddr.sin_addr.s_addr = inet_addr ( ip ); fSendAddr.sin_port = htons ( port ); return 0; } char* JackNetWinSocket::GetSendIP() { return inet_ntoa ( fSendAddr.sin_addr ); } char* JackNetWinSocket::GetRecvIP() { return inet_ntoa ( fRecvAddr.sin_addr ); } //utility************************************************************************************************************ int JackNetWinSocket::GetName ( char* name ) { return gethostname ( name, 255 ); } int JackNetWinSocket::JoinMCastGroup ( const char* ip ) { struct ip_mreq multicast_req; multicast_req.imr_multiaddr.s_addr = inet_addr ( ip ); multicast_req.imr_interface.s_addr = htonl ( INADDR_ANY ); //12 is IP_ADD_MEMBERSHIP in winsock2 (differs from winsock1...) return SetOption ( IPPROTO_IP, 12, &multicast_req, sizeof ( multicast_req ) ); } //options************************************************************************************************************ int JackNetWinSocket::SetOption ( int level, int optname, const void* optval, SOCKLEN optlen ) { return setsockopt ( fSockfd, level, optname, static_cast ( optval ), optlen ); } int JackNetWinSocket::GetOption ( int level, int optname, void* optval, SOCKLEN* optlen ) { return getsockopt ( fSockfd, level, optname, static_cast ( optval ), optlen ); } //tiemout************************************************************************************************************ int JackNetWinSocket::SetTimeOut ( int usec ) { jack_log ( "JackNetWinSocket::SetTimeout %d usec", usec ); //negative timeout, or exceeding 10s, return if ( ( usec < 0 ) || ( usec > 10000000 ) ) return SOCKET_ERROR; int time = usec / 1000; return SetOption ( SOL_SOCKET, SO_RCVTIMEO, &time, sizeof ( time ) ); } //local loop********************************************************************************************************* int JackNetWinSocket::SetLocalLoop() { char disable = 0; return SetOption ( IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof ( disable ) ); } //network operations************************************************************************************************* int JackNetWinSocket::SendTo ( const void* buffer, size_t nbytes, int flags ) { return sendto ( fSockfd, reinterpret_cast ( buffer ), nbytes, flags, reinterpret_cast ( &fSendAddr ), sizeof ( SOCKADDR ) ); } int JackNetWinSocket::SendTo ( const void* buffer, size_t nbytes, int flags, const char* ip ) { fSendAddr.sin_addr.s_addr = inet_addr ( ip ); return SendTo ( buffer, nbytes, flags ); } int JackNetWinSocket::Send ( const void* buffer, size_t nbytes, int flags ) { return send ( fSockfd, reinterpret_cast ( buffer ), nbytes, flags ); } int JackNetWinSocket::RecvFrom ( void* buffer, size_t nbytes, int flags ) { SOCKLEN addr_len = sizeof ( SOCKADDR ); return recvfrom ( fSockfd, reinterpret_cast ( buffer ), nbytes, flags, reinterpret_cast ( &fRecvAddr ), &addr_len ); } int JackNetWinSocket::Recv ( void* buffer, size_t nbytes, int flags ) { return recv ( fSockfd, reinterpret_cast ( buffer ), nbytes, flags ); } int JackNetWinSocket::CatchHost ( void* buffer, size_t nbytes, int flags ) { SOCKLEN addr_len = sizeof ( SOCKADDR ); return recvfrom ( fSockfd, reinterpret_cast ( buffer ), nbytes, flags, reinterpret_cast ( &fSendAddr ), &addr_len ); } net_error_t JackNetWinSocket::GetError() { switch ( NET_ERROR_CODE ) { case WSABASEERR: return NET_NO_ERROR; case WSAETIMEDOUT: return NET_NO_DATA; case WSAEWOULDBLOCK: return NET_NO_DATA; case WSAECONNREFUSED: return NET_CONN_ERROR; case WSAECONNRESET: return NET_CONN_ERROR; case WSAEACCES: return NET_CONN_ERROR; case WSAECONNABORTED: return NET_CONN_ERROR; case WSAEHOSTDOWN: return NET_CONN_ERROR; case WSAEHOSTUNREACH: return NET_CONN_ERROR; default: return NET_OP_ERROR; } } }