X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fmidi%2B%2B2%2Fipmidi_port.cc;h=fd5cb9a2395e727a457dda57104038439ea0429b;hb=5eacf424b6cd5d68e1d5d25e587a46ea7df905ce;hp=4c0282f1f757a40e32cca91106a43c3d11108e26;hpb=fb313fb1741a04f270fff3703967df572ac4fc45;p=ardour.git diff --git a/libs/midi++2/ipmidi_port.cc b/libs/midi++2/ipmidi_port.cc index 4c0282f1f7..fd5cb9a239 100644 --- a/libs/midi++2/ipmidi_port.cc +++ b/libs/midi++2/ipmidi_port.cc @@ -2,7 +2,7 @@ Copyright (C) 2012 Paul Davis Using code from Rui Nuno Capela's qmidinet as inspiration. - + 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 @@ -31,12 +31,12 @@ #endif #if defined(PLATFORM_WINDOWS) #include +#include #else #include #endif #if defined(PLATFORM_WINDOWS) -static WSADATA g_wsaData; typedef int socklen_t; #else #include @@ -44,9 +44,6 @@ typedef int socklen_t; inline void closesocket(int s) { ::close(s); } #endif -#include -#include - #include "pbd/xml++.h" #include "pbd/error.h" #include "pbd/failed_constructor.h" @@ -85,8 +82,8 @@ IPMIDIPort::~IPMIDIPort () int IPMIDIPort::selectable () const -{ - return sockin; +{ + return sockin; } XMLNode& @@ -108,19 +105,19 @@ IPMIDIPort::close_sockets () ::closesocket (sockin); sockin = -1; } - + if (sockout >= 0) { ::closesocket (sockout); sockout = -1; } } -static bool +#ifndef PLATFORM_WINDOWS +static bool get_address (int sock, struct in_addr *inaddr, const string& ifname ) { // Get interface address from supplied name. -#if !defined(PLATFORM_WINDOWS) struct ifreq ifr; ::strncpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name)); @@ -144,18 +141,12 @@ get_address (int sock, struct in_addr *inaddr, const string& ifname ) inaddr->s_addr = sa.sin_addr.s_addr; return true; - -#else - - return false; - -#endif // !PLATFORM_WINDOWS' } +#endif bool IPMIDIPort::open_sockets (int base_port, const string& ifname) { -#if !defined(PLATFORM_WINDOWS) int protonum = 0; struct protoent *proto = ::getprotobyname("IP"); @@ -174,16 +165,17 @@ IPMIDIPort::open_sockets (int base_port, const string& ifname) addrin.sin_family = AF_INET; addrin.sin_addr.s_addr = htonl(INADDR_ANY); addrin.sin_port = htons(base_port); - + if (::bind(sockin, (struct sockaddr *) (&addrin), sizeof(addrin)) < 0) { ::perror("bind"); return false; } - + // Will Hall, 2007 // INADDR_ANY will bind to default interface, // specify alternate interface nameon which to bind... struct in_addr if_addr_in; +#ifndef PLATFORM_WINDOWS if (!ifname.empty()) { if (!get_address(sockin, &if_addr_in, ifname)) { error << string_compose ("socket(in): could not find interface address for %1", ifname) << endmsg; @@ -197,9 +189,12 @@ IPMIDIPort::open_sockets (int base_port, const string& ifname) } else { if_addr_in.s_addr = htonl (INADDR_ANY); } - +#else + if_addr_in.s_addr = htonl (INADDR_ANY); +#endif + struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = ::inet_addr("225.0.0.37"); + mreq.imr_multiaddr.s_addr = ::inet_addr("225.0.0.37"); /* ipMIDI group multicast address */ mreq.imr_interface.s_addr = if_addr_in.s_addr; if(::setsockopt (sockin, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) < 0) { ::perror("setsockopt(IP_ADD_MEMBERSHIP)"); @@ -215,8 +210,9 @@ IPMIDIPort::open_sockets (int base_port, const string& ifname) ::perror("socket(out)"); return false; } - + // Will Hall, Oct 2007 +#ifndef PLATFORM_WINDOWS if (!ifname.empty()) { struct in_addr if_addr_out; if (!get_address(sockout, &if_addr_out, ifname)) { @@ -228,19 +224,52 @@ IPMIDIPort::open_sockets (int base_port, const string& ifname) return false; } } - +#endif + ::memset(&addrout, 0, sizeof(struct sockaddr_in)); addrout.sin_family = AF_INET; addrout.sin_addr.s_addr = ::inet_addr("225.0.0.37"); addrout.sin_port = htons (base_port); - + // Turn off loopback... int loop = 0; - if (::setsockopt(sockout, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &loop, sizeof (loop)) < 0) { + +#ifdef PLATFORM_WINDOWS + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms739161%28v=vs.85%29.aspx + * + * ------------------------------------------------------------------------------ + * Note The Winsock version of the IP_MULTICAST_LOOP option is + * semantically different than the UNIX version of the + * IP_MULTICAST_LOOP option: + * + * In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path. + * In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path. + * + * For example, applications ON and OFF (which are easier to track than + * X and Y) join the same group on the same interface; application ON + * sets the IP_MULTICAST_LOOP option on, application OFF sets the + * IP_MULTICAST_LOOP option off. If ON and OFF are Winsock + * applications, OFF can send to ON, but ON cannot sent to OFF. In + * contrast, if ON and OFF are UNIX applications, ON can send to OFF, + * but OFF cannot send to ON. + * ------------------------------------------------------------------------------ + * + * Alles klar? Gut! + */ + + const int target_sock = sockin; +#else + const int target_sock = sockout; +#endif + + if (::setsockopt (target_sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &loop, sizeof (loop)) < 0) { ::perror("setsockopt(IP_MULTICAST_LOOP)"); return false; } +#ifndef PLATFORM_WINDOWS + if (fcntl (sockin, F_SETFL, O_NONBLOCK)) { error << "cannot set non-blocking mode for IP MIDI input socket (" << ::strerror (errno) << ')' << endmsg; return false; @@ -250,11 +279,22 @@ IPMIDIPort::open_sockets (int base_port, const string& ifname) error << "cannot set non-blocking mode for IP MIDI output socket (" << ::strerror (errno) << ')' << endmsg; return false; } - - return true; + #else - return false; -#endif // !PLATFORM_WINDOWS' + // If imode !=0, non-blocking mode is enabled. + u_long mode=1; + if (ioctlsocket(sockin,FIONBIO,&mode)) { + error << "cannot set non-blocking mode for IP MIDI input socket (" << ::strerror (errno) << ')' << endmsg; + return false; + } + mode = 1; /* just in case it was modified in the previous call */ + if (ioctlsocket(sockout,FIONBIO,&mode)) { + error << "cannot set non-blocking mode for IP MIDI output socket (" << ::strerror (errno) << ')' << endmsg; + return false; + } +#endif + + return true; } int @@ -285,7 +325,7 @@ IPMIDIPort::parse (framecnt_t timestamp) * parser. This will emit appropriate signals that will be handled * by anyone who cares. */ - + unsigned char buf[1024]; struct sockaddr_in sender; socklen_t slen = sizeof(sender); @@ -294,7 +334,7 @@ IPMIDIPort::parse (framecnt_t timestamp) if (r >= 0) { _parser->set_timestamp (timestamp); - + for (int i = 0; i < r; ++i) { _parser->scanner (buf[i]); } @@ -302,4 +342,3 @@ IPMIDIPort::parse (framecnt_t timestamp) ::perror ("failed to recv from socket"); } } -