379 lines
13 KiB
C++
379 lines
13 KiB
C++
/*
|
|
Copyright (C) 2004-2008 Grame
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#include "JackError.h"
|
|
#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;
|
|
}
|
|
|
|
win_net_error_t 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;
|
|
}
|
|
|
|
bool JackNetWinSocket::IsLocal(char* ip)
|
|
{
|
|
if (strcmp(ip, "127.0.0.1") == 0) {
|
|
return true;
|
|
}
|
|
|
|
char host_name[32];
|
|
gethostname(host_name, sizeof(host_name));
|
|
|
|
struct hostent* host = gethostbyname(host_name);
|
|
if (host) {
|
|
for (int i = 0; host->h_addr_list[i] != 0; ++i) {
|
|
struct in_addr addr;
|
|
memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
|
|
if (strcmp(inet_ntoa(addr), ip) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int JackNetWinSocket::Bind()
|
|
{
|
|
return bind(fSockfd, reinterpret_cast<SOCKADDR*>(&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<SOCKADDR*>(&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<const char*>(optval), optlen);
|
|
}
|
|
|
|
int JackNetWinSocket::GetOption(int level, int optname, void* optval, SOCKLEN* optlen)
|
|
{
|
|
return getsockopt(fSockfd, level, optname, static_cast<char*>(optval), optlen);
|
|
}
|
|
|
|
//timeout************************************************************************************************************
|
|
int JackNetWinSocket::SetTimeOut(int usec)
|
|
{
|
|
jack_log("JackNetWinSocket::SetTimeout %d usec", usec);
|
|
int millisec = usec / 1000;
|
|
return SetOption(SOL_SOCKET, SO_RCVTIMEO, &millisec, sizeof(millisec));
|
|
}
|
|
|
|
//local loop*********************************************************************************************************
|
|
int JackNetWinSocket::SetLocalLoop()
|
|
{
|
|
//char disable = 0;
|
|
/*
|
|
see http://msdn.microsoft.com/en-us/library/aa916098.aspx
|
|
Default value is TRUE. When TRUE, data that is sent from the local interface to the multicast group to
|
|
which the socket is joined, including data sent from the same socket, will be echoed to its receive buffer.
|
|
*/
|
|
char disable = 1;
|
|
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<const char*>(buffer), nbytes, flags, reinterpret_cast<SOCKADDR*>(&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);
|
|
fSendAddr.sin_port = htons(fPort);
|
|
return SendTo(buffer, nbytes, flags);
|
|
}
|
|
|
|
int JackNetWinSocket::Send(const void* buffer, size_t nbytes, int flags)
|
|
{
|
|
return send(fSockfd, reinterpret_cast<const char*>(buffer), nbytes, flags);
|
|
}
|
|
|
|
int JackNetWinSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
|
|
{
|
|
SOCKLEN addr_len = sizeof(SOCKADDR);
|
|
return recvfrom(fSockfd, reinterpret_cast<char*>(buffer), nbytes, flags, reinterpret_cast<SOCKADDR*>(&fRecvAddr), &addr_len);
|
|
}
|
|
|
|
int JackNetWinSocket::Recv(void* buffer, size_t nbytes, int flags)
|
|
{
|
|
return recv(fSockfd, reinterpret_cast<char*>(buffer), nbytes, flags);
|
|
}
|
|
|
|
int JackNetWinSocket::CatchHost(void* buffer, size_t nbytes, int flags)
|
|
{
|
|
SOCKLEN addr_len = sizeof(SOCKADDR);
|
|
return recvfrom(fSockfd, reinterpret_cast<char*>(buffer), nbytes, flags, reinterpret_cast<SOCKADDR*>(&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;
|
|
}
|
|
}
|
|
}
|
|
|