<commit_before>/* bzflag
 * Copyright (c) 1993 - 2001 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "multicast.h"
#include "ErrorHandler.h"

int			openBroadcast(int port, const char* service,
					struct sockaddr_in* addr)
{
#if defined(_WIN32)
  const BOOL optOn = TRUE;
#else
  const int optOn = 1;
#endif
  int fd;

  /* check parameters */
  if (!addr) {
    printError("openBroadcast: Must supply a return address structure!");
    return -1;
  }
  memset(addr, 0, sizeof(*addr));

  /* lookup service and check port */
  if (service) {
    struct servent *sp = getservbyname(service, "udp");
    if (!sp) {
      if (port <= 0) {
	printError("openBroadcast: No udp service %s", service);
	return -1;
      }
    }
    else {
      port = sp->s_port;
    }
  }
  if (port <= 0) {
    printError("openBroadcast: Invalid port %s", port);
    return -1;
  }

  /* open socket */
  fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd < 0) {
    nerror("openBroadcast: socket");
    return -1;
  }

  /* set address info */
  addr->sin_family = AF_INET;
  addr->sin_addr.s_addr = htonl(INADDR_ANY);
  addr->sin_port = htons(port);

#if defined(SO_REUSEPORT)
  /* set reuse port */
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
    nerror("openBroadcast: setsockopt SO_REUSEPORT");
    close(fd);
    return -1;
  }
#elif defined(SO_REUSEADDR)
  /* set reuse address */
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
    nerror("openBroadcast: setsockopt SO_REUSEADDR");
    close(fd);
    return -1;
  }
#endif

  /* bind address */
  if (bind(fd, (const struct sockaddr*)addr, sizeof(*addr)) < 0) {
    nerror("openBroadcast: bind");
    close(fd);
    return -1;
  }

  /* make broadcast */
  if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
    nerror("openBroadcast: setsockopt SO_BROADCAST");
    close(fd);
    return -1;
  }

  // address to send to is the broadcast address
  addr->sin_addr.s_addr = INADDR_BROADCAST;

#if defined(__linux__)
  // linux doesn't seem to like INADDR_BROADCAST, but it's okay
  // with the broadcast address on the local network.  get the
  // broadcast address on the first interface that's not the
  // loopback interface.  (check the first numInterfaces
  // interfaces.)
  const int numInterfaces = 5;
  int i;
  struct ifconf conf;
  struct ifreq req[numInterfaces];

  // get the list of interface names
  conf.ifc_len = sizeof(req);
  conf.ifc_ifcu.ifcu_req = req;
  for (i = 0; i < numInterfaces; ++i)
    req[i].ifr_ifrn.ifrn_name[0] = 0;
  if (ioctl(fd, SIOCGIFCONF, &conf) < 0) {
    nerror("openBroadcast: getting interface list");
    close(fd);
    return(-1);
  }

  // get the broadcast address on each interface
  for (i = 0; i < numInterfaces; ++i) {
    // if no name then we're done
    if (req[i].ifr_ifrn.ifrn_name[0] == 0)
      break;

    // if we can't get the address then skip this interface
    if (ioctl(fd, SIOCGIFBRDADDR, req + i) < 0)
      continue;

    // if the address is the loopback broadcast address then skip it
    const sockaddr_in* ifbaddr = (const sockaddr_in*)
					&req[i].ifr_ifru.ifru_broadaddr;
    if (ntohl(ifbaddr->sin_addr.s_addr) == 0x7ffffffflu)
      continue;

    // got the broadcast address on the interface
    addr->sin_addr.s_addr = ifbaddr->sin_addr.s_addr;
    break;
  }

  // failed if no broadcast addresses found
  if (i == numInterfaces) {
    nerror("openBroadcast: getting broadcast address");
    close(fd);
    return(-1);
  }
#endif

  /* turn on non-blocking io */
  if (BzfNetwork::setNonBlocking(fd) < 0) {
    nerror("openBroadcast: setNonBlocking");
    close(fd);
    return(-1);
  }

  return fd;
}

int			openMulticast(const Address& address, int port,
					const char* service, int ttl,
					const char* net_interface,
					const char* mode,
					struct sockaddr_in* addr)
{
  struct ip_mreq mreq;
  struct in_addr ifaddr;
  int fd;
#if defined(_WIN32)
  const BOOL optOn = TRUE;
#else
  const int optOn = 1;
#endif

  /* check parameters */
  if (!addr) {
    printError("openMulticast: Must supply a return address structure!");
    return -1;
  }
  memset(addr, 0, sizeof(*addr));

  /* check mode */
  if (!mode || (mode[0] != 'r' && mode[0] != 'w')) {
    printError("openMulticast: Invalid mode");
    return -1;
  }

  /* lookup service and check port */
  if (service) {
    struct servent *sp = getservbyname(service, "udp");
    if (!sp) {
      if (port <= 0) {
	printError("openMulticast: No udp service %s", service);
	return -1;
      }
    }
    else {
      port = sp->s_port;
    }
  }
  if (port <= 0) {
    printError("openMulticast: Invalid port %s", port);
    return -1;
  }

  /* check group address */
  mreq.imr_multiaddr = InAddr(address);
  if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
    printError("openMulticast: Invalid multicast address");
    return -1;
  }

  /* open socket */
  fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd < 0) {
    nerror("openMulticast: socket");
    return -1;
  }

  /* check interface */
  if (net_interface && net_interface[0]) {
    ifaddr.s_addr = inet_addr(net_interface);
    if (ifaddr.s_addr == (unsigned long)-1) {
      struct hostent* hp = gethostbyname(net_interface);
      if (!hp) {
	printError("openMulticast: Can't get address of %s", net_interface);
	close(fd);
	return -1;
      }
      memcpy(&ifaddr, hp->h_addr, hp->h_length);
    }
    mreq.imr_interface = ifaddr;
  }
  else {
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

#if defined(__linux__)
    // linux doesn't seem to like INADDR_ANY as the interface.
    // find the first non-loopback interface and use that.
    // (only check the first numInterfaces interfaces.)
    const int numInterfaces = 5;
    int i;
    struct ifconf conf;
    struct ifreq req[numInterfaces];

    // get the list of interface names
    conf.ifc_len = sizeof(req);
    conf.ifc_ifcu.ifcu_req = req;
    for (i = 0; i < numInterfaces; ++i)
      req[i].ifr_ifrn.ifrn_name[0] = 0;
    if (ioctl(fd, SIOCGIFCONF, &conf) < 0) {
      nerror("openMulticast: getting interface list");
      close(fd);
      return(-1);
    }

    // get the address of each interface
    for (i = 0; i < numInterfaces; ++i) {
      // if no name then we're done
      if (req[i].ifr_ifrn.ifrn_name[0] == 0)
	break;

      // if we can't get the address then skip this interface
      if (ioctl(fd, SIOCGIFADDR, req + i) < 0)
	continue;

      // if the address is the loopback address then skip it
      const sockaddr_in* ifaddr = (const sockaddr_in*)
					&req[i].ifr_ifru.ifru_addr;
      if (ntohl(ifaddr->sin_addr.s_addr) == INADDR_LOOPBACK)
	continue;

      // got the address on the interface
      if (!net_interface || !net_interface[0])
	mreq.imr_interface.s_addr = ifaddr->sin_addr.s_addr;
      break;
    }
#endif
  }

  /* set address info */
  addr->sin_family = AF_INET;
  addr->sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
  addr->sin_port = htons(port);

  /* set options on socket */
  if (mode[0] == 'w') {
#if defined(_WIN32) || defined(__linux__) || defined(GUSI_20)
    /* windows requires socket to be bound before using multicast sockopts */
    /* linux requires that we bind to an interface's address to send */
    struct sockaddr_in tmpAddr;
    memset(&tmpAddr, 0, sizeof(tmpAddr));
    tmpAddr.sin_family = AF_INET;
    tmpAddr.sin_addr.s_addr = mreq.imr_interface.s_addr;
    tmpAddr.sin_port = 0;
    if (bind(fd, (const struct sockaddr*)&tmpAddr, sizeof(tmpAddr)) < 0) {
      nerror("openMulticast: bind");
      close(fd);
      return -1;
    }
#endif

    /* set ttl */
    if (setMulticastTTL(fd, ttl) < 0) {
      nerror("WARNING: openMulticast: setsockopt IP_MULTICAST_TTL");
      close(fd);
      return -1;
    }

    if (net_interface && net_interface[0] &&
		setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
		(SSOType)&ifaddr, sizeof(ifaddr)) < 0) {
      nerror("WARNING: openMulticast: Can't multicast on interface");
      close(fd);
      return -1;
    }
  }

  else {
#if defined(SO_REUSEPORT)
    /* set reuse port */
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
      nerror("WARNING: openMulticast: setsockopt SO_REUSEPORT");
      close(fd);
      return -1;
    }
#endif
#if defined(SO_REUSEADDR)
    /* set reuse address */
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
      nerror("WARNING: openMulticast: setsockopt SO_REUSEADDR");
      close(fd);
      return -1;
    }
#endif

    /* bind address */
#if defined(_WIN32)
    /* unlike linux, win32 requires that we bind to the ANY address */
    addr->sin_addr.s_addr = htonl(INADDR_ANY);
#endif
    if (bind(fd, (const struct sockaddr*)addr, sizeof(*addr)) < 0) {
      nerror("openMulticast: bind");
      close(fd);
      return -1;
    }

    /* join multicast group */
    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
				(SSOType)&mreq, sizeof(mreq)) < 0) {
      nerror("WARNING: openMulticast: Can't join multicast group");
      close(fd);
      return -1;
    }
  }

  /* turn on non-blocking io */
  if (BzfNetwork::setNonBlocking(fd) < 0) {
    nerror("openBroadcast: setNonBlocking");
    close(fd);
    return(-1);
  }

  return fd;
}

int			closeMulticast(int fd)
{
  if (fd == -1) return 0;
  return close(fd);
}

int			setMulticastTTL(int fd, int ttl)
{
#if defined(_WIN32)
  unsigned int opt = (unsigned int)ttl;
#else /* defined(_WIN32) */
  unsigned char opt = (unsigned char)ttl;
#endif /* defined(_WIN32) */
  return setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
				(SSOType)&opt, sizeof(opt));
}

int			sendMulticast(int fd, const void* buffer,
					int bufferLength,
					const struct sockaddr_in* addr)
{
  return sendto(fd, (const char*)buffer, bufferLength, 0,
				(const struct sockaddr*)addr, sizeof(*addr));
}

#if !defined(AddrLen)
#define AddrLen		int
#endif

int			recvMulticast(int fd, void* buffer, int bufferLength,
					 struct sockaddr_in* addr)
{
  struct sockaddr_in from;
  AddrLen fromLength = sizeof(from);

  int byteCount = recvfrom(fd, (char*)buffer, bufferLength, 0,
				(struct sockaddr*)&from, &fromLength);
  if (byteCount < 0) {
    if (getErrno() == EWOULDBLOCK) {
      return 0;
    }
    else {
      nerror("recvMulticast");
      return -1;
    }
  }
  if (addr) *addr = from;
  return byteCount;
}
<commit_msg>multicast is broken for now<commit_after>/* bzflag
 * Copyright (c) 1993 - 2001 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "multicast.h"
#include "ErrorHandler.h"

int			openBroadcast(int port, const char* service,
					struct sockaddr_in* addr)
{
#if defined(_WIN32)
  const BOOL optOn = TRUE;
#else
  const int optOn = 1;
#endif
  int fd;

  /* check parameters */
  if (!addr) {
    printError("openBroadcast: Must supply a return address structure!");
    return -1;
  }
  memset(addr, 0, sizeof(*addr));

  /* lookup service and check port */
  if (service) {
    struct servent *sp = getservbyname(service, "udp");
    if (!sp) {
      if (port <= 0) {
	printError("openBroadcast: No udp service %s", service);
	return -1;
      }
    }
    else {
      port = sp->s_port;
    }
  }
  if (port <= 0) {
    printError("openBroadcast: Invalid port %s", port);
    return -1;
  }

  /* open socket */
  fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd < 0) {
    nerror("openBroadcast: socket");
    return -1;
  }

  /* set address info */
  addr->sin_family = AF_INET;
  addr->sin_addr.s_addr = htonl(INADDR_ANY);
  addr->sin_port = htons(port);

#if defined(SO_REUSEPORT)
  /* set reuse port */
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
    nerror("openBroadcast: setsockopt SO_REUSEPORT");
    close(fd);
    return -1;
  }
#elif defined(SO_REUSEADDR)
  /* set reuse address */
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
    nerror("openBroadcast: setsockopt SO_REUSEADDR");
    close(fd);
    return -1;
  }
#endif

  /* bind address */
  if (bind(fd, (const struct sockaddr*)addr, sizeof(*addr)) < 0) {
    nerror("openBroadcast: bind");
    close(fd);
    return -1;
  }

  /* make broadcast */
  if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
    nerror("openBroadcast: setsockopt SO_BROADCAST");
    close(fd);
    return -1;
  }

  // address to send to is the broadcast address
  addr->sin_addr.s_addr = INADDR_BROADCAST;

#if defined(__linux__)
  // linux doesn't seem to like INADDR_BROADCAST, but it's okay
  // with the broadcast address on the local network.  get the
  // broadcast address on the first interface that's not the
  // loopback interface.  (check the first numInterfaces
  // interfaces.)
  const int numInterfaces = 5;
  int i;
  struct ifconf conf;
  struct ifreq req[numInterfaces];

  // get the list of interface names
  conf.ifc_len = sizeof(req);
  conf.ifc_ifcu.ifcu_req = req;
  for (i = 0; i < numInterfaces; ++i)
    req[i].ifr_ifrn.ifrn_name[0] = 0;
  if (ioctl(fd, SIOCGIFCONF, &conf) < 0) {
    nerror("openBroadcast: getting interface list");
    close(fd);
    return(-1);
  }

  // get the broadcast address on each interface
  for (i = 0; i < numInterfaces; ++i) {
    // if no name then we're done
    if (req[i].ifr_ifrn.ifrn_name[0] == 0)
      break;

    // if we can't get the address then skip this interface
    if (ioctl(fd, SIOCGIFBRDADDR, req + i) < 0)
      continue;

    // if the address is the loopback broadcast address then skip it
    const sockaddr_in* ifbaddr = (const sockaddr_in*)
					&req[i].ifr_ifru.ifru_broadaddr;
    if (ntohl(ifbaddr->sin_addr.s_addr) == 0x7ffffffflu)
      continue;

    // got the broadcast address on the interface
    addr->sin_addr.s_addr = ifbaddr->sin_addr.s_addr;
    break;
  }

  // failed if no broadcast addresses found
  if (i == numInterfaces) {
    nerror("openBroadcast: getting broadcast address");
    close(fd);
    return(-1);
  }
#endif

  /* turn on non-blocking io */
  if (BzfNetwork::setNonBlocking(fd) < 0) {
    nerror("openBroadcast: setNonBlocking");
    close(fd);
    return(-1);
  }

  return fd;
}

int			openMulticast(const Address& address, int port,
					const char* service, int ttl,
					const char* net_interface,
					const char* mode,
					struct sockaddr_in* addr)
{
  // Multicast is broken
  return -1;

  struct ip_mreq mreq;
  struct in_addr ifaddr;
  int fd;
#if defined(_WIN32)
  const BOOL optOn = TRUE;
#else
  const int optOn = 1;
#endif

  /* check parameters */
  if (!addr) {
    printError("openMulticast: Must supply a return address structure!");
    return -1;
  }
  memset(addr, 0, sizeof(*addr));

  /* check mode */
  if (!mode || (mode[0] != 'r' && mode[0] != 'w')) {
    printError("openMulticast: Invalid mode");
    return -1;
  }

  /* lookup service and check port */
  if (service) {
    struct servent *sp = getservbyname(service, "udp");
    if (!sp) {
      if (port <= 0) {
	printError("openMulticast: No udp service %s", service);
	return -1;
      }
    }
    else {
      port = sp->s_port;
    }
  }
  if (port <= 0) {
    printError("openMulticast: Invalid port %s", port);
    return -1;
  }

  /* check group address */
  mreq.imr_multiaddr = InAddr(address);
  if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
    printError("openMulticast: Invalid multicast address");
    return -1;
  }

  /* open socket */
  fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd < 0) {
    nerror("openMulticast: socket");
    return -1;
  }

  /* check interface */
  if (net_interface && net_interface[0]) {
    ifaddr.s_addr = inet_addr(net_interface);
    if (ifaddr.s_addr == (unsigned long)-1) {
      struct hostent* hp = gethostbyname(net_interface);
      if (!hp) {
	printError("openMulticast: Can't get address of %s", net_interface);
	close(fd);
	return -1;
      }
      memcpy(&ifaddr, hp->h_addr, hp->h_length);
    }
    mreq.imr_interface = ifaddr;
  }
  else {
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

#if defined(__linux__)
    // linux doesn't seem to like INADDR_ANY as the interface.
    // find the first non-loopback interface and use that.
    // (only check the first numInterfaces interfaces.)
    const int numInterfaces = 5;
    int i;
    struct ifconf conf;
    struct ifreq req[numInterfaces];

    // get the list of interface names
    conf.ifc_len = sizeof(req);
    conf.ifc_ifcu.ifcu_req = req;
    for (i = 0; i < numInterfaces; ++i)
      req[i].ifr_ifrn.ifrn_name[0] = 0;
    if (ioctl(fd, SIOCGIFCONF, &conf) < 0) {
      nerror("openMulticast: getting interface list");
      close(fd);
      return(-1);
    }

    // get the address of each interface
    for (i = 0; i < numInterfaces; ++i) {
      // if no name then we're done
      if (req[i].ifr_ifrn.ifrn_name[0] == 0)
	break;

      // if we can't get the address then skip this interface
      if (ioctl(fd, SIOCGIFADDR, req + i) < 0)
	continue;

      // if the address is the loopback address then skip it
      const sockaddr_in* ifaddr = (const sockaddr_in*)
					&req[i].ifr_ifru.ifru_addr;
      if (ntohl(ifaddr->sin_addr.s_addr) == INADDR_LOOPBACK)
	continue;

      // got the address on the interface
      if (!net_interface || !net_interface[0])
	mreq.imr_interface.s_addr = ifaddr->sin_addr.s_addr;
      break;
    }
#endif
  }

  /* set address info */
  addr->sin_family = AF_INET;
  addr->sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
  addr->sin_port = htons(port);

  /* set options on socket */
  if (mode[0] == 'w') {
#if defined(_WIN32) || defined(__linux__) || defined(GUSI_20)
    /* windows requires socket to be bound before using multicast sockopts */
    /* linux requires that we bind to an interface's address to send */
    struct sockaddr_in tmpAddr;
    memset(&tmpAddr, 0, sizeof(tmpAddr));
    tmpAddr.sin_family = AF_INET;
    tmpAddr.sin_addr.s_addr = mreq.imr_interface.s_addr;
    tmpAddr.sin_port = 0;
    if (bind(fd, (const struct sockaddr*)&tmpAddr, sizeof(tmpAddr)) < 0) {
      nerror("openMulticast: bind");
      close(fd);
      return -1;
    }
#endif

    /* set ttl */
    if (setMulticastTTL(fd, ttl) < 0) {
      nerror("WARNING: openMulticast: setsockopt IP_MULTICAST_TTL");
      close(fd);
      return -1;
    }

    if (net_interface && net_interface[0] &&
		setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
		(SSOType)&ifaddr, sizeof(ifaddr)) < 0) {
      nerror("WARNING: openMulticast: Can't multicast on interface");
      close(fd);
      return -1;
    }
  }

  else {
#if defined(SO_REUSEPORT)
    /* set reuse port */
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
      nerror("WARNING: openMulticast: setsockopt SO_REUSEPORT");
      close(fd);
      return -1;
    }
#endif
#if defined(SO_REUSEADDR)
    /* set reuse address */
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
				(SSOType)&optOn, sizeof(optOn)) < 0) {
      nerror("WARNING: openMulticast: setsockopt SO_REUSEADDR");
      close(fd);
      return -1;
    }
#endif

    /* bind address */
#if defined(_WIN32)
    /* unlike linux, win32 requires that we bind to the ANY address */
    addr->sin_addr.s_addr = htonl(INADDR_ANY);
#endif
    if (bind(fd, (const struct sockaddr*)addr, sizeof(*addr)) < 0) {
      nerror("openMulticast: bind");
      close(fd);
      return -1;
    }

    /* join multicast group */
    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
				(SSOType)&mreq, sizeof(mreq)) < 0) {
      nerror("WARNING: openMulticast: Can't join multicast group");
      close(fd);
      return -1;
    }
  }

  /* turn on non-blocking io */
  if (BzfNetwork::setNonBlocking(fd) < 0) {
    nerror("openBroadcast: setNonBlocking");
    close(fd);
    return(-1);
  }

  return fd;
}

int			closeMulticast(int fd)
{
  if (fd == -1) return 0;
  return close(fd);
}

int			setMulticastTTL(int fd, int ttl)
{
#if defined(_WIN32)
  unsigned int opt = (unsigned int)ttl;
#else /* defined(_WIN32) */
  unsigned char opt = (unsigned char)ttl;
#endif /* defined(_WIN32) */
  return setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
				(SSOType)&opt, sizeof(opt));
}

int			sendMulticast(int fd, const void* buffer,
					int bufferLength,
					const struct sockaddr_in* addr)
{
  return sendto(fd, (const char*)buffer, bufferLength, 0,
				(const struct sockaddr*)addr, sizeof(*addr));
}

#if !defined(AddrLen)
#define AddrLen		int
#endif

int			recvMulticast(int fd, void* buffer, int bufferLength,
					 struct sockaddr_in* addr)
{
  struct sockaddr_in from;
  AddrLen fromLength = sizeof(from);

  int byteCount = recvfrom(fd, (char*)buffer, bufferLength, 0,
				(struct sockaddr*)&from, &fromLength);
  if (byteCount < 0) {
    if (getErrno() == EWOULDBLOCK) {
      return 0;
    }
    else {
      nerror("recvMulticast");
      return -1;
    }
  }
  if (addr) *addr = from;
  return byteCount;
}
<|endoftext|>


<commit_before>//===--- ClangModuleDependencyScanner.cpp - Dependency Scanning -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements dependency scanning for Clang modules.
//
//===----------------------------------------------------------------------===//
#include "ImporterImpl.h"
#include "swift/AST/ModuleDependencies.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangImporterOptions.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"

using namespace swift;

using namespace clang::tooling;
using namespace clang::tooling::dependencies;

class swift::ClangModuleDependenciesCacheImpl {
  /// The name of the file used for the "import hack" to compute module
  /// dependencies.
  /// FIXME: This should go away once Clang's dependency scanning library
  /// can scan by module name.
  std::string importHackFile;

public:
  /// Set containing all of the Clang modules that have already been seen.
  llvm::StringSet<> alreadySeen;

  DependencyScanningService service;

  DependencyScanningTool tool;

  ClangModuleDependenciesCacheImpl()
      : service(ScanningMode::MinimizedSourcePreprocessing,
                ScanningOutputFormat::Full),
        tool(service) { }
  ~ClangModuleDependenciesCacheImpl();

  /// Retrieve the name of the file used for the "import hack" that is
  /// used to scan the dependencies of a Clang module.
  llvm::ErrorOr<StringRef> getImportHackFile();
};

ClangModuleDependenciesCacheImpl::~ClangModuleDependenciesCacheImpl() {
  if (!importHackFile.empty()) {
    llvm::sys::fs::remove(importHackFile);
  }
}

llvm::ErrorOr<StringRef> ClangModuleDependenciesCacheImpl::getImportHackFile() {
  if (!importHackFile.empty())
    return importHackFile;

  // Create a temporary file.
  int resultFD;
  SmallString<128> resultPath;
  if (auto error = llvm::sys::fs::createTemporaryFile(
          "import-hack", "m", resultFD, resultPath))
    return error;

  llvm::raw_fd_ostream out(resultFD, /*shouldClose=*/true);
  out << "@import HACK_MODULE_NAME;\n";
  llvm::sys::RemoveFileOnSignal(resultPath);
  importHackFile = resultPath.str().str();
  return importHackFile;
}

namespace {
  class SingleCommandCompilationDatabase : public CompilationDatabase {
  public:
    SingleCommandCompilationDatabase(CompileCommand Cmd)
        : Command(std::move(Cmd)) {}

    virtual std::vector<CompileCommand>
    getCompileCommands(StringRef FilePath) const {
      return {Command};
    }

    virtual std::vector<CompileCommand> getAllCompileCommands() const {
      return {Command};
    }

  private:
    CompileCommand Command;
  };
}

// Add search paths.
// Note: This is handled differently for the Clang importer itself, which
// adds search paths to Clang's data structures rather than to its
// command line.
static void addSearchPathInvocationArguments(
    std::vector<std::string> &invocationArgStrs,
    ASTContext &ctx,
    const ClangImporterOptions &importerOpts) {
  SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
  for (const auto &framepath : searchPathOpts.FrameworkSearchPaths) {
    invocationArgStrs.push_back(framepath.IsSystem ? "-iframework" : "-F");
    invocationArgStrs.push_back(framepath.Path);
  }

  for (auto path : searchPathOpts.ImportSearchPaths) {
    invocationArgStrs.push_back("-I");
    invocationArgStrs.push_back(path);
  }
}

/// Create the command line for Clang dependency scanning.
static std::vector<std::string> getClangDepScanningInvocationArguments(
    ASTContext &ctx,
    const ClangImporterOptions &importerOpts,
    StringRef sourceFileName) {
  std::vector<std::string> commandLineArgs;

  // Form the basic command line.
  commandLineArgs.push_back("clang");
  importer::getNormalInvocationArguments(commandLineArgs, ctx, importerOpts);
  importer::addCommonInvocationArguments(commandLineArgs, ctx, importerOpts);
  addSearchPathInvocationArguments(commandLineArgs, ctx, importerOpts);

  auto sourceFilePos = std::find(
      commandLineArgs.begin(), commandLineArgs.end(),
      "<swift-imported-modules>");
  assert(sourceFilePos != commandLineArgs.end());
  *sourceFilePos = sourceFileName;

  // HACK! Drop the -fmodule-format= argument and the one that
  // precedes it.
  {
    auto moduleFormatPos = std::find_if(commandLineArgs.begin(),
                                        commandLineArgs.end(),
                                        [](StringRef arg) {
      return arg.startswith("-fmodule-format=");
    });
    assert(moduleFormatPos != commandLineArgs.end());
    assert(moduleFormatPos != commandLineArgs.begin());
    commandLineArgs.erase(moduleFormatPos-1, moduleFormatPos+1);
  }

  // HACK: No -fsyntax-only here?
  {
    auto syntaxOnlyPos = std::find(commandLineArgs.begin(),
                                   commandLineArgs.end(),
                                   "-fsyntax-only");
    assert(syntaxOnlyPos != commandLineArgs.end());
    *syntaxOnlyPos = "-c";
  }

  // HACK: Stolen from ClangScanDeps.cpp
  commandLineArgs.push_back("-o");
  commandLineArgs.push_back("/dev/null");
  commandLineArgs.push_back("-M");
  commandLineArgs.push_back("-MT");
  commandLineArgs.push_back("import-hack.o");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-Eonly");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-sys-header-deps");
  commandLineArgs.push_back("-Wno-error");

  return commandLineArgs;
}

/// Get or create the Clang-specific
static ClangModuleDependenciesCacheImpl *getOrCreateClangImpl(
    ModuleDependenciesCache &cache) {
  auto clangImpl = cache.getClangImpl();
  if (!clangImpl) {
    clangImpl = new ClangModuleDependenciesCacheImpl();
    cache.setClangImpl(clangImpl,
                       [](ClangModuleDependenciesCacheImpl *ptr) {
      delete ptr;
    });
  }

  return clangImpl;
}

/// Record the module dependencies we found by scanning Clang modules into
/// the module dependencies cache.
static void recordModuleDependencies(
    ModuleDependenciesCache &cache,
    const FullDependenciesResult &clangDependencies) {
  for (const auto &clangModuleDep : clangDependencies.DiscoveredModules) {
    // If we've already cached this information, we're done.
    if (cache.hasDependencies(clangModuleDep.ModuleName,
                              ModuleDependenciesKind::Clang))
      continue;

    // File dependencies for this module.
    std::vector<std::string> fileDeps;
    for (const auto &fileDep : clangModuleDep.FileDeps) {
      fileDeps.push_back(fileDep.getKey());
    }

    // Create a module filename.
    // FIXME: Query Clang to determine an appropriate hashed name for the
    // module file.
    llvm::SmallString<32> modulePath(clangModuleDep.ModuleName);
    llvm::sys::path::replace_extension(modulePath, "pcm");

    // Module-level dependencies.
    llvm::StringSet<> alreadyAddedModules;
    auto dependencies = ModuleDependencies::forClangModule(
        modulePath.str(), clangModuleDep.ClangModuleMapFile, fileDeps);
    for (const auto &moduleName : clangModuleDep.ClangModuleDeps) {
      dependencies.addModuleDependency(moduleName.ModuleName, alreadyAddedModules);
    }

    cache.recordDependencies(clangModuleDep.ModuleName,
                             std::move(dependencies),
                             ModuleDependenciesKind::Clang);
  }
}

Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
    StringRef moduleName, ModuleDependenciesCache &cache) {
  // Check whether there is already a cached result.
  if (auto found = cache.findDependencies(
          moduleName, ModuleDependenciesKind::Clang))
    return found;

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // HACK! Replace the module import buffer name with the source file hack.
  auto importHackFile = clangImpl->getImportHackFile();
  if (!importHackFile) {
    // FIXME: Emit a diagnostic here.
    return None;
  }

  // Reform the Clang importer options.
  // FIXME: Just save a reference or copy so we can get this back.
  ClangImporterOptions importerOpts;

  // Determine the command-line arguments for dependency scanning.
  auto &ctx = Impl.SwiftContext;
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(
      ctx, importerOpts, *importHackFile);

  // HACK! Trick out a .m file to use to import the module we name.
  std::string moduleNameHackDefine =
      ("-DHACK_MODULE_NAME=" + moduleName).str();
  commandLineArgs.push_back(moduleNameHackDefine);
  commandLineArgs.push_back("-fmodules-ignore-macro=HACK_MODULE_NAME");

  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
  CompileCommand command(workingDir, *importHackFile, commandLineArgs, "-");
  SingleCommandCompilationDatabase database(command);

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      database, workingDir, clangImpl->alreadySeen);

  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return None;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);

  return cache.findDependencies(moduleName, ModuleDependenciesKind::Clang);
}

bool ClangImporter::addBridgingHeaderDependencies(
    StringRef moduleName,
    ModuleDependenciesCache &cache) {
  auto targetModule = *cache.findDependencies(
      moduleName, ModuleDependenciesKind::Swift);

  // If we've already recorded bridging header dependencies, we're done.
  auto swiftDeps = targetModule.getAsSwiftModule();
  if (!swiftDeps->bridgingSourceFiles.empty() ||
      !swiftDeps->bridgingModuleDependencies.empty())
    return false;

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // Reform the Clang importer options.
  // FIXME: Just save a reference or copy so we can get this back.
  ClangImporterOptions importerOpts;

  // Retrieve the bridging header.
  std::string bridgingHeader = *targetModule.getBridgingHeader();

  // Determine the command-line arguments for dependency scanning.
  auto &ctx = Impl.SwiftContext;
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(
      ctx, importerOpts, bridgingHeader);

  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
  CompileCommand command(workingDir, bridgingHeader, commandLineArgs, "-");
  SingleCommandCompilationDatabase database(command);

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      database, workingDir, clangImpl->alreadySeen);

  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return true;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);

  // Record dependencies for the source files the bridging header includes.
  for (const auto &fileDep : clangDependencies->FullDeps.FileDeps)
    targetModule.addBridgingSourceFile(fileDep);

  // ... and all module dependencies.
  llvm::StringSet<> alreadyAddedModules;
  for (const auto &moduleDep : clangDependencies->FullDeps.ClangModuleDeps) {
    targetModule.addBridgingModuleDependency(
        moduleDep.ModuleName, alreadyAddedModules);
  }

  // Update the cache with the new information for the module.
  cache.updateDependencies(
     {moduleName, ModuleDependenciesKind::Swift},
     std::move(targetModule));

  return false;
}
<commit_msg>[Dependency scanner] Get the Clang module file name from Clang.<commit_after>//===--- ClangModuleDependencyScanner.cpp - Dependency Scanning -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements dependency scanning for Clang modules.
//
//===----------------------------------------------------------------------===//
#include "ImporterImpl.h"
#include "swift/AST/ModuleDependencies.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangImporterOptions.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"

using namespace swift;

using namespace clang::tooling;
using namespace clang::tooling::dependencies;

class swift::ClangModuleDependenciesCacheImpl {
  /// The name of the file used for the "import hack" to compute module
  /// dependencies.
  /// FIXME: This should go away once Clang's dependency scanning library
  /// can scan by module name.
  std::string importHackFile;

public:
  /// Set containing all of the Clang modules that have already been seen.
  llvm::StringSet<> alreadySeen;

  DependencyScanningService service;

  DependencyScanningTool tool;

  ClangModuleDependenciesCacheImpl()
      : service(ScanningMode::MinimizedSourcePreprocessing,
                ScanningOutputFormat::Full),
        tool(service) { }
  ~ClangModuleDependenciesCacheImpl();

  /// Retrieve the name of the file used for the "import hack" that is
  /// used to scan the dependencies of a Clang module.
  llvm::ErrorOr<StringRef> getImportHackFile();
};

ClangModuleDependenciesCacheImpl::~ClangModuleDependenciesCacheImpl() {
  if (!importHackFile.empty()) {
    llvm::sys::fs::remove(importHackFile);
  }
}

llvm::ErrorOr<StringRef> ClangModuleDependenciesCacheImpl::getImportHackFile() {
  if (!importHackFile.empty())
    return importHackFile;

  // Create a temporary file.
  int resultFD;
  SmallString<128> resultPath;
  if (auto error = llvm::sys::fs::createTemporaryFile(
          "import-hack", "m", resultFD, resultPath))
    return error;

  llvm::raw_fd_ostream out(resultFD, /*shouldClose=*/true);
  out << "@import HACK_MODULE_NAME;\n";
  llvm::sys::RemoveFileOnSignal(resultPath);
  importHackFile = resultPath.str().str();
  return importHackFile;
}

namespace {
  class SingleCommandCompilationDatabase : public CompilationDatabase {
  public:
    SingleCommandCompilationDatabase(CompileCommand Cmd)
        : Command(std::move(Cmd)) {}

    virtual std::vector<CompileCommand>
    getCompileCommands(StringRef FilePath) const {
      return {Command};
    }

    virtual std::vector<CompileCommand> getAllCompileCommands() const {
      return {Command};
    }

  private:
    CompileCommand Command;
  };
}

// Add search paths.
// Note: This is handled differently for the Clang importer itself, which
// adds search paths to Clang's data structures rather than to its
// command line.
static void addSearchPathInvocationArguments(
    std::vector<std::string> &invocationArgStrs,
    ASTContext &ctx,
    const ClangImporterOptions &importerOpts) {
  SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
  for (const auto &framepath : searchPathOpts.FrameworkSearchPaths) {
    invocationArgStrs.push_back(framepath.IsSystem ? "-iframework" : "-F");
    invocationArgStrs.push_back(framepath.Path);
  }

  for (auto path : searchPathOpts.ImportSearchPaths) {
    invocationArgStrs.push_back("-I");
    invocationArgStrs.push_back(path);
  }
}

/// Create the command line for Clang dependency scanning.
static std::vector<std::string> getClangDepScanningInvocationArguments(
    ASTContext &ctx,
    const ClangImporterOptions &importerOpts,
    StringRef sourceFileName) {
  std::vector<std::string> commandLineArgs;

  // Form the basic command line.
  commandLineArgs.push_back("clang");
  importer::getNormalInvocationArguments(commandLineArgs, ctx, importerOpts);
  importer::addCommonInvocationArguments(commandLineArgs, ctx, importerOpts);
  addSearchPathInvocationArguments(commandLineArgs, ctx, importerOpts);

  auto sourceFilePos = std::find(
      commandLineArgs.begin(), commandLineArgs.end(),
      "<swift-imported-modules>");
  assert(sourceFilePos != commandLineArgs.end());
  *sourceFilePos = sourceFileName;

  // HACK! Drop the -fmodule-format= argument and the one that
  // precedes it.
  {
    auto moduleFormatPos = std::find_if(commandLineArgs.begin(),
                                        commandLineArgs.end(),
                                        [](StringRef arg) {
      return arg.startswith("-fmodule-format=");
    });
    assert(moduleFormatPos != commandLineArgs.end());
    assert(moduleFormatPos != commandLineArgs.begin());
    commandLineArgs.erase(moduleFormatPos-1, moduleFormatPos+1);
  }

  // HACK: No -fsyntax-only here?
  {
    auto syntaxOnlyPos = std::find(commandLineArgs.begin(),
                                   commandLineArgs.end(),
                                   "-fsyntax-only");
    assert(syntaxOnlyPos != commandLineArgs.end());
    *syntaxOnlyPos = "-c";
  }

  // HACK: Stolen from ClangScanDeps.cpp
  commandLineArgs.push_back("-o");
  commandLineArgs.push_back("/dev/null");
  commandLineArgs.push_back("-M");
  commandLineArgs.push_back("-MT");
  commandLineArgs.push_back("import-hack.o");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-Eonly");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-sys-header-deps");
  commandLineArgs.push_back("-Wno-error");

  return commandLineArgs;
}

/// Get or create the Clang-specific
static ClangModuleDependenciesCacheImpl *getOrCreateClangImpl(
    ModuleDependenciesCache &cache) {
  auto clangImpl = cache.getClangImpl();
  if (!clangImpl) {
    clangImpl = new ClangModuleDependenciesCacheImpl();
    cache.setClangImpl(clangImpl,
                       [](ClangModuleDependenciesCacheImpl *ptr) {
      delete ptr;
    });
  }

  return clangImpl;
}

/// Record the module dependencies we found by scanning Clang modules into
/// the module dependencies cache.
static void recordModuleDependencies(
    ModuleDependenciesCache &cache,
    const FullDependenciesResult &clangDependencies) {
  for (const auto &clangModuleDep : clangDependencies.DiscoveredModules) {
    // If we've already cached this information, we're done.
    if (cache.hasDependencies(clangModuleDep.ModuleName,
                              ModuleDependenciesKind::Clang))
      continue;

    // File dependencies for this module.
    std::vector<std::string> fileDeps;
    for (const auto &fileDep : clangModuleDep.FileDeps) {
      fileDeps.push_back(fileDep.getKey());
    }

    // Module-level dependencies.
    llvm::StringSet<> alreadyAddedModules;
    auto dependencies = ModuleDependencies::forClangModule(
        clangModuleDep.ImplicitModulePCMPath,
        clangModuleDep.ClangModuleMapFile, fileDeps);
    for (const auto &moduleName : clangModuleDep.ClangModuleDeps) {
      dependencies.addModuleDependency(moduleName.ModuleName, alreadyAddedModules);
    }

    cache.recordDependencies(clangModuleDep.ModuleName,
                             std::move(dependencies),
                             ModuleDependenciesKind::Clang);
  }
}

Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
    StringRef moduleName, ModuleDependenciesCache &cache) {
  // Check whether there is already a cached result.
  if (auto found = cache.findDependencies(
          moduleName, ModuleDependenciesKind::Clang))
    return found;

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // HACK! Replace the module import buffer name with the source file hack.
  auto importHackFile = clangImpl->getImportHackFile();
  if (!importHackFile) {
    // FIXME: Emit a diagnostic here.
    return None;
  }

  // Reform the Clang importer options.
  // FIXME: Just save a reference or copy so we can get this back.
  ClangImporterOptions importerOpts;

  // Determine the command-line arguments for dependency scanning.
  auto &ctx = Impl.SwiftContext;
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(
      ctx, importerOpts, *importHackFile);

  // HACK! Trick out a .m file to use to import the module we name.
  std::string moduleNameHackDefine =
      ("-DHACK_MODULE_NAME=" + moduleName).str();
  commandLineArgs.push_back(moduleNameHackDefine);
  commandLineArgs.push_back("-fmodules-ignore-macro=HACK_MODULE_NAME");

  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
  CompileCommand command(workingDir, *importHackFile, commandLineArgs, "-");
  SingleCommandCompilationDatabase database(command);

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      database, workingDir, clangImpl->alreadySeen);

  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return None;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);

  return cache.findDependencies(moduleName, ModuleDependenciesKind::Clang);
}

bool ClangImporter::addBridgingHeaderDependencies(
    StringRef moduleName,
    ModuleDependenciesCache &cache) {
  auto targetModule = *cache.findDependencies(
      moduleName, ModuleDependenciesKind::Swift);

  // If we've already recorded bridging header dependencies, we're done.
  auto swiftDeps = targetModule.getAsSwiftModule();
  if (!swiftDeps->bridgingSourceFiles.empty() ||
      !swiftDeps->bridgingModuleDependencies.empty())
    return false;

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // Reform the Clang importer options.
  // FIXME: Just save a reference or copy so we can get this back.
  ClangImporterOptions importerOpts;

  // Retrieve the bridging header.
  std::string bridgingHeader = *targetModule.getBridgingHeader();

  // Determine the command-line arguments for dependency scanning.
  auto &ctx = Impl.SwiftContext;
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(
      ctx, importerOpts, bridgingHeader);

  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
  CompileCommand command(workingDir, bridgingHeader, commandLineArgs, "-");
  SingleCommandCompilationDatabase database(command);

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      database, workingDir, clangImpl->alreadySeen);

  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return true;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);

  // Record dependencies for the source files the bridging header includes.
  for (const auto &fileDep : clangDependencies->FullDeps.FileDeps)
    targetModule.addBridgingSourceFile(fileDep);

  // ... and all module dependencies.
  llvm::StringSet<> alreadyAddedModules;
  for (const auto &moduleDep : clangDependencies->FullDeps.ClangModuleDeps) {
    targetModule.addBridgingModuleDependency(
        moduleDep.ModuleName, alreadyAddedModules);
  }

  // Update the cache with the new information for the module.
  cache.updateDependencies(
     {moduleName, ModuleDependenciesKind::Swift},
     std::move(targetModule));

  return false;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Baozeng Ding <sploving1@gmail.com>
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "NullDerefProtectionTransformer.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Lookup.h"

#include <bitset>

using namespace clang;

namespace {
using namespace cling;

class PointerCheckInjector : public RecursiveASTVisitor<PointerCheckInjector> {
  private:
    Interpreter& m_Interp;
    Sema& m_Sema;
    typedef llvm::DenseMap<clang::FunctionDecl*, std::bitset<32> > decl_map_t;
    llvm::DenseMap<clang::FunctionDecl*, std::bitset<32> > m_NonNullArgIndexs;

    ///\brief Needed for the AST transformations, owned by Sema.
    ///
    ASTContext& m_Context;

    ///\brief cling_runtime_internal_throwIfInvalidPointer cache.
    ///
    LookupResult* m_clingthrowIfInvalidPointerCache;

  public:
    PointerCheckInjector(Interpreter& I)
      : m_Interp(I), m_Sema(I.getCI()->getSema()),
        m_Context(I.getCI()->getASTContext()),
        m_clingthrowIfInvalidPointerCache(0) {}

    ~PointerCheckInjector() {
      delete m_clingthrowIfInvalidPointerCache;
    }

    bool VisitUnaryOperator(UnaryOperator* UnOp) {
      Expr* SubExpr = UnOp->getSubExpr();
      VisitStmt(SubExpr);
      if (UnOp->getOpcode() == UO_Deref
          && !llvm::isa<clang::CXXThisExpr>(SubExpr)
          && SubExpr->getType().getTypePtr()->isPointerType())
          UnOp->setSubExpr(SynthesizeCheck(SubExpr));
      return true;
    }

    bool VisitMemberExpr(MemberExpr* ME) {
      Expr* Base = ME->getBase();
      VisitStmt(Base);
      if (ME->isArrow()
          && !llvm::isa<clang::CXXThisExpr>(Base)
          && ME->getMemberDecl()->isCXXInstanceMember())
        ME->setBase(SynthesizeCheck(Base));
      return true;
    }

    bool VisitCallExpr(CallExpr* CE) {
      VisitStmt(CE->getCallee());
      FunctionDecl* FDecl = CE->getDirectCallee();
      if (FDecl && isDeclCandidate(FDecl)) {
        decl_map_t::const_iterator it = m_NonNullArgIndexs.find(FDecl);
        const std::bitset<32>& ArgIndexs = it->second;
        Sema::ContextRAII pushedDC(m_Sema, FDecl);
        for (int index = 0; index < 32; ++index) {
          if (ArgIndexs.test(index)) {
            // Get the argument with the nonnull attribute.
            Expr* Arg = CE->getArg(index);
            if (Arg->getType().getTypePtr()->isPointerType()
                && !llvm::isa<clang::CXXThisExpr>(Arg))
              CE->setArg(index, SynthesizeCheck(Arg));
          }
        }
      }
      return true;
    }

    bool TraverseFunctionDecl(FunctionDecl* FD) {
      // We cannot synthesize when there is a const expr
      // and if it is a function template (we will do the transformation on
      // the instance).
      if (!FD->isConstexpr() && !FD->getDescribedFunctionTemplate())
         RecursiveASTVisitor::TraverseFunctionDecl(FD);
      return true;
    }

    bool TraverseCXXMethodDecl(CXXMethodDecl* CXXMD) {
      // We cannot synthesize when there is a const expr.
      if (!CXXMD->isConstexpr())
        RecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
      return true;
    }

  private:
    Expr* SynthesizeCheck(Expr* Arg) {
      assert(Arg && "Cannot call with Arg=0");

      if(!m_clingthrowIfInvalidPointerCache)
        FindAndCacheRuntimeLookupResult();

      SourceLocation Loc = Arg->getLocStart();
      Expr* VoidSemaArg = utils::Synthesize::CStyleCastPtrExpr(&m_Sema,
                                                            m_Context.VoidPtrTy,
                                                            (uintptr_t)&m_Interp);
      Expr* VoidExprArg = utils::Synthesize::CStyleCastPtrExpr(&m_Sema,
                                                          m_Context.VoidPtrTy,
                                                          (uintptr_t)Arg);
      Scope* S = m_Sema.getScopeForContext(m_Sema.CurContext);
      CXXScopeSpec CSS;

      Expr* checkCall
        = m_Sema.BuildDeclarationNameExpr(CSS,
                                          *m_clingthrowIfInvalidPointerCache,
                                         /*ADL*/ false).get();
      const clang::FunctionProtoType* checkCallType
        = llvm::dyn_cast<const clang::FunctionProtoType>(
            checkCall->getType().getTypePtr());

      TypeSourceInfo* constVoidPtrTSI = m_Context.getTrivialTypeSourceInfo(
        checkCallType->getParamType(2), Loc);

      // It is unclear whether this is the correct cast if the type
      // is dependent.  Hence, For now, we do not expect SynthesizeCheck to
      // be run on a function template.  It should be run only on function
      // instances.
      // When this is actually insert in a function template, it seems that
      // clang r272382 when instantiating the templates drops one of the part
      // of the implicit cast chain.
      // Namely in:
/*
`-ImplicitCastExpr 0x1010cea90 <col:4> 'const void *' <BitCast>
 `-ImplicitCastExpr 0x1026e0bc0 <col:4> 'const class TAttMarker *'
                    <UncheckedDerivedToBase (TAttMarker)>
  `-ImplicitCastExpr 0x1026e0b48 <col:4> 'class TGraph *' <LValueToRValue>
   `-DeclRefExpr 0x1026e0b20 <col:4> 'class TGraph *' lvalue Var 0x1026e09c0
                   'g5' 'class TGraph *'
*/
      // It drops the 2nd lines (ImplicitCastExpr UncheckedDerivedToBase)
      // clang r227800 seems to actually keep that lines during instantiation.
      Expr* voidPtrArg
        = m_Sema.BuildCStyleCastExpr(Loc, constVoidPtrTSI, Loc, Arg).get();

      Expr *args[] = {VoidSemaArg, VoidExprArg, voidPtrArg};

      if (Expr* call = m_Sema.ActOnCallExpr(S, checkCall,
                                            Loc, args, Loc).get())
      {
        // It is unclear whether this is the correct cast if the type
        // is dependent.  Hence, For now, we do not expect SynthesizeCheck to
        // be run on a function template.  It should be run only on function
        // instances.
        clang::TypeSourceInfo* argTSI = m_Context.getTrivialTypeSourceInfo(
                                          Arg->getType(), Loc);
        Expr* castExpr = m_Sema.BuildCStyleCastExpr(Loc, argTSI,
                                                    Loc, call).get();
        return castExpr;
      }
      return voidPtrArg;
    }

    bool isDeclCandidate(FunctionDecl * FDecl) {
      if (m_NonNullArgIndexs.count(FDecl))
        return true;

      if (llvm::isa<CXXRecordDecl>(FDecl))
        return true;

      std::bitset<32> ArgIndexs;
      for (specific_attr_iterator<NonNullAttr>
             I = FDecl->specific_attr_begin<NonNullAttr>(),
             E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I) {

        NonNullAttr *NonNull = *I;
        for (NonNullAttr::args_iterator i = NonNull->args_begin(),
               e = NonNull->args_end(); i != e; ++i) {
          ArgIndexs.set(*i);
        }
      }

      if (ArgIndexs.any()) {
        m_NonNullArgIndexs.insert(std::make_pair(FDecl, ArgIndexs));
        return true;
      }
      return false;
    }

    void FindAndCacheRuntimeLookupResult() {
      assert(!m_clingthrowIfInvalidPointerCache && "Called multiple times!?");

      DeclarationName Name
        = &m_Context.Idents.get("cling_runtime_internal_throwIfInvalidPointer");
      SourceLocation noLoc;
      m_clingthrowIfInvalidPointerCache = new LookupResult(m_Sema, Name, noLoc,
                                        Sema::LookupOrdinaryName,
                                        Sema::ForRedeclaration);
      m_Sema.LookupQualifiedName(*m_clingthrowIfInvalidPointerCache,
                                 m_Context.getTranslationUnitDecl());
      assert(!m_clingthrowIfInvalidPointerCache->empty() &&
              "Lookup of cling_runtime_internal_throwIfInvalidPointer failed!");
    }
  };
}

namespace cling {
  NullDerefProtectionTransformer::NullDerefProtectionTransformer(Interpreter* I)
    : ASTTransformer(&I->getCI()->getSema()), m_Interp(I) {
  }

  NullDerefProtectionTransformer::~NullDerefProtectionTransformer()
  { }

  bool NullDerefProtectionTransformer::shouldTransform(const clang::Decl* D) {
    if (D->isFromASTFile())
      return false;
    if (D->isTemplateDecl())
      return false;

    auto Loc = D->getLocation();
    if (Loc.isInvalid())
      return false;

    SourceManager& SM = m_Interp->getSema().getSourceManager();
    auto Characteristic = SM.getFileCharacteristic(Loc);
    if (Characteristic != clang::SrcMgr::C_User)
      return false;

    auto FID = SM.getFileID(Loc);
    if (FID.isInvalid())
      return false;

    auto FE = SM.getFileEntryForID(FID);
    if (!FE)
      return false;

    auto Dir = FE->getDir();
    if (!Dir)
      return false;

    auto IterAndInserted = m_ShouldVisitDir.try_emplace(Dir, true);
    if (IterAndInserted.second == false)
      return IterAndInserted.first->second;

    if (llvm::sys::fs::can_write(Dir->getName()))
      return true; // `true` is already emplaced above.

    // Remember that this dir is not writable and should not be visited.
    IterAndInserted.first->second = false;
    return false;
  }

  ASTTransformer::Result
  NullDerefProtectionTransformer::Transform(clang::Decl* D) {
    if (getCompilationOpts().CheckPointerValidity && shouldTransform(D)) {
      PointerCheckInjector injector(*m_Interp);
      injector.TraverseDecl(D);
    }
    return Result(D, true);
  }
} // end namespace cling
<commit_msg>Do not check *this, even if implicitly cast.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Baozeng Ding <sploving1@gmail.com>
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "NullDerefProtectionTransformer.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Lookup.h"

#include <bitset>

using namespace clang;

namespace {
using namespace cling;

class PointerCheckInjector : public RecursiveASTVisitor<PointerCheckInjector> {
  private:
    Interpreter& m_Interp;
    Sema& m_Sema;
    typedef llvm::DenseMap<clang::FunctionDecl*, std::bitset<32> > decl_map_t;
    llvm::DenseMap<clang::FunctionDecl*, std::bitset<32> > m_NonNullArgIndexs;

    ///\brief Needed for the AST transformations, owned by Sema.
    ///
    ASTContext& m_Context;

    ///\brief cling_runtime_internal_throwIfInvalidPointer cache.
    ///
    LookupResult* m_clingthrowIfInvalidPointerCache;

    bool IsTransparentThis(Expr* E) {
      if (auto TE = dyn_cast<CXXThisExpr>(E))
        return true;
      if (auto ICE = dyn_cast<ImplicitCastExpr>(E))
        return IsTransparentThis(ICE->getSubExpr());
      return false;
    }

  public:
    PointerCheckInjector(Interpreter& I)
      : m_Interp(I), m_Sema(I.getCI()->getSema()),
        m_Context(I.getCI()->getASTContext()),
        m_clingthrowIfInvalidPointerCache(0) {}

    ~PointerCheckInjector() {
      delete m_clingthrowIfInvalidPointerCache;
    }

    bool VisitUnaryOperator(UnaryOperator* UnOp) {
      Expr* SubExpr = UnOp->getSubExpr();
      VisitStmt(SubExpr);
      if (UnOp->getOpcode() == UO_Deref
          && !IsTransparentThis(SubExpr)
          && SubExpr->getType().getTypePtr()->isPointerType())
          UnOp->setSubExpr(SynthesizeCheck(SubExpr));
      return true;
    }

    bool VisitMemberExpr(MemberExpr* ME) {
      Expr* Base = ME->getBase();
      VisitStmt(Base);
      if (ME->isArrow()
          && !IsTransparentThis(Base)
          && ME->getMemberDecl()->isCXXInstanceMember())
        ME->setBase(SynthesizeCheck(Base));
      return true;
    }

    bool VisitCallExpr(CallExpr* CE) {
      VisitStmt(CE->getCallee());
      FunctionDecl* FDecl = CE->getDirectCallee();
      if (FDecl && isDeclCandidate(FDecl)) {
        decl_map_t::const_iterator it = m_NonNullArgIndexs.find(FDecl);
        const std::bitset<32>& ArgIndexs = it->second;
        Sema::ContextRAII pushedDC(m_Sema, FDecl);
        for (int index = 0; index < 32; ++index) {
          if (ArgIndexs.test(index)) {
            // Get the argument with the nonnull attribute.
            Expr* Arg = CE->getArg(index);
            if (Arg->getType().getTypePtr()->isPointerType()
                && !IsTransparentThis(Arg))
              CE->setArg(index, SynthesizeCheck(Arg));
          }
        }
      }
      return true;
    }

    bool TraverseFunctionDecl(FunctionDecl* FD) {
      // We cannot synthesize when there is a const expr
      // and if it is a function template (we will do the transformation on
      // the instance).
      if (!FD->isConstexpr() && !FD->getDescribedFunctionTemplate())
         RecursiveASTVisitor::TraverseFunctionDecl(FD);
      return true;
    }

    bool TraverseCXXMethodDecl(CXXMethodDecl* CXXMD) {
      // We cannot synthesize when there is a const expr.
      if (!CXXMD->isConstexpr())
        RecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
      return true;
    }

  private:
    Expr* SynthesizeCheck(Expr* Arg) {
      assert(Arg && "Cannot call with Arg=0");

      if(!m_clingthrowIfInvalidPointerCache)
        FindAndCacheRuntimeLookupResult();

      SourceLocation Loc = Arg->getLocStart();
      Expr* VoidSemaArg = utils::Synthesize::CStyleCastPtrExpr(&m_Sema,
                                                            m_Context.VoidPtrTy,
                                                            (uintptr_t)&m_Interp);
      Expr* VoidExprArg = utils::Synthesize::CStyleCastPtrExpr(&m_Sema,
                                                          m_Context.VoidPtrTy,
                                                          (uintptr_t)Arg);
      Scope* S = m_Sema.getScopeForContext(m_Sema.CurContext);
      CXXScopeSpec CSS;

      Expr* checkCall
        = m_Sema.BuildDeclarationNameExpr(CSS,
                                          *m_clingthrowIfInvalidPointerCache,
                                         /*ADL*/ false).get();
      const clang::FunctionProtoType* checkCallType
        = llvm::dyn_cast<const clang::FunctionProtoType>(
            checkCall->getType().getTypePtr());

      TypeSourceInfo* constVoidPtrTSI = m_Context.getTrivialTypeSourceInfo(
        checkCallType->getParamType(2), Loc);

      // It is unclear whether this is the correct cast if the type
      // is dependent.  Hence, For now, we do not expect SynthesizeCheck to
      // be run on a function template.  It should be run only on function
      // instances.
      // When this is actually insert in a function template, it seems that
      // clang r272382 when instantiating the templates drops one of the part
      // of the implicit cast chain.
      // Namely in:
/*
`-ImplicitCastExpr 0x1010cea90 <col:4> 'const void *' <BitCast>
 `-ImplicitCastExpr 0x1026e0bc0 <col:4> 'const class TAttMarker *'
                    <UncheckedDerivedToBase (TAttMarker)>
  `-ImplicitCastExpr 0x1026e0b48 <col:4> 'class TGraph *' <LValueToRValue>
   `-DeclRefExpr 0x1026e0b20 <col:4> 'class TGraph *' lvalue Var 0x1026e09c0
                   'g5' 'class TGraph *'
*/
      // It drops the 2nd lines (ImplicitCastExpr UncheckedDerivedToBase)
      // clang r227800 seems to actually keep that lines during instantiation.
      Expr* voidPtrArg
        = m_Sema.BuildCStyleCastExpr(Loc, constVoidPtrTSI, Loc, Arg).get();

      Expr *args[] = {VoidSemaArg, VoidExprArg, voidPtrArg};

      if (Expr* call = m_Sema.ActOnCallExpr(S, checkCall,
                                            Loc, args, Loc).get())
      {
        // It is unclear whether this is the correct cast if the type
        // is dependent.  Hence, For now, we do not expect SynthesizeCheck to
        // be run on a function template.  It should be run only on function
        // instances.
        clang::TypeSourceInfo* argTSI = m_Context.getTrivialTypeSourceInfo(
                                          Arg->getType(), Loc);
        Expr* castExpr = m_Sema.BuildCStyleCastExpr(Loc, argTSI,
                                                    Loc, call).get();
        return castExpr;
      }
      return voidPtrArg;
    }

    bool isDeclCandidate(FunctionDecl * FDecl) {
      if (m_NonNullArgIndexs.count(FDecl))
        return true;

      if (llvm::isa<CXXRecordDecl>(FDecl))
        return true;

      std::bitset<32> ArgIndexs;
      for (specific_attr_iterator<NonNullAttr>
             I = FDecl->specific_attr_begin<NonNullAttr>(),
             E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I) {

        NonNullAttr *NonNull = *I;
        for (NonNullAttr::args_iterator i = NonNull->args_begin(),
               e = NonNull->args_end(); i != e; ++i) {
          ArgIndexs.set(*i);
        }
      }

      if (ArgIndexs.any()) {
        m_NonNullArgIndexs.insert(std::make_pair(FDecl, ArgIndexs));
        return true;
      }
      return false;
    }

    void FindAndCacheRuntimeLookupResult() {
      assert(!m_clingthrowIfInvalidPointerCache && "Called multiple times!?");

      DeclarationName Name
        = &m_Context.Idents.get("cling_runtime_internal_throwIfInvalidPointer");
      SourceLocation noLoc;
      m_clingthrowIfInvalidPointerCache = new LookupResult(m_Sema, Name, noLoc,
                                        Sema::LookupOrdinaryName,
                                        Sema::ForRedeclaration);
      m_Sema.LookupQualifiedName(*m_clingthrowIfInvalidPointerCache,
                                 m_Context.getTranslationUnitDecl());
      assert(!m_clingthrowIfInvalidPointerCache->empty() &&
              "Lookup of cling_runtime_internal_throwIfInvalidPointer failed!");
    }
  };
}

namespace cling {
  NullDerefProtectionTransformer::NullDerefProtectionTransformer(Interpreter* I)
    : ASTTransformer(&I->getCI()->getSema()), m_Interp(I) {
  }

  NullDerefProtectionTransformer::~NullDerefProtectionTransformer()
  { }

  bool NullDerefProtectionTransformer::shouldTransform(const clang::Decl* D) {
    if (D->isFromASTFile())
      return false;
    if (D->isTemplateDecl())
      return false;

    auto Loc = D->getLocation();
    if (Loc.isInvalid())
      return false;

    SourceManager& SM = m_Interp->getSema().getSourceManager();
    auto Characteristic = SM.getFileCharacteristic(Loc);
    if (Characteristic != clang::SrcMgr::C_User)
      return false;

    auto FID = SM.getFileID(Loc);
    if (FID.isInvalid())
      return false;

    auto FE = SM.getFileEntryForID(FID);
    if (!FE)
      return false;

    auto Dir = FE->getDir();
    if (!Dir)
      return false;

    auto IterAndInserted = m_ShouldVisitDir.try_emplace(Dir, true);
    if (IterAndInserted.second == false)
      return IterAndInserted.first->second;

    if (llvm::sys::fs::can_write(Dir->getName()))
      return true; // `true` is already emplaced above.

    // Remember that this dir is not writable and should not be visited.
    IterAndInserted.first->second = false;
    return false;
  }

  ASTTransformer::Result
  NullDerefProtectionTransformer::Transform(clang::Decl* D) {
    if (getCompilationOpts().CheckPointerValidity && shouldTransform(D)) {
      PointerCheckInjector injector(*m_Interp);
      injector.TraverseDecl(D);
    }
    return Result(D, true);
  }
} // end namespace cling
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 Nagisa Sekiguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "server.h"

using namespace ydsh;
using namespace lsp;

int main() {
    LSPLogger logger;
    LSPServer server(logger, FilePtr(stdin), FilePtr(stdout));
    server.run();
}
<commit_msg>[LSP] set log level<commit_after>/*
 * Copyright (C) 2018 Nagisa Sekiguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "server.h"

using namespace ydsh;
using namespace lsp;

int main() {
    LSPLogger logger;
    logger.setSeverity(LogLevel::INFO);
    logger.setAppender(FilePtr(stderr));
    LSPServer server(logger, FilePtr(stdin), FilePtr(stdout));
    server.run();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 Sirikata Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

#include "BulletCharacterObject.hpp"
#include "BulletCharacterController.hpp"
#include "BulletPhysicsService.hpp"

#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"

namespace Sirikata {

BulletCharacterObject::BulletCharacterObject(BulletPhysicsService* parent, const UUID& uuid, bulletObjBBox bb)
 : BulletObject(parent),
   mID(uuid),
   mBBox(bb),
   mGhostObject(NULL),
   mCharacter(NULL),
   mCollisionShape(NULL)
{
    if (mBBox != BULLET_OBJECT_BOUNDS_SPHERE &&
        mBBox != BULLET_OBJECT_BOUNDS_ENTIRE_OBJECT)
    {
        BULLETLOG(error, "Tried to set character collision bounds to unsupported type. Only box and sphere are supported for characters. Defaulting to box.");
        mBBox = BULLET_OBJECT_BOUNDS_ENTIRE_OBJECT;
    }
}

BulletCharacterObject::~BulletCharacterObject() {
}

bool BulletCharacterObject::fixed() {
    return false;
}

bulletObjTreatment BulletCharacterObject::treatment() {
    return BULLET_OBJECT_TREATMENT_CHARACTER;
}

bulletObjBBox BulletCharacterObject::bbox() {
    return mBBox;
}

float32 BulletCharacterObject::mass() {
    return 0.f;
}

void BulletCharacterObject::load(Mesh::MeshdataPtr mesh) {
    LocationInfo& locinfo = mParent->info(mID);

    Vector3f objPosition = mParent->currentPosition(mID);
    Quaternion objOrient = mParent->currentOrientation(mID);
    btTransform startTransform = btTransform(
        btQuaternion(objOrient.x,objOrient.y,objOrient.z,objOrient.w),
        btVector3(objPosition.x,objPosition.y,objPosition.z)
    );

    mGhostObject = new btPairCachingGhostObject();
    mGhostObject->setWorldTransform(startTransform);
    mParent->broadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());

    // Currently only support spheres, TODO(ewencp) we might want to support
    // capsules instead.
    mCollisionShape = computeCollisionShape(mID, mBBox, Mesh::MeshdataPtr());
    mGhostObject->setCollisionShape(mCollisionShape);
    mGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);

    // TODO(ewencp) make this configurable?
    btScalar stepHeight = btScalar(0.5);
    // FIXME(ewencp) we know we're only allocating spheres/capsules for this, so
    // it's currently safe to do this cast, but technically
    // computeCollisionShape can compute concave shapes as well.
    mCharacter = new BulletCharacterController (mGhostObject, static_cast<btConvexShape*>(mCollisionShape), stepHeight);

    // Get mask information
    bulletObjCollisionMaskGroup mygroup, collide_with;
    BulletObject::getCollisionMask(BULLET_OBJECT_TREATMENT_CHARACTER, &mygroup, &collide_with);
    mParent->dynamicsWorld()->addCollisionObject(mGhostObject, (short)mygroup, (short)collide_with);
    mParent->dynamicsWorld()->addAction(mCharacter);

    mParent->addTickObject(mID);
    mParent->addDeactivateableObject(mID);
}

void BulletCharacterObject::unload() {
    if (mCharacter) {
        mParent->removeTickObject(mID);
        mParent->removeDeactivateableObject(mID);

        mParent->dynamicsWorld()->removeAction(mCharacter);
        mParent->dynamicsWorld()->removeCollisionObject(mGhostObject);

        delete mCharacter;
        mCharacter = NULL;

        delete mGhostObject;
        mGhostObject = NULL;

        delete mCollisionShape;
        mCollisionShape = NULL;
    }
}

void BulletCharacterObject::preTick(const Time& t) {
    LocationInfo& locinfo = mParent->info(mID);
    Vector3f char_vel = locinfo.location.velocity();
    btVector3 bt_char_vel(char_vel.x, char_vel.y, char_vel.z);
    mCharacter->setWalkDirection(bt_char_vel);
    // Character controller doesn't have any rotation support. Instead, we set
    // the rotation on the ghost object directly based on the requested
    // rotation. FIXME(ewencp) this needs some sort of handling similar to
    // walking direction where we know to stop the rotation at some point.
    btTransform xform = mGhostObject->getWorldTransform();
    btVector3 objPosition = xform.getOrigin();
    Quaternion objOrient = mParent->currentOrientation(mID);
    mGhostObject->setWorldTransform(
        btTransform(
            btQuaternion(objOrient.x, objOrient.y, objOrient.z, objOrient.w),
            objPosition
        )
    );
}

void BulletCharacterObject::postTick(const Time& t) {
    LocationInfo& locinfo = mParent->info(mID);

    btTransform worldTrans = mGhostObject->getWorldTransform();
    btVector3 pos = worldTrans.getOrigin();
    TimedMotionVector3f newLocation(t, MotionVector3f(Vector3f(pos.x(), pos.y(), pos.z()), locinfo.location.velocity()));
    mParent->setLocation(mID, newLocation);
    btQuaternion rot = worldTrans.getRotation();
    TimedMotionQuaternion newOrientation(
        t,
        MotionQuaternion(
            Quaternion(rot.x(), rot.y(), rot.z(), rot.w()),
            locinfo.orientation.velocity()
        )
    );
    mParent->setOrientation(mID, newOrientation);

    mParent->addUpdate(mID);
}

void BulletCharacterObject::deactivationTick(const Time& t) {
    if (mGhostObject != NULL && !mGhostObject->isActive())
        mParent->updateObjectFromDeactivation(mID);
}

} // namespace Sirikata
<commit_msg>Avoid very small updates to characters in Bullet LocationService.<commit_after>// Copyright (c) 2011 Sirikata Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

#include "BulletCharacterObject.hpp"
#include "BulletCharacterController.hpp"
#include "BulletPhysicsService.hpp"

#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"

namespace Sirikata {

BulletCharacterObject::BulletCharacterObject(BulletPhysicsService* parent, const UUID& uuid, bulletObjBBox bb)
 : BulletObject(parent),
   mID(uuid),
   mBBox(bb),
   mGhostObject(NULL),
   mCharacter(NULL),
   mCollisionShape(NULL)
{
    if (mBBox != BULLET_OBJECT_BOUNDS_SPHERE &&
        mBBox != BULLET_OBJECT_BOUNDS_ENTIRE_OBJECT)
    {
        BULLETLOG(error, "Tried to set character collision bounds to unsupported type. Only box and sphere are supported for characters. Defaulting to box.");
        mBBox = BULLET_OBJECT_BOUNDS_ENTIRE_OBJECT;
    }
}

BulletCharacterObject::~BulletCharacterObject() {
}

bool BulletCharacterObject::fixed() {
    return false;
}

bulletObjTreatment BulletCharacterObject::treatment() {
    return BULLET_OBJECT_TREATMENT_CHARACTER;
}

bulletObjBBox BulletCharacterObject::bbox() {
    return mBBox;
}

float32 BulletCharacterObject::mass() {
    return 0.f;
}

void BulletCharacterObject::load(Mesh::MeshdataPtr mesh) {
    LocationInfo& locinfo = mParent->info(mID);

    Vector3f objPosition = mParent->currentPosition(mID);
    Quaternion objOrient = mParent->currentOrientation(mID);
    btTransform startTransform = btTransform(
        btQuaternion(objOrient.x,objOrient.y,objOrient.z,objOrient.w),
        btVector3(objPosition.x,objPosition.y,objPosition.z)
    );

    mGhostObject = new btPairCachingGhostObject();
    mGhostObject->setWorldTransform(startTransform);
    mParent->broadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());

    // Currently only support spheres, TODO(ewencp) we might want to support
    // capsules instead.
    mCollisionShape = computeCollisionShape(mID, mBBox, Mesh::MeshdataPtr());
    mGhostObject->setCollisionShape(mCollisionShape);
    mGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);

    // TODO(ewencp) make this configurable?
    btScalar stepHeight = btScalar(0.5);
    // FIXME(ewencp) we know we're only allocating spheres/capsules for this, so
    // it's currently safe to do this cast, but technically
    // computeCollisionShape can compute concave shapes as well.
    mCharacter = new BulletCharacterController (mGhostObject, static_cast<btConvexShape*>(mCollisionShape), stepHeight);

    // Get mask information
    bulletObjCollisionMaskGroup mygroup, collide_with;
    BulletObject::getCollisionMask(BULLET_OBJECT_TREATMENT_CHARACTER, &mygroup, &collide_with);
    mParent->dynamicsWorld()->addCollisionObject(mGhostObject, (short)mygroup, (short)collide_with);
    mParent->dynamicsWorld()->addAction(mCharacter);

    mParent->addTickObject(mID);
    mParent->addDeactivateableObject(mID);
}

void BulletCharacterObject::unload() {
    if (mCharacter) {
        mParent->removeTickObject(mID);
        mParent->removeDeactivateableObject(mID);

        mParent->dynamicsWorld()->removeAction(mCharacter);
        mParent->dynamicsWorld()->removeCollisionObject(mGhostObject);

        delete mCharacter;
        mCharacter = NULL;

        delete mGhostObject;
        mGhostObject = NULL;

        delete mCollisionShape;
        mCollisionShape = NULL;
    }
}

void BulletCharacterObject::preTick(const Time& t) {
    LocationInfo& locinfo = mParent->info(mID);
    Vector3f char_vel = locinfo.location.velocity();
    btVector3 bt_char_vel(char_vel.x, char_vel.y, char_vel.z);
    mCharacter->setWalkDirection(bt_char_vel);
    // Character controller doesn't have any rotation support. Instead, we set
    // the rotation on the ghost object directly based on the requested
    // rotation. FIXME(ewencp) this needs some sort of handling similar to
    // walking direction where we know to stop the rotation at some point.
    btTransform xform = mGhostObject->getWorldTransform();
    btVector3 objPosition = xform.getOrigin();
    Quaternion objOrient = mParent->currentOrientation(mID);
    mGhostObject->setWorldTransform(
        btTransform(
            btQuaternion(objOrient.x, objOrient.y, objOrient.z, objOrient.w),
            objPosition
        )
    );
}

void BulletCharacterObject::postTick(const Time& t) {
    LocationInfo& locinfo = mParent->info(mID);

    btTransform worldTrans = mGhostObject->getWorldTransform();
    btVector3 pos = worldTrans.getOrigin();
    TimedMotionVector3f newLocation(t, MotionVector3f(Vector3f(pos.x(), pos.y(), pos.z()), locinfo.location.velocity()));

    btQuaternion rot = worldTrans.getRotation();
    TimedMotionQuaternion newOrientation(
        t,
        MotionQuaternion(
            Quaternion(rot.x(), rot.y(), rot.z(), rot.w()),
            locinfo.orientation.velocity()
        )
    );

    // Only update and report a change if it's big enough. This allows us to
    // stop sending updates if the object ends up essentially still.
    float32 pos_diff = (mParent->location(mID).position(t)-newLocation.position(t)).lengthSquared();
    // This test is easy, but also conservative...
    float32 angle1, angle2;
    Vector3f axis1, axis2;
    mParent->orientation(mID).position(t).toAngleAxis(angle1, axis1);
    newOrientation.position(t).toAngleAxis(angle2, axis2);
    // FIXME what should this really be? This approach doesn't seem to really
    // work because we sometimes get 0 vectors and the constants seem odd...
    bool orient_changed =
        (axis1.dot(axis2) < 0.9) || (fabs(angle1-angle2) > 3.14159/180);

    if (pos_diff > 0.001 || orient_changed) {
        mParent->setLocation(mID, newLocation);
        mParent->setOrientation(mID, newOrientation);
        mParent->addUpdate(mID);
    }
}

void BulletCharacterObject::deactivationTick(const Time& t) {
    if (mGhostObject != NULL && !mGhostObject->isActive())
        mParent->updateObjectFromDeactivation(mID);
}

} // namespace Sirikata
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the LICENSE
 * file in the root directory of this source tree.
 */
#include "mcrouter/lib/network/AsyncTlsToPlaintextSocket.h"

#include <chrono>
#include <functional>
#include <utility>

#include <folly/GLog.h>
#include <folly/ScopeGuard.h>
#include <folly/io/async/AsyncSocket.h>
#include <folly/portability/OpenSSL.h>

#include <thrift/lib/cpp/async/TAsyncSSLSocket.h>
#include <thrift/lib/cpp/async/TAsyncSocket.h>

namespace facebook {
namespace memcache {

class AsyncTlsToPlaintextSocket::ConnectCallback
    : public folly::AsyncSocket::ConnectCallback {
 public:
  ConnectCallback(
      AsyncTlsToPlaintextSocket& me,
      folly::AsyncSocket::ConnectCallback* connectCallback)
      : me_(me), connectCallback_(connectCallback) {}

  void connectSuccess() noexcept override {
    DestructorGuard dg{&me_};
    SCOPE_EXIT {
      if (auto* cb = std::exchange(connectCallback_, nullptr)) {
        cb->connectSuccess();
      }
      delete this;
    };

    auto& impl = me_.impl_;
    auto* tlsSocket =
        impl->getUnderlyingTransport<apache::thrift::async::TAsyncSSLSocket>();
    CHECK(tlsSocket);
    if (tlsSocket->getApplicationProtocol() != kMcSecurityTlsToPlaintextProto) {
      FB_LOG_EVERY_MS(ERROR, 10)
          << "Failed to negotiate plaintext fallback. Falling back to full TLS.";
      return;
    }

    // We need to mark the SSL as shutdown here, but need to do
    // it quietly so no alerts are sent over the wire.
    // This prevents SSL thinking we are shutting down in a bad state
    // when AsyncSSLSocket is cleaned up, which could remove the session
    // from the session cache
    auto* ssl = const_cast<SSL*>(tlsSocket->getSSL());
    SSL_set_quiet_shutdown(ssl, 1);
    SSL_shutdown(ssl);

    DCHECK_EQ(0, tlsSocket->getZeroCopyBufId());
    impl.reset(new apache::thrift::async::TAsyncSocket(
        &me_.evb_, tlsSocket->detachNetworkSocket().toFd()));
    impl->setSendTimeout(me_.writeTimeout_.count());
    impl->setReadCB(std::exchange(me_.readCallback_, nullptr));

    me_.state_ = State::CONNECTED;
    me_.flushWrites();
  }

  void connectErr(const folly::AsyncSocketException& ex) noexcept override {
    DestructorGuard dg{&me_};

    me_.failAllWrites(ex);
    if (auto* readCallback = std::exchange(me_.readCallback_, nullptr)) {
      readCallback->readErr(ex);
    }
    if (auto* cb = std::exchange(connectCallback_, nullptr)) {
      cb->connectErr(ex);
    }
    delete this;
  }

 private:
  AsyncTlsToPlaintextSocket& me_;
  folly::AsyncSocket::ConnectCallback* connectCallback_{nullptr};
};

void AsyncTlsToPlaintextSocket::connect(
    folly::AsyncSocket::ConnectCallback* connectCallback,
    const folly::SocketAddress& address,
    std::chrono::milliseconds connectTimeout,
    folly::AsyncSocket::OptionMap socketOptions) {
  auto* const wrappedConnectCallback =
      new ConnectCallback(*this, connectCallback);
  impl_->getUnderlyingTransport<apache::thrift::async::TAsyncSSLSocket>()
      ->connect(
          wrappedConnectCallback,
          address,
          connectTimeout.count(),
          std::move(socketOptions));
}

void AsyncTlsToPlaintextSocket::flushWrites() {
  while (!bufferedWrites_.empty()) {
    auto& bufferedWrite = bufferedWrites_.front();
    auto* cb = bufferedWrite.callback;
    auto buf = std::move(bufferedWrite.buf);
    bufferedWrites_.pop_front();

    impl_->writeChain(cb, std::move(buf));
  }
}

void AsyncTlsToPlaintextSocket::failAllWrites(
    const folly::AsyncSocketException& ex) {
  while (!bufferedWrites_.empty()) {
    auto& bufferedWrite = bufferedWrites_.front();
    auto* cb = bufferedWrite.callback;
    bufferedWrites_.pop_front();

    cb->writeErr(0, ex);
  }
}

} // namespace memcache
} // namespace facebook
<commit_msg>Fix AsyncTlsToPlaintextSocket on handshake failure<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the LICENSE
 * file in the root directory of this source tree.
 */
#include "mcrouter/lib/network/AsyncTlsToPlaintextSocket.h"

#include <chrono>
#include <functional>
#include <utility>

#include <folly/GLog.h>
#include <folly/ScopeGuard.h>
#include <folly/io/async/AsyncSocket.h>
#include <folly/portability/OpenSSL.h>

#include <thrift/lib/cpp/async/TAsyncSSLSocket.h>
#include <thrift/lib/cpp/async/TAsyncSocket.h>

namespace facebook {
namespace memcache {

class AsyncTlsToPlaintextSocket::ConnectCallback
    : public folly::AsyncSocket::ConnectCallback {
 public:
  ConnectCallback(
      AsyncTlsToPlaintextSocket& me,
      folly::AsyncSocket::ConnectCallback* connectCallback)
      : me_(me), connectCallback_(connectCallback) {}

  void connectSuccess() noexcept override {
    DestructorGuard dg{&me_};
    SCOPE_EXIT {
      if (auto* cb = std::exchange(connectCallback_, nullptr)) {
        cb->connectSuccess();
      }
      delete this;
    };

    auto& impl = me_.impl_;
    auto activateSocket = [&] {
      impl->setSendTimeout(me_.writeTimeout_.count());
      impl->setReadCB(std::exchange(me_.readCallback_, nullptr));

      me_.state_ = State::CONNECTED;
      me_.flushWrites();
    };

    auto* tlsSocket =
        impl->getUnderlyingTransport<apache::thrift::async::TAsyncSSLSocket>();
    CHECK(tlsSocket);
    if (tlsSocket->getApplicationProtocol() != kMcSecurityTlsToPlaintextProto) {
      FB_LOG_EVERY_MS(ERROR, 10)
          << "Failed to negotiate plaintext fallback. Falling back to full TLS.";
      // Even if the server fails the handshake, we must be sure to drain any
      // pending writes
      activateSocket();
      return;
    }

    // We need to mark the SSL as shutdown here, but need to do
    // it quietly so no alerts are sent over the wire.
    // This prevents SSL thinking we are shutting down in a bad state
    // when AsyncSSLSocket is cleaned up, which could remove the session
    // from the session cache
    auto* ssl = const_cast<SSL*>(tlsSocket->getSSL());
    SSL_set_quiet_shutdown(ssl, 1);
    SSL_shutdown(ssl);

    DCHECK_EQ(0, tlsSocket->getZeroCopyBufId());
    impl.reset(new apache::thrift::async::TAsyncSocket(
        &me_.evb_, tlsSocket->detachNetworkSocket().toFd()));
    activateSocket();
  }

  void connectErr(const folly::AsyncSocketException& ex) noexcept override {
    DestructorGuard dg{&me_};

    me_.failAllWrites(ex);
    if (auto* readCallback = std::exchange(me_.readCallback_, nullptr)) {
      readCallback->readErr(ex);
    }
    if (auto* cb = std::exchange(connectCallback_, nullptr)) {
      cb->connectErr(ex);
    }
    delete this;
  }

 private:
  AsyncTlsToPlaintextSocket& me_;
  folly::AsyncSocket::ConnectCallback* connectCallback_{nullptr};
};

void AsyncTlsToPlaintextSocket::connect(
    folly::AsyncSocket::ConnectCallback* connectCallback,
    const folly::SocketAddress& address,
    std::chrono::milliseconds connectTimeout,
    folly::AsyncSocket::OptionMap socketOptions) {
  auto* const wrappedConnectCallback =
      new ConnectCallback(*this, connectCallback);
  impl_->getUnderlyingTransport<apache::thrift::async::TAsyncSSLSocket>()
      ->connect(
          wrappedConnectCallback,
          address,
          connectTimeout.count(),
          std::move(socketOptions));
}

void AsyncTlsToPlaintextSocket::flushWrites() {
  while (!bufferedWrites_.empty()) {
    auto& bufferedWrite = bufferedWrites_.front();
    auto* cb = bufferedWrite.callback;
    auto buf = std::move(bufferedWrite.buf);
    bufferedWrites_.pop_front();

    impl_->writeChain(cb, std::move(buf));
  }
}

void AsyncTlsToPlaintextSocket::failAllWrites(
    const folly::AsyncSocketException& ex) {
  while (!bufferedWrites_.empty()) {
    auto& bufferedWrite = bufferedWrites_.front();
    auto* cb = bufferedWrite.callback;
    bufferedWrites_.pop_front();

    cb->writeErr(0, ex);
  }
}

} // namespace memcache
} // namespace facebook
<|endoftext|>