blob: d1eed670ddb482eb796c3e226eb7627338aa23cd [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 "util.h"
#include <poll.h>
#include "gtest/gtest.h"
const uint8_t kNotifySuccess = 1;
const uint8_t kNotifyFail = 2;
void NotifySuccess(int ntfyfd) {
uint8_t c = kNotifySuccess;
EXPECT_EQ(1, write(ntfyfd, &c, 1));
}
void NotifyFail(int ntfyfd) {
uint8_t c = kNotifyFail;
EXPECT_EQ(1, write(ntfyfd, &c, 1));
}
bool WaitSuccess(int ntfyfd, int timeout) {
struct pollfd fds = {ntfyfd, POLLIN, 0};
int nfds = poll(&fds, 1, timeout);
EXPECT_GE(nfds, 0) << "poll failed: " << errno;
if (nfds == 1) {
uint8_t c = kNotifyFail;
EXPECT_EQ(1, read(ntfyfd, &c, 1));
return kNotifySuccess == c;
} else {
EXPECT_EQ(1, nfds);
return false;
}
}
void StreamAcceptRead(int acptfd, std::string* out, int ntfyfd) {
int connfd = accept(acptfd, nullptr, nullptr);
EXPECT_GE(connfd, 0) << "accept failed: " << errno;
if (connfd < 0) {
NotifyFail(ntfyfd);
return;
}
int n;
char buf[4096];
while ((n = read(connfd, buf, sizeof(buf))) > 0) {
out->append(buf, n);
}
EXPECT_EQ(0, close(connfd));
NotifySuccess(ntfyfd);
}
void StreamConnectRead(struct sockaddr_in* addr, std::string* out, int ntfyfd) {
int connfd = socket(AF_INET, SOCK_STREAM, 0);
EXPECT_GE(connfd, 0);
if (connfd < 0) {
NotifyFail(ntfyfd);
return;
}
int ret = connect(connfd, (const struct sockaddr*)addr, sizeof(*addr));
EXPECT_EQ(0, ret) << strerror(errno);
if (ret != 0) {
NotifyFail(ntfyfd);
return;
}
int n;
char buf[4096];
while ((n = read(connfd, buf, sizeof(buf))) > 0) {
out->append(buf, n);
}
EXPECT_EQ(close(connfd), 0);
NotifySuccess(ntfyfd);
}
void StreamAcceptWrite(int acptfd, const char* msg, int ntfyfd) {
int connfd = accept(acptfd, nullptr, nullptr);
EXPECT_GE(connfd, 0) << "accept failed: " << errno;
if (connfd < 0) {
NotifyFail(ntfyfd);
return;
}
ASSERT_EQ((ssize_t)strlen(msg), write(connfd, msg, strlen(msg)));
EXPECT_EQ(0, close(connfd));
NotifySuccess(ntfyfd);
}
void PollSignal(struct sockaddr_in* addr, short events, short* revents,
int ntfyfd) {
int connfd = socket(AF_INET, SOCK_STREAM, 0);
ASSERT_GE(connfd, 0);
int ret = connect(connfd, (const struct sockaddr*)addr, sizeof(*addr));
EXPECT_EQ(0, ret) << "connect failed: " << errno;
if (ret != 0) {
NotifyFail(ntfyfd);
return;
}
struct pollfd fds = {connfd, events, 0};
int n = poll(&fds, 1, kTimeout);
EXPECT_GT(n, 0) << "poll failed: " << errno;
if (n <= 0) {
NotifyFail(ntfyfd);
return;
}
EXPECT_EQ(0, close(connfd));
*revents = fds.revents;
NotifySuccess(ntfyfd);
}
void DatagramRead(int recvfd, std::string* out, struct sockaddr_in* addr,
socklen_t* addrlen, int ntfyfd, int timeout) {
struct pollfd fds = {recvfd, POLLIN, 0};
int nfds = poll(&fds, 1, timeout);
EXPECT_EQ(1, nfds) << "poll returned: " << nfds << " errno: " << errno;
if (nfds != 1) {
NotifyFail(ntfyfd);
return;
}
char buf[4096];
int nbytes =
recvfrom(recvfd, buf, sizeof(buf), 0, (struct sockaddr*)addr, addrlen);
EXPECT_GT(nbytes, 0) << "recvfrom failed: " << errno;
if (nbytes < 0) {
NotifyFail(ntfyfd);
return;
}
out->append(buf, nbytes);
NotifySuccess(ntfyfd);
}
void DatagramReadWrite(int recvfd, int ntfyfd) {
struct pollfd fds = {recvfd, POLLIN, 0};
int nfds = poll(&fds, 1, kTimeout);
EXPECT_EQ(1, nfds) << "poll returned: " << nfds << " errno: " << errno;
if (nfds != 1) {
NotifyFail(ntfyfd);
return;
}
char buf[32];
struct sockaddr_in peer;
socklen_t peerlen = sizeof(peer);
int nbytes = recvfrom(recvfd, buf, sizeof(buf), 0,
reinterpret_cast<struct sockaddr*>(&peer), &peerlen);
EXPECT_GE(nbytes, 0) << "recvfrom failed: " << errno;
if (nbytes < 0) {
NotifyFail(ntfyfd);
return;
}
#if DEBUG
char addrstr[INET_ADDRSTRLEN];
printf("peer.sin_addr: %s\n",
inet_ntop(AF_INET, &peer.sin_addr, addrstr, sizeof(addrstr)));
printf("peer.sin_port: %d\n", ntohs(peer.sin_port));
printf("peerlen: %d\n", peerlen);
#endif
nbytes = sendto(recvfd, buf, nbytes, 0,
reinterpret_cast<struct sockaddr*>(&peer), peerlen);
EXPECT_GE(nbytes, 0) << "sendto failed: " << errno;
if (nbytes < 0) {
NotifyFail(ntfyfd);
return;
}
NotifySuccess(ntfyfd);
}
void DatagramReadWriteV6(int recvfd, int ntfyfd) {
struct pollfd fds = {recvfd, POLLIN, 0};
int nfds = poll(&fds, 1, kTimeout);
EXPECT_EQ(1, nfds) << "poll returned: " << nfds << " errno: " << errno;
if (nfds != 1) {
NotifyFail(ntfyfd);
return;
}
char buf[32];
struct sockaddr_in6 peer;
socklen_t peerlen = sizeof(peer);
int nbytes = recvfrom(recvfd, buf, sizeof(buf), 0,
reinterpret_cast<struct sockaddr*>(&peer), &peerlen);
EXPECT_GE(nbytes, 0) << "recvfrom failed: " << errno;
if (nbytes < 0) {
NotifyFail(ntfyfd);
return;
}
#if DEBUG
char addrstr[INET_ADDRSTRLEN];
printf("peer.sin6_addr: %s\n",
inet_ntop(AF_INET6, &peer.sin6_addr, addrstr, sizeof(addrstr)));
printf("peer.sin6_port: %d\n", ntohs(peer.sin6_port));
printf("peerlen: %d\n", peerlen);
#endif
nbytes = sendto(recvfd, buf, nbytes, 0,
reinterpret_cast<struct sockaddr*>(&peer), peerlen);
EXPECT_GE(nbytes, 0) << "sendto failed: " << errno;
if (nbytes < 0) {
NotifyFail(ntfyfd);
return;
}
NotifySuccess(ntfyfd);
}