void PanoServerTCP::NewConnection() {
  // Open Socket to client.
  QTcpSocket* conn = server_->nextPendingConnection();
  
  if (!conn) {
    log("ERROR: can't establish connection to host.");
    return;
  }
  
  log (QString("Connected to peer :") + conn->peerAddress().toString());
  connections_.push_back(TcpConnection(conn));
  
  latest_conn_ = conn;
  QTimer::singleShot(500, this, SLOT(SendAllImages()));
  
  connect(conn, SIGNAL(readyRead()), this, SLOT(IncomingData()));
  connect(conn, SIGNAL(disconnected()), this, SLOT(ConnectionClosed()));
}
예제 #2
0
TcpConnection TcpListener::accept() {
  assert(system != nullptr);
  if (stopped) {
    throw std::runtime_error("Stopped");
  }

  void* context = system->getCurrentContext();
  boost::asio::ip::tcp::socket* socket = new boost::asio::ip::tcp::socket(*static_cast<boost::asio::io_service*>(system->getIoService()));
  boost::system::error_code errorCode;
  static_cast<boost::asio::ip::tcp::acceptor*>(listener)->async_accept(*socket, [&](const boost::system::error_code& callbackErrorCode) {
    errorCode = callbackErrorCode;
    system->pushContext(context);
  });

  system->yield();
  if (errorCode) {
    delete socket;
    throw boost::system::system_error(errorCode);
  }

  return TcpConnection(*system, socket);
}
void PanoServerTCP::ConnectionClosed() {
  // Remove from peer list.
  QTcpSocket* conn = (QTcpSocket*) sender();
  log (QString("WARNING: Connection to peer ") + conn->peerAddress().toString() + " closed.");
  
  vector<TcpConnection>::iterator i = std::find(connections_.begin(),
                                                connections_.end(),
                                                TcpConnection(conn));
  vector<ImageInfo>& img_infos = view_->getImageInfos();
  for (vector<ImageInfo>::iterator ii = img_infos.begin();
       ii != img_infos.end();
       ++ii) {
    if (ii->locked_by == conn) {
      ii->locked_by = 0;
      SendReleaseToClients(ii->img_id);
    }
  }
  
  if (i != connections_.end())
    connections_.erase(i);
  
  conn->deleteLater();
}
예제 #4
0
TcpConnection TcpListener::accept() {
  assert(dispatcher != nullptr);
  assert(context == nullptr);
  if (dispatcher->interrupted()) {
    throw InterruptedException();
  }

  std::string message;
  SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (connection == INVALID_SOCKET) {
    message = "socket failed, " + errorMessage(WSAGetLastError());
  } else {
    uint8_t addresses[sizeof sockaddr_in * 2 + 32];
    DWORD received;
    TcpListenerContext context2;
    context2.hEvent = NULL;
    if (acceptEx(listener, connection, addresses, 0, sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &received, &context2) == TRUE) {
      message = "AcceptEx returned immediately, which is not supported.";
    } else {
      int lastError = WSAGetLastError();
      if (lastError != WSA_IO_PENDING) {
        message = "AcceptEx failed, " + errorMessage(lastError);
      } else {
        context2.context = dispatcher->getCurrentContext();
        context2.interrupted = false;
        context = &context2;
        dispatcher->getCurrentContext()->interruptProcedure = [&]() {
          assert(dispatcher != nullptr);
          assert(context != nullptr);
          TcpListenerContext* context2 = static_cast<TcpListenerContext*>(context);
          if (!context2->interrupted) {
            if (CancelIoEx(reinterpret_cast<HANDLE>(listener), context2) != TRUE) {
              DWORD lastError = GetLastError();
              if (lastError != ERROR_NOT_FOUND) {
                throw std::runtime_error("TcpListener::stop, CancelIoEx failed, " + lastErrorMessage());
              }

              context2->context->interrupted = true;
            }

            context2->interrupted = true;
          }
        };

        dispatcher->dispatch();
        dispatcher->getCurrentContext()->interruptProcedure = nullptr;
        assert(context2.context == dispatcher->getCurrentContext());
        assert(dispatcher != nullptr);
        assert(context == &context2);
        context = nullptr;
        DWORD transferred;
        DWORD flags;
        if (WSAGetOverlappedResult(listener, &context2, &transferred, FALSE, &flags) != TRUE) {
          lastError = WSAGetLastError();
          if (lastError != ERROR_OPERATION_ABORTED) {
            message = "AcceptEx failed, " + errorMessage(lastError);
          } else {
            assert(context2.interrupted);
            if (closesocket(connection) != 0) {
              throw std::runtime_error("TcpListener::accept, closesocket failed, " + errorMessage(WSAGetLastError()));
            } else {
              throw InterruptedException();
            }
          }
        } else {
          assert(transferred == 0);
          assert(flags == 0);
          if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast<char*>(&listener), sizeof listener) != 0) {
            message = "setsockopt failed, " + errorMessage(WSAGetLastError());
          } else {
            if (CreateIoCompletionPort(reinterpret_cast<HANDLE>(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) {
              message = "CreateIoCompletionPort failed, " + lastErrorMessage();
            } else {
              return TcpConnection(*dispatcher, connection);
            }
          }
        }
      }
    }

    int result = closesocket(connection);
    assert(result == 0);
  }

  throw std::runtime_error("TcpListener::accept, " + message);
}
예제 #5
0
TcpConnection TcpListener::accept() {
  assert(dispatcher != nullptr);
  assert(context == nullptr);
  if (dispatcher->interrupted()) {
    throw InterruptedException();
  }

  ContextPair contextPair;
  OperationContext listenerContext;
  listenerContext.interrupted = false;
  listenerContext.context = dispatcher->getCurrentContext();

  contextPair.writeContext = nullptr;
  contextPair.readContext = &listenerContext;

  epoll_event listenEvent;
  listenEvent.events = EPOLLIN | EPOLLONESHOT;
  listenEvent.data.ptr = &contextPair;
  std::string message;
  if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) {
    message = "epoll_ctl failed, " + lastErrorMessage();
  } else {
    context = &listenerContext;
    dispatcher->getCurrentContext()->interruptProcedure = [&]() {
        assert(dispatcher != nullptr);
        assert(context != nullptr);
        OperationContext* listenerContext = static_cast<OperationContext*>(context);
        if (!listenerContext->interrupted) {
          epoll_event listenEvent;
          listenEvent.events = 0;
          listenEvent.data.ptr = nullptr;

          if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) {
            throw std::runtime_error("TcpListener::stop, epoll_ctl failed, " + lastErrorMessage() );
          }

          listenerContext->interrupted = true;
          dispatcher->pushContext(listenerContext->context);
        }
    };

    dispatcher->dispatch();
    dispatcher->getCurrentContext()->interruptProcedure = nullptr;
    assert(dispatcher != nullptr);
    assert(listenerContext.context == dispatcher->getCurrentContext());
    assert(contextPair.writeContext == nullptr);
    assert(context == &listenerContext);
    context = nullptr;
    listenerContext.context = nullptr;
    if (listenerContext.interrupted) {
      throw InterruptedException();
    }

    if((listenerContext.events & (EPOLLERR | EPOLLHUP)) != 0) {
      throw std::runtime_error("TcpListener::accept, accepting failed");
    }

    sockaddr inAddr;
    socklen_t inLen = sizeof(inAddr);
    int connection = ::accept(listener, &inAddr, &inLen);
    if (connection == -1) {
      message = "accept failed, " + lastErrorMessage();
    } else {
      int flags = fcntl(connection, F_GETFL, 0);
      if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) {
        message = "fcntl failed, " + lastErrorMessage();
      } else {
        return TcpConnection(*dispatcher, connection);
      }

      int result = close(connection);
      assert(result != -1);
    }
  }

  throw std::runtime_error("TcpListener::accept, " + message);
}
TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
  assert(dispatcher != nullptr);
  assert(context == nullptr);
  if (dispatcher->interrupted()) {
    throw InterruptedException();
  }

  std::string message;
  int connection = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (connection == -1) {
    message = "socket failed, " + lastErrorMessage();
  } else {
    sockaddr_in bindAddress;
    bindAddress.sin_family = AF_INET;
    bindAddress.sin_port = 0;
    bindAddress.sin_addr.s_addr = INADDR_ANY;
    if (bind(connection, reinterpret_cast<sockaddr*>(&bindAddress), sizeof bindAddress) != 0) {
      message = "bind failed, " + lastErrorMessage();
    } else {
      int flags = fcntl(connection, F_GETFL, 0);
      if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) {
        message = "fcntl failed, " + lastErrorMessage();
      } else {
        sockaddr_in addressData;
        addressData.sin_family = AF_INET;
        addressData.sin_port = htons(port);
        addressData.sin_addr.s_addr = htonl(address.getValue());
        int result = ::connect(connection, reinterpret_cast<sockaddr *>(&addressData), sizeof addressData);
        if (result == -1) {
          if (errno == EINPROGRESS) {
            ConnectorContext connectorContext;
            connectorContext.context = dispatcher->getCurrentContext();
            connectorContext.interrupted = false;
            connectorContext.connection = connection;

            struct kevent event;
            EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, &connectorContext);
            if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
              message = "kevent failed, " + lastErrorMessage();
            } else {
              context = &connectorContext;
              dispatcher->getCurrentContext()->interruptProcedure = [&] {
                assert(dispatcher != nullptr);
                assert(context != nullptr);
                ConnectorContext* connectorContext = static_cast<ConnectorContext*>(context);
                if (!connectorContext->interrupted) {
                  if (close(connectorContext->connection) == -1) {
                    throw std::runtime_error("TcpListener::stop, close failed, " + lastErrorMessage());
                  }
                  
                  dispatcher->pushContext(connectorContext->context);
                  connectorContext->interrupted = true;
                }                
              };
              
              dispatcher->dispatch();
              dispatcher->getCurrentContext()->interruptProcedure = nullptr;
              assert(dispatcher != nullptr);
              assert(connectorContext.context == dispatcher->getCurrentContext());
              assert(context == &connectorContext);
              context = nullptr;
              connectorContext.context = nullptr;
              if (connectorContext.interrupted) {
                throw InterruptedException();
              }

              struct kevent event;
              EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_DISABLE, 0, 0, NULL);

              if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
                message = "kevent failed, " + lastErrorMessage();
              } else {
                int retval = -1;
                socklen_t retValLen = sizeof(retval);
                int s = getsockopt(connection, SOL_SOCKET, SO_ERROR, &retval, &retValLen);
                if (s == -1) {
                  message = "getsockopt failed, " + lastErrorMessage();
                } else {
                  if (retval != 0) {
                    message = "getsockopt failed, " + lastErrorMessage();
                  } else {
                    return TcpConnection(*dispatcher, connection);
                  }
                }
              }
            }
          }
        } else {
          return TcpConnection(*dispatcher, connection);
        }
      }
    }

    int result = close(connection);
    if (result) {}
    assert(result != -1);;
  }

  throw std::runtime_error("TcpConnector::connect, " + message);
}
예제 #7
0
TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
  assert(dispatcher != nullptr);
  assert(context == nullptr);
  if (dispatcher->interrupted()) {
    throw InterruptedException();
  }

  std::string message;
  SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (connection == INVALID_SOCKET) {
    message = "socket failed, result=" + std::to_string(WSAGetLastError());
  } else {
    sockaddr_in bindAddress;
    bindAddress.sin_family = AF_INET;
    bindAddress.sin_port = 0;
    bindAddress.sin_addr.s_addr = INADDR_ANY;
    if (bind(connection, reinterpret_cast<sockaddr*>(&bindAddress), sizeof bindAddress) != 0) {
      message = "bind failed, result=" + std::to_string(WSAGetLastError());
    } else {
      GUID guidConnectEx = WSAID_CONNECTEX;
      DWORD read = sizeof connectEx;
      if (connectEx == nullptr && WSAIoctl(connection, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConnectEx, sizeof guidConnectEx, &connectEx, sizeof connectEx, &read, NULL, NULL) != 0) {
        message = "WSAIoctl failed, result=" + std::to_string(WSAGetLastError());
      } else {
        assert(read == sizeof connectEx);
        if (CreateIoCompletionPort(reinterpret_cast<HANDLE>(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) {
          message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError());
        } else {
          sockaddr_in addressData;
          addressData.sin_family = AF_INET;
          addressData.sin_port = htons(port);
          addressData.sin_addr.S_un.S_addr = htonl(address.getValue());
          TcpConnectorContext context2;
          context2.hEvent = NULL;
          if (connectEx(connection, reinterpret_cast<sockaddr*>(&addressData), sizeof addressData, NULL, 0, NULL, &context2) == TRUE) {
            message = "ConnectEx returned immediately, which is not supported.";
          } else {
            int lastError = WSAGetLastError();
            if (lastError != WSA_IO_PENDING) {
              message = "ConnectEx failed, result=" + std::to_string(lastError);
            } else {
              context2.context = dispatcher->getCurrentContext();
              context2.connection = connection;
              context2.interrupted = false;
              context = &context2;
              dispatcher->getCurrentContext()->interruptProcedure = [&]() {
                assert(dispatcher != nullptr);
                assert(context != nullptr);
                TcpConnectorContext* context2 = static_cast<TcpConnectorContext*>(context);
                if (!context2->interrupted) {
                  if (CancelIoEx(reinterpret_cast<HANDLE>(context2->connection), context2) != TRUE) {
                    DWORD lastError = GetLastError();
                    if (lastError != ERROR_NOT_FOUND) {
                      throw std::runtime_error("TcpConnector::stop, CancelIoEx failed, result=" + std::to_string(GetLastError()));
                    }

                    context2->context->interrupted = true;
                  }

                  context2->interrupted = true;
                }
              };

              dispatcher->dispatch();
              dispatcher->getCurrentContext()->interruptProcedure = nullptr;
              assert(context2.context == dispatcher->getCurrentContext());
              assert(context2.connection == connection);
              assert(dispatcher != nullptr);
              assert(context == &context2);
              context = nullptr;
              DWORD transferred;
              DWORD flags;
              if (WSAGetOverlappedResult(connection, &context2, &transferred, FALSE, &flags) != TRUE) {
                lastError = WSAGetLastError();
                if (lastError != ERROR_OPERATION_ABORTED) {
                  message = "ConnectEx failed, result=" + std::to_string(lastError);
                } else {
                  assert(context2.interrupted);
                  if (closesocket(connection) != 0) {
                    throw std::runtime_error("TcpConnector::connect, closesocket failed, result=" + std::to_string(WSAGetLastError()));
                  } else {
                    throw InterruptedException();
                  }
                }
              } else {
                assert(transferred == 0);
                assert(flags == 0);
                DWORD value = 1;
                if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, reinterpret_cast<char*>(&value), sizeof(value)) != 0) {
                  message = "setsockopt failed, result=" + std::to_string(WSAGetLastError());
                } else {
                  return TcpConnection(*dispatcher, connection);
                }
              }
            }
          }
        }
      }
    }

    int result = closesocket(connection);
    assert(result == 0);
  }

  throw std::runtime_error("TcpConnector::connect, " + message);
}
예제 #8
0
TcpConnection TcpListener::accept() {
  assert(dispatcher != nullptr);
  assert(context == nullptr);
  if (dispatcher->interrupted()) {
    throw InterruptedException();
  }

  std::string message;
  OperationContext listenerContext;
  listenerContext.context = dispatcher->getCurrentContext();
  listenerContext.interrupted = false;
  struct kevent event;
  EV_SET(&event, listener, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR , 0, SOMAXCONN, &listenerContext);
  if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
    message = "kevent() failed, errno=" + std::to_string(errno);
  } else {
    context = &listenerContext;
    dispatcher->getCurrentContext()->interruptProcedure = [&] {
      assert(dispatcher != nullptr);
      assert(context != nullptr);
      OperationContext* listenerContext = static_cast<OperationContext*>(context);
      if (!listenerContext->interrupted) {
        
        struct kevent event;
        EV_SET(&event, listener, EVFILT_READ, EV_DELETE | EV_DISABLE, 0, 0, NULL);
        
        if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
          throw std::runtime_error("TcpListener::stop, kevent() failed, errno=" + std::to_string(errno));
        }
        
        listenerContext->interrupted = true;
        dispatcher->pushContext(listenerContext->context);
      }
    };
    
    dispatcher->dispatch();
    dispatcher->getCurrentContext()->interruptProcedure = nullptr;
    assert(dispatcher != nullptr);
    assert(listenerContext.context == dispatcher->getCurrentContext());
    assert(context == &listenerContext);
    context = nullptr;
    listenerContext.context = nullptr;
    if (listenerContext.interrupted) {
      throw InterruptedException();
    }

    sockaddr inAddr;
    socklen_t inLen = sizeof(inAddr);
    int connection = ::accept(listener, &inAddr, &inLen);
    if (connection == -1) {
      message = "accept() failed, errno=" + std::to_string(errno);
    } else {
      int flags = fcntl(connection, F_GETFL, 0);
      if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) {
        message = "fcntl() failed errno=" + std::to_string(errno);
      } else {
        return TcpConnection(*dispatcher, connection);
      }
    }
  }

  throw std::runtime_error("TcpListener::accept, " + message);
}
void PanoServerTCP::IncomingData() {
  QTcpSocket* conn = (QTcpSocket*) sender();
  vector<TcpConnection>::iterator host = std::find(connections_.begin(),
                                                   connections_.end(),
                                                   TcpConnection(conn));
  
  if (host == connections_.end()) {
    log("Client to registered at TCP server.");
    return;
  }
  
  if (conn->bytesAvailable() <= 0) {
    log("Error on incoming data. Packet is empty!");
    return;
  }
  
  QByteArray data = conn->readAll();
  int data_pos = 0;
  
  // Multiple packages possible.
  while (data_pos < data.length()) {
    // Continue package?
    if (host->pkg.length()) {
      int remaining_data_bytes = data.length() - data_pos;
      int remaining_bytes = host->target_sz - host->pkg.length();
      
      if (remaining_data_bytes <= remaining_bytes) {
        host->pkg.append(data.mid(data_pos, remaining_data_bytes));
        data_pos += remaining_data_bytes;
      } else {
        // Another package is waiting.
        host->pkg.append(data.mid(data_pos, remaining_bytes));
        data_pos += remaining_bytes;
      }
      
    } else {
      // New package.
      QDataStream data_stream(data.mid(data_pos));
      data_stream.setByteOrder(QDataStream::LittleEndian);
      int msg_id;
      int length;
      
      data_stream >> msg_id;
      data_stream >> length;
      
      data_pos += sizeof(int) * 2;
      int remaining_data_bytes = data.length() - data_pos;
      
      switch (msg_id) {
        case 0x13030002: 
        {
          log("New image uploaded");          
          // Most likely more packages are incoming ...
          host->target_sz = length;
          host->msg_id = msg_id;
          
          if (length > remaining_data_bytes) {
            host->pkg.append(data.mid(data_pos, remaining_data_bytes));
            data_pos += remaining_data_bytes;
          } else {
            host->pkg.append(data.mid(data_pos, length));
            data_pos += length;
          }
          break;
        }
        case 0x13030005:
        {
          // Image lock request.
          QDataStream img_id_stream(data.mid(data_pos));
          img_id_stream.setByteOrder(QDataStream::LittleEndian);
          int img_id;
          img_id_stream >> img_id;
          data_pos += sizeof(int);
          
          if (view_->aquireLock(img_id, conn)) {
            // Notify all clients.
            SendLockToClients(img_id);
          } else {
            log("Failed lock request from client. Lock already aquired.");
          }
          
          break;
        }
        case 0x13030006:
        {
          // Image release request.
          QDataStream img_id_stream(data.mid(data_pos));
          img_id_stream.setByteOrder(QDataStream::LittleEndian);
          int img_id;
          img_id_stream >> img_id;
          data_pos += sizeof(int);
          
          if (view_->releaseLock(img_id, conn)) {
            // Notify all clients.
            SendReleaseToClients(img_id);
          } else {
            log("Failed release request. Inconsistency error occured.\n");
          }
          
          break;
        }
        default:
          log("Unknown package incoming!");
          break;
      }
    }
      
    // Read completely?
    if (host->pkg.length() == host->target_sz) {
      switch(host->msg_id) {
        case 0x13030002:
        {
          // Get initial transformation.
          QDataStream pkg_stream(host->pkg);
          pkg_stream.setByteOrder(QDataStream::LittleEndian);
          float scale, rotation, trans_x, trans_y;
          pkg_stream >> scale >> rotation >> trans_x >> trans_y;
          
          QByteArray img_data = host->pkg.mid(sizeof(float) * 4);
          QImage img = QImage::fromData(img_data, "png");
          int img_id = view_->AddImage(img);
          log(QString("Assigned id ") + QString::number(img_id) + " to image. Sending ACK.");
          view_->updateImgPosition(img_id, scale, rotation, trans_x, trans_y);
          
          // Send img_id back.
          QByteArray img_id_package;
          int img_id_sz = sizeof(int);
          QDataStream img_id_stream(&img_id_package, QIODevice::WriteOnly);
          img_id_stream.setByteOrder(QDataStream::LittleEndian);
          img_id_stream << 0x13030003 << img_id_sz << img_id;
          Write(img_id_package, conn, 0);
          
          // Send to remaining cients.
          QByteArray to_send;
          QDataStream send_stream(&to_send, QIODevice::WriteOnly);
          send_stream.setByteOrder(QDataStream::LittleEndian);
          
          int preload_sz = sizeof(float) * 4 + sizeof(int);
          int total_sz = preload_sz + img_data.size();
          send_stream << host->msg_id << total_sz
                      << img_id << scale << rotation << trans_x << trans_y;
          
          to_send.append(img_data);
          
          Write(to_send, 0, conn);
          break;
        }
        default:
          break;
      }
      host->pkg.clear();
    }
  }
}