blob: 4b79c1a4e831a4575a79680238090d18564d04d4 [file] [log] [blame]
/*
* Copyright 2016 The Chromium OS 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 <fcntl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include "hal/usb_v1/arc_camera_service_provider.h"
#include "hal/usb_v1/ipc_util.h"
namespace arc {
constexpr char kArcCameraSocketPath[] = "/run/camera/camera.sock";
ArcCameraServiceProvider::ArcCameraServiceProvider() {
// Reap zombie processes when child process exited.
signal(SIGCHLD, SIG_IGN);
}
ArcCameraServiceProvider::~ArcCameraServiceProvider() {}
int ArcCameraServiceProvider::Start() {
base::FilePath socket_path(kArcCameraSocketPath);
// Set file permission to 0660.
// Container accesses the socket file by using arc-camera group.
umask(0117);
int raw_fd = -1;
if (!::internal::CreateServerUnixDomainSocket(socket_path, &raw_fd)) {
LOG(ERROR) << "CreateSreverUnixDomainSocket failed";
return -1;
}
base::ScopedFD socket_fd(raw_fd);
// Make socket blocking.
int flags = HANDLE_EINTR(fcntl(socket_fd.get(), F_GETFL));
if (flags == -1) {
PLOG(ERROR) << "fcntl(F_GETFL)";
return -1;
}
if (HANDLE_EINTR(fcntl(socket_fd.get(), F_SETFL, flags & ~O_NONBLOCK)) ==
-1) {
PLOG(ERROR) << "fcntl(F_SETFL) failed to disable O_NONBLOCK";
return -1;
}
while (1) {
int accept_fd = -1;
if (!::internal::ServerAcceptConnection(socket_fd.get(), &accept_fd)) {
PLOG(ERROR) << "Accept failed";
break;
}
if (accept_fd < 0) {
LOG(ERROR) << "Invalid accept fd: " << accept_fd;
} else {
VLOG(1) << "Accepted a client, fd: " << accept_fd;
pid_t child_pid = fork();
if (child_pid < 0) {
PLOG(ERROR) << "Fork failed";
continue;
}
if (child_pid == 0) { // child
return accept_fd;
} else { // parent
close(accept_fd);
}
}
}
return -1;
}
} // namespace arc