mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 01:13:23 +00:00
Format code automatically for regression tests
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
60cd65d837
commit
82de200d03
2
Makefile
2
Makefile
@ -157,6 +157,7 @@ docs: $(CARGO_OSDK)
|
|||||||
.PHONY: format
|
.PHONY: format
|
||||||
format:
|
format:
|
||||||
@./tools/format_all.sh
|
@./tools/format_all.sh
|
||||||
|
@make --no-print-directory -C regression format
|
||||||
|
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: $(CARGO_OSDK)
|
check: $(CARGO_OSDK)
|
||||||
@ -175,6 +176,7 @@ check: $(CARGO_OSDK)
|
|||||||
@for dir in $(OSDK_CRATES); do \
|
@for dir in $(OSDK_CRATES); do \
|
||||||
(cd $$dir && cargo osdk clippy -- -- -D warnings) || exit 1; \
|
(cd $$dir && cargo osdk clippy -- -- -D warnings) || exit 1; \
|
||||||
done
|
done
|
||||||
|
@make --no-print-directory -C regression check
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
@ -120,6 +120,14 @@ $(EXT2_IMAGE):
|
|||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: $(INITRAMFS_IMAGE) $(EXT2_IMAGE)
|
build: $(INITRAMFS_IMAGE) $(EXT2_IMAGE)
|
||||||
|
|
||||||
|
.PHONY: format
|
||||||
|
format:
|
||||||
|
@make --no-print-directory -C apps format
|
||||||
|
|
||||||
|
.PHONY: check
|
||||||
|
check:
|
||||||
|
@make --no-print-directory -C apps check
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(BUILD_DIR)
|
@rm -rf $(BUILD_DIR)
|
||||||
|
125
regression/apps/.clang-format
Normal file
125
regression/apps/.clang-format
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
#
|
||||||
|
# This file was copied from Linux kernel, or more precisely, from:
|
||||||
|
#
|
||||||
|
# https://github.com/torvalds/linux/blob/e5eb28f6d1afebed4bb7d740a797d0390bd3a357/.clang-format
|
||||||
|
#
|
||||||
|
# We have removed the long but useless `ForEachMacros` option.
|
||||||
|
|
||||||
|
# clang-format configuration file. Intended for clang-format >= 11.
|
||||||
|
#
|
||||||
|
# For more information, see:
|
||||||
|
#
|
||||||
|
# Documentation/process/clang-format.rst
|
||||||
|
# https://clang.llvm.org/docs/ClangFormat.html
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||||
|
#
|
||||||
|
---
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: false
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 8
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentGotoLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 8
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 8
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
|
||||||
|
# Taken from git's rules
|
||||||
|
PenaltyBreakAssignment: 10
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 30
|
||||||
|
PenaltyBreakComment: 10
|
||||||
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakString: 10
|
||||||
|
PenaltyExcessCharacter: 100
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatementsExceptForEachMacros
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp03
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Always
|
||||||
|
...
|
@ -1,12 +1,17 @@
|
|||||||
# SPDX-License-Identifier: MPL-2.0
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
MAKEFLAGS += --no-builtin-rules # Prevent the implicit rules from compiling ".c" or ".s" files automatically.
|
MAKEFLAGS += --no-builtin-rules # Prevent the implicit rules from compiling ".c" or ".s" files automatically.
|
||||||
|
|
||||||
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
|
CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
|
||||||
|
|
||||||
INITRAMFS ?= $(CUR_DIR)/../build/initramfs
|
INITRAMFS ?= $(CUR_DIR)/../build/initramfs
|
||||||
REGRESSION_BUILD_DIR ?= $(INITRAMFS)/regression
|
REGRESSION_BUILD_DIR ?= $(INITRAMFS)/regression
|
||||||
|
|
||||||
TEST_APPS := signal_c pthread network hello_world hello_pie hello_c fork_c fork execve pty
|
TEST_APPS := signal_c pthread network hello_world hello_pie hello_c fork_c fork execve pty
|
||||||
|
|
||||||
|
C_SOURCES := $(shell find . -type f \( -name "*.c" -or -name "*.h" \) )
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(TEST_APPS) scripts
|
all: $(TEST_APPS) scripts
|
||||||
|
|
||||||
@ -14,6 +19,16 @@ all: $(TEST_APPS) scripts
|
|||||||
$(TEST_APPS):
|
$(TEST_APPS):
|
||||||
@make --no-print-directory -C $@
|
@make --no-print-directory -C $@
|
||||||
|
|
||||||
|
.PHONY: format
|
||||||
|
format:
|
||||||
|
@echo "Fixing code format for regression tests..."
|
||||||
|
@clang-format -i $(C_SOURCES)
|
||||||
|
|
||||||
|
.PHONY: check
|
||||||
|
check:
|
||||||
|
@echo "Checking code format for regression tests..."
|
||||||
|
@clang-format --dry-run --Werror $(C_SOURCES)
|
||||||
|
|
||||||
$(REGRESSION_BUILD_DIR):
|
$(REGRESSION_BUILD_DIR):
|
||||||
@mkdir -p $@
|
@mkdir -p $@
|
||||||
|
|
||||||
|
@ -3,15 +3,16 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
char* argv[] = { "argv1", "argv2", NULL };
|
{
|
||||||
char* envp[] = { "home=/", "version=1.1", NULL };
|
char *argv[] = { "argv1", "argv2", NULL };
|
||||||
// The hello will be put at /execve/hello in InitRamfs
|
char *envp[] = { "home=/", "version=1.1", NULL };
|
||||||
printf("Execve a new file /execve/hello:\n");
|
// The hello will be put at /execve/hello in InitRamfs
|
||||||
// flush the stdout content to ensure the content print to console
|
printf("Execve a new file /execve/hello:\n");
|
||||||
fflush(stdout);
|
// flush the stdout content to ensure the content print to console
|
||||||
execve("/regression/execve/hello", argv, envp);
|
fflush(stdout);
|
||||||
printf("Should not print\n");
|
execve("/regression/execve/hello", argv, envp);
|
||||||
fflush(stdout);
|
printf("Should not print\n");
|
||||||
return 0;
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -2,17 +2,18 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *envp[]) {
|
int main(int argc, char *argv[], char *envp[])
|
||||||
printf("Hello world from hello.c(execved in execve.c)!\n");
|
{
|
||||||
printf("argc = %d\n", argc);
|
printf("Hello world from hello.c(execved in execve.c)!\n");
|
||||||
for(int i = 0; i < argc; i++) {
|
printf("argc = %d\n", argc);
|
||||||
printf("%s\n", argv[i]);
|
for (int i = 0; i < argc; i++) {
|
||||||
}
|
printf("%s\n", argv[i]);
|
||||||
for(int i = 0 ;; i++) {
|
}
|
||||||
if (envp[i] == NULL) {
|
for (int i = 0;; i++) {
|
||||||
break;
|
if (envp[i] == NULL) {
|
||||||
}
|
break;
|
||||||
printf("%s\n", envp[i]);
|
}
|
||||||
}
|
printf("%s\n", envp[i]);
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -3,14 +3,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
printf("before fork\n");
|
{
|
||||||
fflush(stdout);
|
printf("before fork\n");
|
||||||
if(fork() == 0) {
|
fflush(stdout);
|
||||||
printf("after fork: Hello from child\n");
|
if (fork() == 0) {
|
||||||
} else {
|
printf("after fork: Hello from child\n");
|
||||||
printf("after fork: Hello from parent\n");
|
} else {
|
||||||
}
|
printf("after fork: Hello from parent\n");
|
||||||
fflush(stdout);
|
}
|
||||||
return 0;
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
printf("hello world from hello_c!\n");
|
{
|
||||||
return 0;
|
printf("hello world from hello_c!\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
printf("hello world from hello_pie!\n");
|
{
|
||||||
return 0;
|
printf("hello world from hello_pie!\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -8,135 +8,135 @@
|
|||||||
|
|
||||||
static int new_bound_socket(struct sockaddr_in *addr)
|
static int new_bound_socket(struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
||||||
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
perror("new_bound_socket: socket");
|
perror("new_bound_socket: socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
||||||
perror("new_bound_socket: bind");
|
perror("new_bound_socket: bind");
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int new_connected_socket(struct sockaddr_in *addr)
|
static int new_connected_socket(struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
||||||
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
perror("new_connected_socket: socket");
|
perror("new_connected_socket: socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
||||||
perror("new_connected_socket: connect");
|
perror("new_connected_socket: connect");
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_TEST_BACKLOG 5
|
#define MAX_TEST_BACKLOG 5
|
||||||
|
|
||||||
int test_listen_backlog(struct sockaddr_in *addr, int backlog)
|
int test_listen_backlog(struct sockaddr_in *addr, int backlog)
|
||||||
{
|
{
|
||||||
int listenfd;
|
int listenfd;
|
||||||
int connectfd[MAX_TEST_BACKLOG], acceptfd[MAX_TEST_BACKLOG];
|
int connectfd[MAX_TEST_BACKLOG], acceptfd[MAX_TEST_BACKLOG];
|
||||||
int num_connectfd = 0, num_acceptfd = 0;
|
int num_connectfd = 0, num_acceptfd = 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
struct sockaddr caddr;
|
struct sockaddr caddr;
|
||||||
socklen_t caddrlen = sizeof(caddr);
|
socklen_t caddrlen = sizeof(caddr);
|
||||||
|
|
||||||
listenfd = new_bound_socket(addr);
|
listenfd = new_bound_socket(addr);
|
||||||
if (listenfd < 0) {
|
if (listenfd < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Error occurs in new_bound_socket\n");
|
"Test failed: Error occurs in new_bound_socket\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(listenfd, backlog) < 0) {
|
if (listen(listenfd, backlog) < 0) {
|
||||||
perror("listen");
|
perror("listen");
|
||||||
fprintf(stderr, "Test failed: Error occurs in listen\n");
|
fprintf(stderr, "Test failed: Error occurs in listen\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; num_connectfd < backlog; ++num_connectfd) {
|
for (; num_connectfd < backlog; ++num_connectfd) {
|
||||||
connectfd[num_connectfd] = new_connected_socket(addr);
|
connectfd[num_connectfd] = new_connected_socket(addr);
|
||||||
if (connectfd[num_connectfd] < 0)
|
if (connectfd[num_connectfd] < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_connectfd != backlog) {
|
if (num_connectfd != backlog) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: listen(backlog=%d) allows only %d pending connections\n",
|
"Test failed: listen(backlog=%d) allows only %d pending connections\n",
|
||||||
backlog, num_connectfd);
|
backlog, num_connectfd);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test passed: listen(backlog=%d) allows >=%d pending connections\n",
|
"Test passed: listen(backlog=%d) allows >=%d pending connections\n",
|
||||||
backlog, num_connectfd);
|
backlog, num_connectfd);
|
||||||
|
|
||||||
for (; num_acceptfd < num_connectfd; ++num_acceptfd) {
|
for (; num_acceptfd < num_connectfd; ++num_acceptfd) {
|
||||||
acceptfd[num_acceptfd] = accept(listenfd, &caddr, &caddrlen);
|
acceptfd[num_acceptfd] = accept(listenfd, &caddr, &caddrlen);
|
||||||
if (acceptfd[num_acceptfd] < 0) {
|
if (acceptfd[num_acceptfd] < 0) {
|
||||||
perror("accept");
|
perror("accept");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_acceptfd != num_connectfd) {
|
if (num_acceptfd != num_connectfd) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Only %d pending connections can be accept()'ed out "
|
"Test failed: Only %d pending connections can be accept()'ed out "
|
||||||
"of %d\n",
|
"of %d\n",
|
||||||
num_acceptfd, num_connectfd);
|
num_acceptfd, num_connectfd);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test passed: All of %d pending connections can be accept()'ed\n",
|
"Test passed: All of %d pending connections can be accept()'ed\n",
|
||||||
num_acceptfd);
|
num_acceptfd);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
while (--num_acceptfd >= 0)
|
while (--num_acceptfd >= 0)
|
||||||
close(acceptfd[num_acceptfd]);
|
close(acceptfd[num_acceptfd]);
|
||||||
|
|
||||||
while (--num_connectfd >= 0)
|
while (--num_connectfd >= 0)
|
||||||
close(connectfd[num_connectfd]);
|
close(connectfd[num_connectfd]);
|
||||||
|
|
||||||
close(listenfd);
|
close(listenfd);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
int backlog;
|
int backlog;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) {
|
if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) {
|
||||||
fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n");
|
fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (backlog = 0; backlog <= MAX_TEST_BACKLOG; ++backlog) {
|
for (backlog = 0; backlog <= MAX_TEST_BACKLOG; ++backlog) {
|
||||||
// Avoid "bind: Address already in use"
|
// Avoid "bind: Address already in use"
|
||||||
addr.sin_port = htons(8080 + backlog);
|
addr.sin_port = htons(8080 + backlog);
|
||||||
|
|
||||||
err = test_listen_backlog(&addr, backlog);
|
err = test_listen_backlog(&addr, backlog);
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err ? -1 : 0;
|
return err ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
@ -12,264 +12,264 @@
|
|||||||
|
|
||||||
static int new_bound_socket(struct sockaddr_in *addr)
|
static int new_bound_socket(struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
||||||
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
perror("new_bound_socket: socket");
|
perror("new_bound_socket: socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
||||||
perror("new_bound_socket: bind");
|
perror("new_bound_socket: bind");
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int new_connected_socket(struct sockaddr_in *addr)
|
static int new_connected_socket(struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
||||||
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
perror("new_connected_socket: socket");
|
perror("new_connected_socket: socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
|
||||||
perror("new_connected_socket: connect");
|
perror("new_connected_socket: connect");
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int accept_without_addr(int sockfd)
|
static int accept_without_addr(int sockfd)
|
||||||
{
|
{
|
||||||
struct sockaddr addr;
|
struct sockaddr addr;
|
||||||
socklen_t addrlen = sizeof(addr);
|
socklen_t addrlen = sizeof(addr);
|
||||||
int acceptfd;
|
int acceptfd;
|
||||||
|
|
||||||
acceptfd = accept(sockfd, &addr, &addrlen);
|
acceptfd = accept(sockfd, &addr, &addrlen);
|
||||||
if (acceptfd < 0) {
|
if (acceptfd < 0) {
|
||||||
perror("accept_without_addr: accept");
|
perror("accept_without_addr: accept");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return acceptfd;
|
return acceptfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mark_filde_nonblock(int flide)
|
static int mark_filde_nonblock(int flide)
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
flags = fcntl(flide, F_GETFL, 0);
|
flags = fcntl(flide, F_GETFL, 0);
|
||||||
if (flags < 0) {
|
if (flags < 0) {
|
||||||
perror("mark_filde_nonblock: fcntl(F_GETFL)");
|
perror("mark_filde_nonblock: fcntl(F_GETFL)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcntl(flide, F_SETFL, flags | O_NONBLOCK) < 0) {
|
if (fcntl(flide, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||||
perror("mark_filde_nonblock: fcntl(F_SETFL)");
|
perror("mark_filde_nonblock: fcntl(F_SETFL)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mark_filde_mayblock(int flide)
|
static int mark_filde_mayblock(int flide)
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
flags = fcntl(flide, F_GETFL, 0);
|
flags = fcntl(flide, F_GETFL, 0);
|
||||||
if (flags < 0) {
|
if (flags < 0) {
|
||||||
perror("mark_filde_mayblock: fcntl(F_GETFL)");
|
perror("mark_filde_mayblock: fcntl(F_GETFL)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcntl(flide, F_SETFL, flags & ~O_NONBLOCK) < 0) {
|
if (fcntl(flide, F_SETFL, flags & ~O_NONBLOCK) < 0) {
|
||||||
perror("mark_filde_mayblock: fcntl(F_SETFL)");
|
perror("mark_filde_mayblock: fcntl(F_SETFL)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char buffer[4096] = "Hello, world";
|
static char buffer[4096] = "Hello, world";
|
||||||
|
|
||||||
static ssize_t receive_all(int sockfd)
|
static ssize_t receive_all(int sockfd)
|
||||||
{
|
{
|
||||||
size_t recv_len = 0;
|
size_t recv_len = 0;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
if (mark_filde_nonblock(sockfd) < 0) {
|
if (mark_filde_nonblock(sockfd) < 0) {
|
||||||
perror("receive_all: mark_filde_nonblock");
|
perror("receive_all: mark_filde_nonblock");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ret = recv(sockfd, buffer, sizeof(buffer), 0);
|
ret = recv(sockfd, buffer, sizeof(buffer), 0);
|
||||||
if (ret < 0 && errno == EAGAIN)
|
if (ret < 0 && errno == EAGAIN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
perror("receive_all: recv");
|
perror("receive_all: recv");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
recv_len += ret;
|
recv_len += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return recv_len;
|
return recv_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_full_send_buffer(struct sockaddr_in *addr)
|
int test_full_send_buffer(struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
int listenfd, sendfd, recvfd;
|
int listenfd, sendfd, recvfd;
|
||||||
int ret = -1, wstatus;
|
int ret = -1, wstatus;
|
||||||
size_t sent_len = 0;
|
size_t sent_len = 0;
|
||||||
ssize_t sent;
|
ssize_t sent;
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
listenfd = new_bound_socket(addr);
|
listenfd = new_bound_socket(addr);
|
||||||
if (listenfd < 0) {
|
if (listenfd < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Error occurs in new_bound_socket\n");
|
"Test failed: Error occurs in new_bound_socket\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(listenfd, 2) < 0) {
|
if (listen(listenfd, 2) < 0) {
|
||||||
perror("listen");
|
perror("listen");
|
||||||
fprintf(stderr, "Test failed: Error occurs in listen\n");
|
fprintf(stderr, "Test failed: Error occurs in listen\n");
|
||||||
goto out_listen;
|
goto out_listen;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendfd = new_connected_socket(addr);
|
sendfd = new_connected_socket(addr);
|
||||||
if (sendfd < 0) {
|
if (sendfd < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Error occurs in new_connected_socket\n");
|
"Test failed: Error occurs in new_connected_socket\n");
|
||||||
goto out_listen;
|
goto out_listen;
|
||||||
}
|
}
|
||||||
|
|
||||||
recvfd = accept_without_addr(listenfd);
|
recvfd = accept_without_addr(listenfd);
|
||||||
if (recvfd < 0) {
|
if (recvfd < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Error occurs in accept_without_addr\n");
|
"Test failed: Error occurs in accept_without_addr\n");
|
||||||
goto out_send;
|
goto out_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark_filde_nonblock(sendfd) < 0) {
|
if (mark_filde_nonblock(sendfd) < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Error occurs in mark_filde_nonblock\n");
|
"Test failed: Error occurs in mark_filde_nonblock\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
sent = send(sendfd, buffer, sizeof(buffer), 0);
|
sent = send(sendfd, buffer, sizeof(buffer), 0);
|
||||||
if (sent < 0 && errno == EAGAIN)
|
if (sent < 0 && errno == EAGAIN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (sent < 0) {
|
if (sent < 0) {
|
||||||
perror("send");
|
perror("send");
|
||||||
fprintf(stderr, "Test failed: Error occurs in send\n");
|
fprintf(stderr, "Test failed: Error occurs in send\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sent_len += sent;
|
sent_len += sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark_filde_mayblock(sendfd) < 0) {
|
if (mark_filde_mayblock(sendfd) < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Error occurs in mark_filde_mayblock\n");
|
"Test failed: Error occurs in mark_filde_mayblock\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
perror("fork");
|
perror("fork");
|
||||||
fprintf(stderr, "Test failed: Error occurs in fork\n");
|
fprintf(stderr, "Test failed: Error occurs in fork\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
int i;
|
int i;
|
||||||
ssize_t recv_len;
|
ssize_t recv_len;
|
||||||
|
|
||||||
// Ensure that the parent executes send() first, then the child
|
// Ensure that the parent executes send() first, then the child
|
||||||
// executes recv().
|
// executes recv().
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
fprintf(stderr, "Start receiving...\n");
|
fprintf(stderr, "Start receiving...\n");
|
||||||
recv_len = receive_all(recvfd);
|
recv_len = receive_all(recvfd);
|
||||||
if (recv_len < 0) {
|
if (recv_len < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Error occurs in receive_all\n");
|
"Test failed: Error occurs in receive_all\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Received bytes: %lu\n", recv_len);
|
fprintf(stderr, "Received bytes: %lu\n", recv_len);
|
||||||
if (recv_len != sent_len + 1) {
|
if (recv_len != sent_len + 1) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test failed: Mismatched sent bytes and received bytes\n");
|
"Test failed: Mismatched sent bytes and received bytes\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sent = send(sendfd, buffer, 1, 0);
|
sent = send(sendfd, buffer, 1, 0);
|
||||||
if (sent < 0) {
|
if (sent < 0) {
|
||||||
perror("send");
|
perror("send");
|
||||||
fprintf(stderr, "Test failed: Error occurs in send\n");
|
fprintf(stderr, "Test failed: Error occurs in send\n");
|
||||||
goto wait;
|
goto wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
sent_len += 1;
|
sent_len += 1;
|
||||||
fprintf(stderr, "Sent bytes: %lu\n", sent_len);
|
fprintf(stderr, "Sent bytes: %lu\n", sent_len);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
wait:
|
wait:
|
||||||
if (wait(&wstatus) < 0) {
|
if (wait(&wstatus) < 0) {
|
||||||
perror("wait");
|
perror("wait");
|
||||||
fprintf(stderr, "Test failed: Error occurs in wait\n");
|
fprintf(stderr, "Test failed: Error occurs in wait\n");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
} else if (WEXITSTATUS(wstatus) != 0) {
|
} else if (WEXITSTATUS(wstatus) != 0) {
|
||||||
fprintf(stderr, "Test failed: Error occurs in child process\n");
|
fprintf(stderr, "Test failed: Error occurs in child process\n");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Test passed: Equal sent bytes and received bytes\n");
|
"Test passed: Equal sent bytes and received bytes\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
close(recvfd);
|
close(recvfd);
|
||||||
|
|
||||||
out_send:
|
out_send:
|
||||||
close(sendfd);
|
close(sendfd);
|
||||||
|
|
||||||
out_listen:
|
out_listen:
|
||||||
close(listenfd);
|
close(listenfd);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_port = htons(8080);
|
addr.sin_port = htons(8080);
|
||||||
if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) {
|
if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) {
|
||||||
fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n");
|
fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return test_full_send_buffer(&addr);
|
return test_full_send_buffer(&addr);
|
||||||
}
|
}
|
||||||
|
@ -8,33 +8,34 @@
|
|||||||
#define MESG1 "Hello from child"
|
#define MESG1 "Hello from child"
|
||||||
#define MESG2 "Hello from parent"
|
#define MESG2 "Hello from parent"
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int sockets[2], child;
|
{
|
||||||
char buf[1024];
|
int sockets[2], child;
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
|
char buf[1024];
|
||||||
perror("create socket pair");
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
|
||||||
exit(1);
|
perror("create socket pair");
|
||||||
}
|
exit(1);
|
||||||
if ((child = fork()) == -1)
|
}
|
||||||
perror("fork");
|
if ((child = fork()) == -1)
|
||||||
else if (child) {
|
perror("fork");
|
||||||
// parent
|
else if (child) {
|
||||||
close(sockets[0]);
|
// parent
|
||||||
if (read(sockets[1], buf, 1024) < 0)
|
close(sockets[0]);
|
||||||
perror("read from child");
|
if (read(sockets[1], buf, 1024) < 0)
|
||||||
printf("Receive from child: %s\n", buf);
|
perror("read from child");
|
||||||
if (write(sockets[1], MESG2, sizeof(MESG2)) < 0)
|
printf("Receive from child: %s\n", buf);
|
||||||
perror("write to child");
|
if (write(sockets[1], MESG2, sizeof(MESG2)) < 0)
|
||||||
close(sockets[1]);
|
perror("write to child");
|
||||||
} else {
|
close(sockets[1]);
|
||||||
// child
|
} else {
|
||||||
close(sockets[1]);
|
// child
|
||||||
if (write(sockets[0], MESG1, sizeof(MESG1)) < 0)
|
close(sockets[1]);
|
||||||
perror("write to parent");
|
if (write(sockets[0], MESG1, sizeof(MESG1)) < 0)
|
||||||
if (read(sockets[0], buf, 1024) < 0)
|
perror("write to parent");
|
||||||
perror("read from parent");
|
if (read(sockets[0], buf, 1024) < 0)
|
||||||
printf("Receive from parent: %s\n", buf);
|
perror("read from parent");
|
||||||
close(sockets[0]);
|
printf("Receive from parent: %s\n", buf);
|
||||||
}
|
close(sockets[0]);
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -7,63 +7,73 @@
|
|||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int sockfd;
|
{
|
||||||
int option;
|
int sockfd;
|
||||||
|
int option;
|
||||||
|
|
||||||
// Create tcp socket
|
// Create tcp socket
|
||||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
perror("Socket creation failed");
|
perror("Socket creation failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get send buffer size
|
// Get send buffer size
|
||||||
int sendbuf;
|
int sendbuf;
|
||||||
socklen_t sendbuf_len = sizeof(sendbuf);
|
socklen_t sendbuf_len = sizeof(sendbuf);
|
||||||
if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf, &sendbuf_len) < 0 || sendbuf_len != sizeof(sendbuf)) {
|
if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf, &sendbuf_len) <
|
||||||
perror("Getting SO_SNDBUF option failed");
|
0 ||
|
||||||
exit(EXIT_FAILURE);
|
sendbuf_len != sizeof(sendbuf)) {
|
||||||
}
|
perror("Getting SO_SNDBUF option failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
int error;
|
int error;
|
||||||
socklen_t error_len = sizeof(error);
|
socklen_t error_len = sizeof(error);
|
||||||
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &error_len ) < 0 || error_len != sizeof(error) || error != 0) {
|
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &error_len) < 0 ||
|
||||||
perror("Getting SO_SNDBUF option failed");
|
error_len != sizeof(error) || error != 0) {
|
||||||
exit(EXIT_FAILURE);
|
perror("Getting SO_SNDBUF option failed");
|
||||||
}
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Disable Nagle algorithm
|
// Disable Nagle algorithm
|
||||||
option = 1;
|
option = 1;
|
||||||
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)) < 0) {
|
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &option,
|
||||||
perror("Setting TCP_NODELAY option failed");
|
sizeof(option)) < 0) {
|
||||||
exit(EXIT_FAILURE);
|
perror("Setting TCP_NODELAY option failed");
|
||||||
}
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Enable reuse addr
|
// Enable reuse addr
|
||||||
option = 1;
|
option = 1;
|
||||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)) < 0) {
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option,
|
||||||
perror("Setting SO_REUSEADDR option failed");
|
sizeof(option)) < 0) {
|
||||||
exit(EXIT_FAILURE);
|
perror("Setting SO_REUSEADDR option failed");
|
||||||
}
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
// Print new value
|
|
||||||
int nagle;
|
|
||||||
socklen_t nagle_len = sizeof(nagle);
|
|
||||||
if (getsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nagle, &nagle_len) < 0 || nagle != 1) {
|
|
||||||
perror("Getting TCP_NODELAY option failed.");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int reuseaddr;
|
// Print new value
|
||||||
socklen_t reuseaddr_len = sizeof(reuseaddr);
|
int nagle;
|
||||||
if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, &reuseaddr_len) < 0 || reuseaddr != 1) {
|
socklen_t nagle_len = sizeof(nagle);
|
||||||
perror("Getting SO_REUSEADDR option failed.");
|
if (getsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nagle, &nagle_len) <
|
||||||
exit(EXIT_FAILURE);
|
0 ||
|
||||||
}
|
nagle != 1) {
|
||||||
|
perror("Getting TCP_NODELAY option failed.");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Close socket
|
int reuseaddr;
|
||||||
close(sockfd);
|
socklen_t reuseaddr_len = sizeof(reuseaddr);
|
||||||
|
if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
|
||||||
|
&reuseaddr_len) < 0 ||
|
||||||
|
reuseaddr != 1) {
|
||||||
|
perror("Getting SO_REUSEADDR option failed.");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
// Close socket
|
||||||
|
close(sockfd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -8,37 +8,39 @@
|
|||||||
|
|
||||||
#define PORT 8080
|
#define PORT 8080
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int sock = 0, valread;
|
{
|
||||||
struct sockaddr_in serv_addr;
|
int sock = 0, valread;
|
||||||
char *hello = "Hello from client";
|
struct sockaddr_in serv_addr;
|
||||||
char buffer[1024] = {0};
|
char *hello = "Hello from client";
|
||||||
|
char buffer[1024] = { 0 };
|
||||||
|
|
||||||
// Create socket
|
// Create socket
|
||||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
printf("\n Socket creation error \n");
|
printf("\n Socket creation error \n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
serv_addr.sin_family = AF_INET;
|
serv_addr.sin_family = AF_INET;
|
||||||
serv_addr.sin_port = htons(PORT);
|
serv_addr.sin_port = htons(PORT);
|
||||||
|
|
||||||
// Convert IPv4 address from text to binary form
|
// Convert IPv4 address from text to binary form
|
||||||
if (inet_pton(AF_INET, "127.0.0.1", &(serv_addr.sin_addr)) <= 0) {
|
if (inet_pton(AF_INET, "127.0.0.1", &(serv_addr.sin_addr)) <= 0) {
|
||||||
printf("\n Invalid address/ Address not supported \n");
|
printf("\n Invalid address/ Address not supported \n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to the server
|
// Connect to the server
|
||||||
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
|
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) <
|
||||||
printf("\n Connection Failed \n");
|
0) {
|
||||||
return -1;
|
printf("\n Connection Failed \n");
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Send message to the server and receive the reply
|
// Send message to the server and receive the reply
|
||||||
send(sock, hello, strlen(hello), 0);
|
send(sock, hello, strlen(hello), 0);
|
||||||
printf("Hello message sent\n");
|
printf("Hello message sent\n");
|
||||||
valread = read(sock, buffer, 1024);
|
valread = read(sock, buffer, 1024);
|
||||||
printf("Server: %s\n", buffer);
|
printf("Server: %s\n", buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -8,58 +8,61 @@
|
|||||||
|
|
||||||
#define PORT 8080
|
#define PORT 8080
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int server_fd, new_socket, valread;
|
{
|
||||||
struct sockaddr_in address;
|
int server_fd, new_socket, valread;
|
||||||
int opt = 1;
|
struct sockaddr_in address;
|
||||||
int addrlen = sizeof(address);
|
int opt = 1;
|
||||||
char buffer[1024] = {0};
|
int addrlen = sizeof(address);
|
||||||
char *hello = "Hello from server";
|
char buffer[1024] = { 0 };
|
||||||
|
char *hello = "Hello from server";
|
||||||
|
|
||||||
// Create socket
|
// Create socket
|
||||||
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||||
perror("socket failed");
|
perror("socket failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set socket options
|
// Set socket options
|
||||||
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
|
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
|
||||||
perror("setsockopt failed");
|
sizeof(opt))) {
|
||||||
exit(EXIT_FAILURE);
|
perror("setsockopt failed");
|
||||||
}
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
address.sin_port = htons(PORT);
|
|
||||||
|
|
||||||
// Convert IPv4 address from text to binary form
|
address.sin_family = AF_INET;
|
||||||
if (inet_pton(AF_INET, "127.0.0.1", &(address.sin_addr)) <= 0) {
|
address.sin_addr.s_addr = INADDR_ANY;
|
||||||
printf("\n Invalid address/ Address not supported \n");
|
address.sin_port = htons(PORT);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the socket to specified IP and port
|
// Convert IPv4 address from text to binary form
|
||||||
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
if (inet_pton(AF_INET, "127.0.0.1", &(address.sin_addr)) <= 0) {
|
||||||
perror("bind failed");
|
printf("\n Invalid address/ Address not supported \n");
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for connections
|
// Bind the socket to specified IP and port
|
||||||
if (listen(server_fd, 3) < 0) {
|
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
||||||
perror("listen failed");
|
perror("bind failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept the connection
|
// Listen for connections
|
||||||
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) {
|
if (listen(server_fd, 3) < 0) {
|
||||||
perror("accept failed");
|
perror("listen failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the message from the client and reply
|
// Accept the connection
|
||||||
valread = read(new_socket, buffer, 1024);
|
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
|
||||||
printf("Client: %s\n", buffer);
|
(socklen_t *)&addrlen)) < 0) {
|
||||||
send(new_socket, hello, strlen(hello), 0);
|
perror("accept failed");
|
||||||
printf("Hello message sent\n");
|
exit(EXIT_FAILURE);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
// Read the message from the client and reply
|
||||||
|
valread = read(new_socket, buffer, 1024);
|
||||||
|
printf("Client: %s\n", buffer);
|
||||||
|
send(new_socket, hello, strlen(hello), 0);
|
||||||
|
printf("Hello message sent\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -12,45 +12,51 @@
|
|||||||
#define SERVER_PORT 1234
|
#define SERVER_PORT 1234
|
||||||
#define BUFFER_SIZE 1024
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int sock_fd;
|
{
|
||||||
char buffer[BUFFER_SIZE];
|
int sock_fd;
|
||||||
struct sockaddr_in serv_addr;
|
char buffer[BUFFER_SIZE];
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
// Create UDP socket
|
// Create UDP socket
|
||||||
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
perror("socket creation failed");
|
perror("socket creation failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set server address
|
// Set server address
|
||||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||||
serv_addr.sin_family = AF_INET;
|
serv_addr.sin_family = AF_INET;
|
||||||
serv_addr.sin_port = htons(SERVER_PORT);
|
serv_addr.sin_port = htons(SERVER_PORT);
|
||||||
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
|
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
|
||||||
perror("invalid IP address");
|
perror("invalid IP address");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send massage to server
|
// Send massage to server
|
||||||
const char* message = "Hello world from udp client!";
|
const char *message = "Hello world from udp client!";
|
||||||
if (sendto(sock_fd, message, strlen(message), 0, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
|
if (sendto(sock_fd, message, strlen(message), 0,
|
||||||
perror("sendto failed");
|
(const struct sockaddr *)&serv_addr,
|
||||||
exit(EXIT_FAILURE);
|
sizeof(serv_addr)) < 0) {
|
||||||
}
|
perror("sendto failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Receive message from server
|
// Receive message from server
|
||||||
struct sockaddr_in sender_addr;
|
struct sockaddr_in sender_addr;
|
||||||
socklen_t sender_len = sizeof(sender_addr);
|
socklen_t sender_len = sizeof(sender_addr);
|
||||||
int recv_len;
|
int recv_len;
|
||||||
if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&sender_addr, &sender_len)) < 0) {
|
if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0,
|
||||||
perror("recvfrom failed");
|
(struct sockaddr *)&sender_addr,
|
||||||
exit(EXIT_FAILURE);
|
&sender_len)) < 0) {
|
||||||
}
|
perror("recvfrom failed");
|
||||||
buffer[recv_len] = '\0';
|
exit(EXIT_FAILURE);
|
||||||
printf("Received %s from %s:%d\n", buffer, inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
|
}
|
||||||
|
buffer[recv_len] = '\0';
|
||||||
|
printf("Received %s from %s:%d\n", buffer,
|
||||||
|
inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
|
||||||
|
|
||||||
// close socket
|
// close socket
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -12,54 +12,59 @@
|
|||||||
#define SERVER_PORT 1234
|
#define SERVER_PORT 1234
|
||||||
#define BUFFER_SIZE 1024
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int sock_fd;
|
{
|
||||||
char buffer[BUFFER_SIZE];
|
int sock_fd;
|
||||||
struct sockaddr_in serv_addr;
|
char buffer[BUFFER_SIZE];
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
// Create UDP socket
|
// Create UDP socket
|
||||||
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
perror("socket creation failed");
|
perror("socket creation failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set server address
|
// Set server address
|
||||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||||
serv_addr.sin_family = AF_INET;
|
serv_addr.sin_family = AF_INET;
|
||||||
serv_addr.sin_port = htons(SERVER_PORT);
|
serv_addr.sin_port = htons(SERVER_PORT);
|
||||||
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
|
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
|
||||||
perror("invalid IP address");
|
perror("invalid IP address");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind to server address
|
// Bind to server address
|
||||||
if (bind(sock_fd, (struct sockaddr*)&serv_addr,
|
if (bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) <
|
||||||
sizeof(serv_addr))
|
0) {
|
||||||
< 0) {
|
perror("bind failed");
|
||||||
perror("bind failed");
|
exit(EXIT_FAILURE);
|
||||||
exit(EXIT_FAILURE);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Receive message from client
|
// Receive message from client
|
||||||
struct sockaddr_in sender_addr;
|
struct sockaddr_in sender_addr;
|
||||||
socklen_t sender_len = sizeof(sender_addr);
|
socklen_t sender_len = sizeof(sender_addr);
|
||||||
int recv_len;
|
int recv_len;
|
||||||
if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&sender_addr, &sender_len)) < 0) {
|
if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0,
|
||||||
perror("recvfrom failed");
|
(struct sockaddr *)&sender_addr,
|
||||||
exit(EXIT_FAILURE);
|
&sender_len)) < 0) {
|
||||||
}
|
perror("recvfrom failed");
|
||||||
buffer[recv_len] = '\0';
|
exit(EXIT_FAILURE);
|
||||||
printf("Received %s from %s:%d\n", buffer, inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
|
}
|
||||||
|
buffer[recv_len] = '\0';
|
||||||
|
printf("Received %s from %s:%d\n", buffer,
|
||||||
|
inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
|
||||||
|
|
||||||
/// Send message to client
|
/// Send message to client
|
||||||
const char* message = "Hello world from udp server!";
|
const char *message = "Hello world from udp server!";
|
||||||
if (sendto(sock_fd, message, strlen(message), 0, (const struct sockaddr *)&sender_addr, sizeof(sender_addr)) < 0) {
|
if (sendto(sock_fd, message, strlen(message), 0,
|
||||||
perror("sendto failed");
|
(const struct sockaddr *)&sender_addr,
|
||||||
exit(EXIT_FAILURE);
|
sizeof(sender_addr)) < 0) {
|
||||||
}
|
perror("sendto failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// 关闭socket
|
// 关闭socket
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -11,55 +11,58 @@
|
|||||||
#define SOCKET_NAME "/tmp/test.sock"
|
#define SOCKET_NAME "/tmp/test.sock"
|
||||||
#define BUFFER_SIZE 128
|
#define BUFFER_SIZE 128
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int client_fd, len;
|
{
|
||||||
struct sockaddr_un server_addr, peer_addr;
|
int client_fd, len;
|
||||||
char buf[BUFFER_SIZE];
|
struct sockaddr_un server_addr, peer_addr;
|
||||||
|
char buf[BUFFER_SIZE];
|
||||||
|
|
||||||
// Create Client Socket
|
// Create Client Socket
|
||||||
client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (client_fd == -1) {
|
if (client_fd == -1) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect Server
|
// Connect Server
|
||||||
memset(&server_addr, 0, sizeof(server_addr));
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
server_addr.sun_family = AF_UNIX;
|
server_addr.sun_family = AF_UNIX;
|
||||||
strncpy(server_addr.sun_path, SOCKET_NAME, sizeof(server_addr.sun_path) - 1);
|
strncpy(server_addr.sun_path, SOCKET_NAME,
|
||||||
|
sizeof(server_addr.sun_path) - 1);
|
||||||
|
|
||||||
if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
|
if (connect(client_fd, (struct sockaddr *)&server_addr,
|
||||||
perror("connect");
|
sizeof(server_addr)) == -1) {
|
||||||
exit(EXIT_FAILURE);
|
perror("connect");
|
||||||
}
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
int addrlen = sizeof(peer_addr);
|
int addrlen = sizeof(peer_addr);
|
||||||
int rc = getpeername(client_fd, (struct sockaddr *)&peer_addr,
|
int rc =
|
||||||
&addrlen);
|
getpeername(client_fd, (struct sockaddr *)&peer_addr, &addrlen);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
perror("getpeername");
|
perror("getpeername");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
printf("server path = %s\n", peer_addr.sun_path);
|
printf("server path = %s\n", peer_addr.sun_path);
|
||||||
// Read from server
|
// Read from server
|
||||||
memset(buf, 0, BUFFER_SIZE);
|
memset(buf, 0, BUFFER_SIZE);
|
||||||
if (read(client_fd, buf, BUFFER_SIZE) == -1) {
|
if (read(client_fd, buf, BUFFER_SIZE) == -1) {
|
||||||
perror("read");
|
perror("read");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Client Received: %s\n", buf);
|
|
||||||
|
|
||||||
// Send message to server
|
printf("Client Received: %s\n", buf);
|
||||||
printf("Client is connected to server\n");
|
|
||||||
char* mesg = "Hello from unix socket client";
|
|
||||||
if (write(client_fd, mesg, strlen(mesg)) == -1) {
|
|
||||||
perror("write");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close socket
|
// Send message to server
|
||||||
close(client_fd);
|
printf("Client is connected to server\n");
|
||||||
|
char *mesg = "Hello from unix socket client";
|
||||||
|
if (write(client_fd, mesg, strlen(mesg)) == -1) {
|
||||||
|
perror("write");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
// Close socket
|
||||||
|
close(client_fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -11,68 +11,71 @@
|
|||||||
#define SOCKET_NAME "/tmp/test.sock"
|
#define SOCKET_NAME "/tmp/test.sock"
|
||||||
#define BUFFER_SIZE 128
|
#define BUFFER_SIZE 128
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int server_fd, accepted_fd, len;
|
{
|
||||||
struct sockaddr_un server_addr, client_addr;
|
int server_fd, accepted_fd, len;
|
||||||
char buf[BUFFER_SIZE];
|
struct sockaddr_un server_addr, client_addr;
|
||||||
|
char buf[BUFFER_SIZE];
|
||||||
|
|
||||||
// 创建Server Socket
|
// 创建Server Socket
|
||||||
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (server_fd == -1) {
|
if (server_fd == -1) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绑定Socket地址
|
// 绑定Socket地址
|
||||||
memset(&server_addr, 0, sizeof(server_addr));
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
server_addr.sun_family = AF_UNIX;
|
server_addr.sun_family = AF_UNIX;
|
||||||
strncpy(server_addr.sun_path, SOCKET_NAME, sizeof(server_addr.sun_path) - 1);
|
strncpy(server_addr.sun_path, SOCKET_NAME,
|
||||||
|
sizeof(server_addr.sun_path) - 1);
|
||||||
|
|
||||||
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
|
if (bind(server_fd, (struct sockaddr *)&server_addr,
|
||||||
perror("bind");
|
sizeof(server_addr)) == -1) {
|
||||||
exit(EXIT_FAILURE);
|
perror("bind");
|
||||||
}
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// 监听连接请求
|
// 监听连接请求
|
||||||
if (listen(server_fd, 5) == -1) {
|
if (listen(server_fd, 5) == -1) {
|
||||||
perror("listen");
|
perror("listen");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Server is listening...\n");
|
printf("Server is listening...\n");
|
||||||
|
|
||||||
// 接收连接请求
|
// 接收连接请求
|
||||||
len = sizeof(client_addr);
|
len = sizeof(client_addr);
|
||||||
accepted_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len);
|
accepted_fd = accept(server_fd, (struct sockaddr *)&client_addr, &len);
|
||||||
if (accepted_fd == -1) {
|
if (accepted_fd == -1) {
|
||||||
perror("accept");
|
perror("accept");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int addrlen = sizeof(client_addr);
|
int addrlen = sizeof(client_addr);
|
||||||
int rc = getpeername(accepted_fd, (struct sockaddr *)&client_addr,
|
int rc = getpeername(accepted_fd, (struct sockaddr *)&client_addr,
|
||||||
&addrlen);
|
&addrlen);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
perror("getpeername");
|
perror("getpeername");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
printf("accepted client path = %s\n", client_addr.sun_path);
|
printf("accepted client path = %s\n", client_addr.sun_path);
|
||||||
|
|
||||||
printf("Server is connected to client\n");
|
printf("Server is connected to client\n");
|
||||||
char* mesg = "Hello from unix socket server";
|
char *mesg = "Hello from unix socket server";
|
||||||
write(accepted_fd, mesg, strlen(mesg));
|
write(accepted_fd, mesg, strlen(mesg));
|
||||||
// 读取客户端发送的数据并打印
|
// 读取客户端发送的数据并打印
|
||||||
memset(buf, 0, BUFFER_SIZE);
|
memset(buf, 0, BUFFER_SIZE);
|
||||||
if (read(accepted_fd, buf, BUFFER_SIZE) == -1) {
|
if (read(accepted_fd, buf, BUFFER_SIZE) == -1) {
|
||||||
perror("read");
|
perror("read");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
printf("Server Received: %s\n", buf);
|
printf("Server Received: %s\n", buf);
|
||||||
|
|
||||||
// 关闭Socket
|
// 关闭Socket
|
||||||
close(accepted_fd);
|
close(accepted_fd);
|
||||||
close(server_fd);
|
close(server_fd);
|
||||||
unlink(SOCKET_NAME);
|
unlink(SOCKET_NAME);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -20,91 +20,96 @@
|
|||||||
// Helper functions
|
// Helper functions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#define THROW_ERROR(fmt, ...) do { \
|
#define THROW_ERROR(fmt, ...) \
|
||||||
printf("\t\tERROR:" fmt " in func %s at line %d of file %s with errno %d: %s\n", \
|
do { \
|
||||||
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, strerror(errno)); \
|
printf("\t\tERROR:" fmt \
|
||||||
return -1; \
|
" in func %s at line %d of file %s with errno %d: %s\n", \
|
||||||
} while (0)
|
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, \
|
||||||
|
strerror(errno)); \
|
||||||
|
return -1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Helper macros
|
// Helper macros
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
#define NTHREADS (3)
|
||||||
#define NTHREADS (3)
|
#define STACK_SIZE (8 * 1024)
|
||||||
#define STACK_SIZE (8 * 1024)
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// The test case of concurrent counter
|
// The test case of concurrent counter
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#define LOCAL_COUNT (1000UL)
|
#define LOCAL_COUNT (1000UL)
|
||||||
#define EXPECTED_GLOBAL_COUNT (LOCAL_COUNT * NTHREADS)
|
#define EXPECTED_GLOBAL_COUNT (LOCAL_COUNT * NTHREADS)
|
||||||
|
|
||||||
struct thread_arg {
|
struct thread_arg {
|
||||||
int ti;
|
int ti;
|
||||||
long local_count;
|
long local_count;
|
||||||
volatile unsigned long *global_count;
|
volatile unsigned long *global_count;
|
||||||
pthread_mutex_t *mutex;
|
pthread_mutex_t *mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *thread_func(void *_arg) {
|
static void *thread_func(void *_arg)
|
||||||
struct thread_arg *arg = _arg;
|
{
|
||||||
for (long i = 0; i < arg->local_count; i++) {
|
struct thread_arg *arg = _arg;
|
||||||
pthread_mutex_lock(arg->mutex);
|
for (long i = 0; i < arg->local_count; i++) {
|
||||||
(*arg->global_count)++;
|
pthread_mutex_lock(arg->mutex);
|
||||||
pthread_mutex_unlock(arg->mutex);
|
(*arg->global_count)++;
|
||||||
}
|
pthread_mutex_unlock(arg->mutex);
|
||||||
return NULL;
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_mutex_with_concurrent_counter(void) {
|
static int test_mutex_with_concurrent_counter(void)
|
||||||
/*
|
{
|
||||||
|
/*
|
||||||
* Multiple threads are to increase a global counter concurrently
|
* Multiple threads are to increase a global counter concurrently
|
||||||
*/
|
*/
|
||||||
volatile unsigned long global_count = 0;
|
volatile unsigned long global_count = 0;
|
||||||
pthread_t threads[NTHREADS];
|
pthread_t threads[NTHREADS];
|
||||||
struct thread_arg thread_args[NTHREADS];
|
struct thread_arg thread_args[NTHREADS];
|
||||||
/*
|
/*
|
||||||
* Protect the counter with a mutex
|
* Protect the counter with a mutex
|
||||||
*/
|
*/
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
pthread_mutex_init(&mutex, NULL);
|
pthread_mutex_init(&mutex, NULL);
|
||||||
/*
|
/*
|
||||||
* Start the threads
|
* Start the threads
|
||||||
*/
|
*/
|
||||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||||
struct thread_arg *thread_arg = &thread_args[ti];
|
struct thread_arg *thread_arg = &thread_args[ti];
|
||||||
thread_arg->ti = ti;
|
thread_arg->ti = ti;
|
||||||
thread_arg->local_count = LOCAL_COUNT;
|
thread_arg->local_count = LOCAL_COUNT;
|
||||||
thread_arg->global_count = &global_count;
|
thread_arg->global_count = &global_count;
|
||||||
thread_arg->mutex = &mutex;
|
thread_arg->mutex = &mutex;
|
||||||
|
|
||||||
if (pthread_create(&threads[ti], NULL, thread_func, thread_arg) < 0) {
|
if (pthread_create(&threads[ti], NULL, thread_func,
|
||||||
printf("ERROR: pthread_create failed (ti = %d)\n", ti);
|
thread_arg) < 0) {
|
||||||
return -1;
|
printf("ERROR: pthread_create failed (ti = %d)\n", ti);
|
||||||
}
|
return -1;
|
||||||
}
|
}
|
||||||
/*
|
}
|
||||||
|
/*
|
||||||
* Wait for the threads to finish
|
* Wait for the threads to finish
|
||||||
*/
|
*/
|
||||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||||
if (pthread_join(threads[ti], NULL) < 0) {
|
if (pthread_join(threads[ti], NULL) < 0) {
|
||||||
printf("ERROR: pthread_join failed (ti = %d)\n", ti);
|
printf("ERROR: pthread_join failed (ti = %d)\n", ti);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Check the correctness of the concurrent counter
|
* Check the correctness of the concurrent counter
|
||||||
*/
|
*/
|
||||||
if (global_count != EXPECTED_GLOBAL_COUNT) {
|
if (global_count != EXPECTED_GLOBAL_COUNT) {
|
||||||
printf("ERROR: incorrect global_count (actual = %ld, expected = %ld)\n",
|
printf("ERROR: incorrect global_count (actual = %ld, expected = %ld)\n",
|
||||||
global_count, EXPECTED_GLOBAL_COUNT);
|
global_count, EXPECTED_GLOBAL_COUNT);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -112,171 +117,181 @@ static int test_mutex_with_concurrent_counter(void) {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
struct thread_robust_arg {
|
struct thread_robust_arg {
|
||||||
int ti;
|
int ti;
|
||||||
volatile int *global_count;
|
volatile int *global_count;
|
||||||
pthread_mutex_t *mutex;
|
pthread_mutex_t *mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ret_err = -1;
|
int ret_err = -1;
|
||||||
|
|
||||||
static void *thread_worker(void *_arg) {
|
static void *thread_worker(void *_arg)
|
||||||
struct thread_robust_arg *arg = _arg;
|
{
|
||||||
int err = pthread_mutex_lock(arg->mutex);
|
struct thread_robust_arg *arg = _arg;
|
||||||
if (err == EOWNERDEAD) {
|
int err = pthread_mutex_lock(arg->mutex);
|
||||||
// The mutex is locked by the thread here, but the state is marked as
|
if (err == EOWNERDEAD) {
|
||||||
// inconsistent, the thread should call 'pthread_mutex_consistent' to
|
// The mutex is locked by the thread here, but the state is marked as
|
||||||
// make the mutex consistent again.
|
// inconsistent, the thread should call 'pthread_mutex_consistent' to
|
||||||
if (pthread_mutex_consistent(arg->mutex) != 0) {
|
// make the mutex consistent again.
|
||||||
printf("ERROR: failed to recover the mutex\n");
|
if (pthread_mutex_consistent(arg->mutex) != 0) {
|
||||||
return &ret_err;
|
printf("ERROR: failed to recover the mutex\n");
|
||||||
}
|
return &ret_err;
|
||||||
} else if (err != 0) {
|
}
|
||||||
printf("ERROR: failed to lock the mutex with error: %d\n", err);
|
} else if (err != 0) {
|
||||||
return &ret_err;
|
printf("ERROR: failed to lock the mutex with error: %d\n", err);
|
||||||
}
|
return &ret_err;
|
||||||
// Mutex is locked
|
}
|
||||||
(*arg->global_count)++;
|
// Mutex is locked
|
||||||
// Wait for other threads to acquire the lock
|
(*arg->global_count)++;
|
||||||
sleep(1);
|
// Wait for other threads to acquire the lock
|
||||||
// Exit without unlocking the mutex, this will makes the mutex in an
|
sleep(1);
|
||||||
// inconsistent state.
|
// Exit without unlocking the mutex, this will makes the mutex in an
|
||||||
return NULL;
|
// inconsistent state.
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_robust_mutex_with_concurrent_counter(void) {
|
static int test_robust_mutex_with_concurrent_counter(void)
|
||||||
volatile int global_count = 0;
|
{
|
||||||
pthread_t threads[NTHREADS];
|
volatile int global_count = 0;
|
||||||
struct thread_robust_arg thread_args[NTHREADS];
|
pthread_t threads[NTHREADS];
|
||||||
// Init robust mutex
|
struct thread_robust_arg thread_args[NTHREADS];
|
||||||
pthread_mutex_t mutex;
|
// Init robust mutex
|
||||||
pthread_mutexattr_t attr;
|
pthread_mutex_t mutex;
|
||||||
pthread_mutexattr_init(&attr);
|
pthread_mutexattr_t attr;
|
||||||
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
|
pthread_mutexattr_init(&attr);
|
||||||
pthread_mutex_init(&mutex, &attr);
|
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
|
||||||
// Start the threads
|
pthread_mutex_init(&mutex, &attr);
|
||||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
// Start the threads
|
||||||
struct thread_robust_arg *thread_arg = &thread_args[ti];
|
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||||
thread_arg->ti = ti;
|
struct thread_robust_arg *thread_arg = &thread_args[ti];
|
||||||
thread_arg->global_count = &global_count;
|
thread_arg->ti = ti;
|
||||||
thread_arg->mutex = &mutex;
|
thread_arg->global_count = &global_count;
|
||||||
|
thread_arg->mutex = &mutex;
|
||||||
|
|
||||||
if (pthread_create(&threads[ti], NULL, thread_worker, thread_arg) < 0) {
|
if (pthread_create(&threads[ti], NULL, thread_worker,
|
||||||
THROW_ERROR("pthread_create failed (ti = %d)", ti);
|
thread_arg) < 0) {
|
||||||
}
|
THROW_ERROR("pthread_create failed (ti = %d)", ti);
|
||||||
}
|
}
|
||||||
// Wait for the threads to finish
|
}
|
||||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
// Wait for the threads to finish
|
||||||
int *ret_val;
|
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||||
if (pthread_join(threads[ti], (void **)&ret_val) < 0) {
|
int *ret_val;
|
||||||
THROW_ERROR("pthread_join failed (ti = %d)", ti);
|
if (pthread_join(threads[ti], (void **)&ret_val) < 0) {
|
||||||
}
|
THROW_ERROR("pthread_join failed (ti = %d)", ti);
|
||||||
// printf("Thread %d joined\n", ti);
|
}
|
||||||
// fflush(stdout);
|
// printf("Thread %d joined\n", ti);
|
||||||
if (ret_val && *ret_val != 0) {
|
// fflush(stdout);
|
||||||
THROW_ERROR("run thread failed (ti = %d) with return val: %d", ti, *ret_val);
|
if (ret_val && *ret_val != 0) {
|
||||||
}
|
THROW_ERROR(
|
||||||
}
|
"run thread failed (ti = %d) with return val: %d",
|
||||||
// printf("Thread all exited.\n");
|
ti, *ret_val);
|
||||||
// fflush(stdout);
|
}
|
||||||
// Check the result
|
}
|
||||||
if (global_count != NTHREADS) {
|
// printf("Thread all exited.\n");
|
||||||
THROW_ERROR("incorrect global_count (actual = %d, expected = %d)", global_count,
|
// fflush(stdout);
|
||||||
NTHREADS);
|
// Check the result
|
||||||
}
|
if (global_count != NTHREADS) {
|
||||||
|
THROW_ERROR(
|
||||||
|
"incorrect global_count (actual = %d, expected = %d)",
|
||||||
|
global_count, NTHREADS);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// The test case of waiting condition variable
|
// The test case of waiting condition variable
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#define WAIT_ROUND (10)
|
#define WAIT_ROUND (10)
|
||||||
|
|
||||||
struct thread_cond_arg {
|
struct thread_cond_arg {
|
||||||
int ti;
|
int ti;
|
||||||
volatile unsigned int *val;
|
volatile unsigned int *val;
|
||||||
volatile int *exit_thread_count;
|
volatile int *exit_thread_count;
|
||||||
pthread_cond_t *cond_val;
|
pthread_cond_t *cond_val;
|
||||||
pthread_mutex_t *mutex;
|
pthread_mutex_t *mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *thread_cond_wait(void *_arg) {
|
static void *thread_cond_wait(void *_arg)
|
||||||
struct thread_cond_arg *arg = _arg;
|
{
|
||||||
printf("Thread #%d: start to wait on condition variable.\n", arg->ti);
|
struct thread_cond_arg *arg = _arg;
|
||||||
fflush(stdout);
|
printf("Thread #%d: start to wait on condition variable.\n", arg->ti);
|
||||||
for (unsigned int i = 0; i < WAIT_ROUND; ++i) {
|
fflush(stdout);
|
||||||
int tid = gettid();
|
for (unsigned int i = 0; i < WAIT_ROUND; ++i) {
|
||||||
printf("WAIT ROUND: %d, tid = %d\n", i, tid);
|
int tid = gettid();
|
||||||
fflush(stdout);
|
printf("WAIT ROUND: %d, tid = %d\n", i, tid);
|
||||||
pthread_mutex_lock(arg->mutex);
|
fflush(stdout);
|
||||||
printf("pthread mutex lock: tid = %d\n", tid);
|
pthread_mutex_lock(arg->mutex);
|
||||||
fflush(stdout);
|
printf("pthread mutex lock: tid = %d\n", tid);
|
||||||
while (*(arg->val) == 0) {
|
fflush(stdout);
|
||||||
pthread_cond_wait(arg->cond_val, arg->mutex);
|
while (*(arg->val) == 0) {
|
||||||
printf("pthread cond wait: tid = %d\n", tid);
|
pthread_cond_wait(arg->cond_val, arg->mutex);
|
||||||
fflush(stdout);
|
printf("pthread cond wait: tid = %d\n", tid);
|
||||||
}
|
fflush(stdout);
|
||||||
pthread_mutex_unlock(arg->mutex);
|
}
|
||||||
}
|
pthread_mutex_unlock(arg->mutex);
|
||||||
(*arg->exit_thread_count)++;
|
}
|
||||||
printf("Thread #%d: exited.\n", arg->ti);
|
(*arg->exit_thread_count)++;
|
||||||
fflush(stdout);
|
printf("Thread #%d: exited.\n", arg->ti);
|
||||||
return NULL;
|
fflush(stdout);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_mutex_with_cond_wait(void) {
|
static int test_mutex_with_cond_wait(void)
|
||||||
volatile unsigned int val = 0;
|
{
|
||||||
volatile int exit_thread_count = 0;
|
volatile unsigned int val = 0;
|
||||||
pthread_t threads[NTHREADS];
|
volatile int exit_thread_count = 0;
|
||||||
struct thread_cond_arg thread_args[NTHREADS];
|
pthread_t threads[NTHREADS];
|
||||||
pthread_cond_t cond_val = PTHREAD_COND_INITIALIZER;
|
struct thread_cond_arg thread_args[NTHREADS];
|
||||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
pthread_cond_t cond_val = PTHREAD_COND_INITIALIZER;
|
||||||
/*
|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
/*
|
||||||
* Start the threads waiting on the condition variable
|
* Start the threads waiting on the condition variable
|
||||||
*/
|
*/
|
||||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||||
struct thread_cond_arg *thread_arg = &thread_args[ti];
|
struct thread_cond_arg *thread_arg = &thread_args[ti];
|
||||||
thread_arg->ti = ti;
|
thread_arg->ti = ti;
|
||||||
thread_arg->val = &val;
|
thread_arg->val = &val;
|
||||||
thread_arg->exit_thread_count = &exit_thread_count;
|
thread_arg->exit_thread_count = &exit_thread_count;
|
||||||
thread_arg->cond_val = &cond_val;
|
thread_arg->cond_val = &cond_val;
|
||||||
thread_arg->mutex = &mutex;
|
thread_arg->mutex = &mutex;
|
||||||
|
|
||||||
if (pthread_create(&threads[ti], NULL, thread_cond_wait, thread_arg) < 0) {
|
if (pthread_create(&threads[ti], NULL, thread_cond_wait,
|
||||||
printf("ERROR: pthread_create failed (ti = %d)\n", ti);
|
thread_arg) < 0) {
|
||||||
return -1;
|
printf("ERROR: pthread_create failed (ti = %d)\n", ti);
|
||||||
}
|
return -1;
|
||||||
}
|
}
|
||||||
/*
|
}
|
||||||
|
/*
|
||||||
* Unblock all threads currently waiting on the condition variable
|
* Unblock all threads currently waiting on the condition variable
|
||||||
*/
|
*/
|
||||||
while (exit_thread_count < NTHREADS) {
|
while (exit_thread_count < NTHREADS) {
|
||||||
pthread_mutex_lock(&mutex);
|
pthread_mutex_lock(&mutex);
|
||||||
val = 1;
|
val = 1;
|
||||||
pthread_cond_broadcast(&cond_val);
|
pthread_cond_broadcast(&cond_val);
|
||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
|
|
||||||
pthread_mutex_lock(&mutex);
|
pthread_mutex_lock(&mutex);
|
||||||
val = 0;
|
val = 0;
|
||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Wait for the threads to finish
|
* Wait for the threads to finish
|
||||||
*/
|
*/
|
||||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||||
if (pthread_join(threads[ti], NULL) < 0) {
|
if (pthread_join(threads[ti], NULL) < 0) {
|
||||||
printf("ERROR: pthread_join failed (ti = %d)\n", ti);
|
printf("ERROR: pthread_join failed (ti = %d)\n", ti);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
test_mutex_with_concurrent_counter();
|
{
|
||||||
test_robust_mutex_with_concurrent_counter();
|
test_mutex_with_concurrent_counter();
|
||||||
// test_mutex_with_cond_wait();
|
test_robust_mutex_with_concurrent_counter();
|
||||||
return 0;
|
// test_mutex_with_cond_wait();
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -7,47 +7,48 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <pty.h>
|
#include <pty.h>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
int master, slave;
|
{
|
||||||
char name[256];
|
int master, slave;
|
||||||
struct termios term;
|
char name[256];
|
||||||
|
struct termios term;
|
||||||
|
|
||||||
if (openpty(&master, &slave, name, NULL, NULL) == -1) {
|
if (openpty(&master, &slave, name, NULL, NULL) == -1) {
|
||||||
perror("openpty");
|
perror("openpty");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("slave name: %s\n", name);
|
printf("slave name: %s\n", name);
|
||||||
|
|
||||||
// Set pty slave terminal attributes
|
// Set pty slave terminal attributes
|
||||||
tcgetattr(slave, &term);
|
tcgetattr(slave, &term);
|
||||||
term.c_lflag &= ~(ICANON | ECHO);
|
term.c_lflag &= ~(ICANON | ECHO);
|
||||||
term.c_cc[VMIN] = 1;
|
term.c_cc[VMIN] = 1;
|
||||||
term.c_cc[VTIME] = 0;
|
term.c_cc[VTIME] = 0;
|
||||||
tcsetattr(slave, TCSANOW, &term);
|
tcsetattr(slave, TCSANOW, &term);
|
||||||
|
|
||||||
// Print to pty slave
|
// Print to pty slave
|
||||||
dprintf(slave, "Hello world!\n");
|
dprintf(slave, "Hello world!\n");
|
||||||
|
|
||||||
// Read from pty slave
|
// Read from pty slave
|
||||||
char buf[256];
|
char buf[256];
|
||||||
ssize_t n = read(master, buf, sizeof(buf));
|
ssize_t n = read(master, buf, sizeof(buf));
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
printf("read %ld bytes from slave: %.*s", n, (int)n, buf);
|
printf("read %ld bytes from slave: %.*s", n, (int)n, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to pty master
|
// Write to pty master
|
||||||
dprintf(master, "hello world from master\n");
|
dprintf(master, "hello world from master\n");
|
||||||
|
|
||||||
// Read from pty master
|
// Read from pty master
|
||||||
char nbuf[256];
|
char nbuf[256];
|
||||||
ssize_t nn = read(slave, nbuf, sizeof(nbuf));
|
ssize_t nn = read(slave, nbuf, sizeof(nbuf));
|
||||||
if (nn > 0) {
|
if (nn > 0) {
|
||||||
printf("read %ld bytes from master: %.*s", nn, (int)nn, nbuf);
|
printf("read %ld bytes from master: %.*s", nn, (int)nn, nbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(master);
|
close(master);
|
||||||
close(slave);
|
close(slave);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,14 @@
|
|||||||
// Helper functions
|
// Helper functions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#define THROW_ERROR(fmt, ...) do { \
|
#define THROW_ERROR(fmt, ...) \
|
||||||
printf("\t\tERROR:" fmt " in func %s at line %d of file %s with errno %d: %s\n", \
|
do { \
|
||||||
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, strerror(errno)); \
|
printf("\t\tERROR:" fmt \
|
||||||
return -1; \
|
" in func %s at line %d of file %s with errno %d: %s\n", \
|
||||||
} while (0)
|
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, \
|
||||||
|
strerror(errno)); \
|
||||||
|
return -1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test sigprocmask
|
// Test sigprocmask
|
||||||
@ -37,216 +39,225 @@
|
|||||||
|
|
||||||
#define sigcmpset(a, b) memcmp((a), (b), 8)
|
#define sigcmpset(a, b) memcmp((a), (b), 8)
|
||||||
|
|
||||||
int test_sigprocmask() {
|
int test_sigprocmask()
|
||||||
int ret;
|
{
|
||||||
sigset_t new, old;
|
int ret;
|
||||||
sigset_t expected_old;
|
sigset_t new, old;
|
||||||
|
sigset_t expected_old;
|
||||||
|
|
||||||
// Check sigmask == []
|
// Check sigmask == []
|
||||||
if ((ret = sigprocmask(0, NULL, &old)) < 0) {
|
if ((ret = sigprocmask(0, NULL, &old)) < 0) {
|
||||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||||
}
|
}
|
||||||
sigemptyset(&expected_old);
|
sigemptyset(&expected_old);
|
||||||
if (sigcmpset(&old, &expected_old) != 0) {
|
if (sigcmpset(&old, &expected_old) != 0) {
|
||||||
THROW_ERROR("unexpected old sigset");
|
THROW_ERROR("unexpected old sigset");
|
||||||
}
|
}
|
||||||
|
|
||||||
// SIG_BLOCK: [] --> [SIGSEGV]
|
// SIG_BLOCK: [] --> [SIGSEGV]
|
||||||
sigemptyset(&new);
|
sigemptyset(&new);
|
||||||
sigaddset(&new, SIGSEGV);
|
sigaddset(&new, SIGSEGV);
|
||||||
if ((ret = sigprocmask(SIG_BLOCK, &new, &old)) < 0) {
|
if ((ret = sigprocmask(SIG_BLOCK, &new, &old)) < 0) {
|
||||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||||
}
|
}
|
||||||
sigemptyset(&expected_old);
|
sigemptyset(&expected_old);
|
||||||
if (sigcmpset(&old, &expected_old) != 0) {
|
if (sigcmpset(&old, &expected_old) != 0) {
|
||||||
THROW_ERROR("unexpected old sigset");
|
THROW_ERROR("unexpected old sigset");
|
||||||
}
|
}
|
||||||
|
|
||||||
// SIG_SETMASK: [SIGSEGV] --> [SIGIO]
|
// SIG_SETMASK: [SIGSEGV] --> [SIGIO]
|
||||||
sigemptyset(&new);
|
sigemptyset(&new);
|
||||||
sigaddset(&new, SIGIO);
|
sigaddset(&new, SIGIO);
|
||||||
if ((ret = sigprocmask(SIG_SETMASK, &new, &old)) < 0) {
|
if ((ret = sigprocmask(SIG_SETMASK, &new, &old)) < 0) {
|
||||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||||
}
|
}
|
||||||
sigemptyset(&expected_old);
|
sigemptyset(&expected_old);
|
||||||
sigaddset(&expected_old, SIGSEGV);
|
sigaddset(&expected_old, SIGSEGV);
|
||||||
if (sigcmpset(&old, &expected_old) != 0) {
|
if (sigcmpset(&old, &expected_old) != 0) {
|
||||||
THROW_ERROR("unexpected old sigset");
|
THROW_ERROR("unexpected old sigset");
|
||||||
}
|
}
|
||||||
|
|
||||||
// SIG_UNBLOCK: [SIGIO] -> []
|
// SIG_UNBLOCK: [SIGIO] -> []
|
||||||
if ((ret = sigprocmask(SIG_UNBLOCK, &new, &old)) < 0) {
|
if ((ret = sigprocmask(SIG_UNBLOCK, &new, &old)) < 0) {
|
||||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||||
}
|
}
|
||||||
sigemptyset(&expected_old);
|
sigemptyset(&expected_old);
|
||||||
sigaddset(&expected_old, SIGIO);
|
sigaddset(&expected_old, SIGIO);
|
||||||
if (sigcmpset(&old, &expected_old) != 0) {
|
if (sigcmpset(&old, &expected_old) != 0) {
|
||||||
THROW_ERROR("unexpected old sigset");
|
THROW_ERROR("unexpected old sigset");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sigmask == []
|
// Check sigmask == []
|
||||||
if ((ret = sigprocmask(0, NULL, &old)) < 0) {
|
if ((ret = sigprocmask(0, NULL, &old)) < 0) {
|
||||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||||
}
|
}
|
||||||
sigemptyset(&expected_old);
|
sigemptyset(&expected_old);
|
||||||
if (sigcmpset(&old, &expected_old) != 0) {
|
if (sigcmpset(&old, &expected_old) != 0) {
|
||||||
THROW_ERROR("unexpected old sigset");
|
THROW_ERROR("unexpected old sigset");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test raise syscall and user-registered signal handlers
|
// Test raise syscall and user-registered signal handlers
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#define MAX_RECURSION_LEVEL 3
|
#define MAX_RECURSION_LEVEL 3
|
||||||
|
|
||||||
static void handle_sigio(int num, siginfo_t *info, void *context) {
|
static void handle_sigio(int num, siginfo_t *info, void *context)
|
||||||
static volatile int recursion_level = 0;
|
{
|
||||||
printf("Hello from SIGIO signal handler (recursion_level = %d)!\n", recursion_level);
|
static volatile int recursion_level = 0;
|
||||||
fflush(stdout);
|
printf("Hello from SIGIO signal handler (recursion_level = %d)!\n",
|
||||||
|
recursion_level);
|
||||||
recursion_level++;
|
fflush(stdout);
|
||||||
if (recursion_level <= MAX_RECURSION_LEVEL) {
|
|
||||||
raise(SIGIO);
|
recursion_level++;
|
||||||
}
|
if (recursion_level <= MAX_RECURSION_LEVEL) {
|
||||||
recursion_level--;
|
raise(SIGIO);
|
||||||
|
}
|
||||||
|
recursion_level--;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_raise() {
|
int test_raise()
|
||||||
struct sigaction new_action, old_action;
|
{
|
||||||
memset(&new_action, 0, sizeof(struct sigaction));
|
struct sigaction new_action, old_action;
|
||||||
memset(&old_action, 0, sizeof(struct sigaction));
|
memset(&new_action, 0, sizeof(struct sigaction));
|
||||||
new_action.sa_sigaction = handle_sigio;
|
memset(&old_action, 0, sizeof(struct sigaction));
|
||||||
new_action.sa_flags = SA_SIGINFO | SA_NODEFER;
|
new_action.sa_sigaction = handle_sigio;
|
||||||
if (sigaction(SIGIO, &new_action, &old_action) < 0) {
|
new_action.sa_flags = SA_SIGINFO | SA_NODEFER;
|
||||||
THROW_ERROR("registering new signal handler failed");
|
if (sigaction(SIGIO, &new_action, &old_action) < 0) {
|
||||||
}
|
THROW_ERROR("registering new signal handler failed");
|
||||||
if (old_action.sa_handler != SIG_DFL) {
|
}
|
||||||
THROW_ERROR("unexpected old sig handler");
|
if (old_action.sa_handler != SIG_DFL) {
|
||||||
}
|
THROW_ERROR("unexpected old sig handler");
|
||||||
|
}
|
||||||
|
|
||||||
raise(SIGIO);
|
raise(SIGIO);
|
||||||
|
|
||||||
if (sigaction(SIGIO, &old_action, NULL) < 0) {
|
if (sigaction(SIGIO, &old_action, NULL) < 0) {
|
||||||
THROW_ERROR("restoring old signal handler failed");
|
THROW_ERROR("restoring old signal handler failed");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test catching and handling hardware exception
|
// Test catching and handling hardware exception
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
static void handle_sigfpe(int num, siginfo_t *info, void *_context) {
|
static void handle_sigfpe(int num, siginfo_t *info, void *_context)
|
||||||
printf("SIGFPE Caught\n");
|
{
|
||||||
fflush(stdout);
|
printf("SIGFPE Caught\n");
|
||||||
assert(num == SIGFPE);
|
fflush(stdout);
|
||||||
assert(info->si_signo == SIGFPE);
|
assert(num == SIGFPE);
|
||||||
ucontext_t *ucontext = _context;
|
assert(info->si_signo == SIGFPE);
|
||||||
mcontext_t *mcontext = &ucontext->uc_mcontext;
|
ucontext_t *ucontext = _context;
|
||||||
// The faulty instruction should be `idiv %esi` (f7 fe)
|
mcontext_t *mcontext = &ucontext->uc_mcontext;
|
||||||
mcontext->gregs[REG_RIP] += 2;
|
// The faulty instruction should be `idiv %esi` (f7 fe)
|
||||||
return;
|
mcontext->gregs[REG_RIP] += 2;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this function is fragile in the sense that compiler may not always
|
// Note: this function is fragile in the sense that compiler may not always
|
||||||
// emit the instruction pattern that triggers divide-by-zero as we expect.
|
// emit the instruction pattern that triggers divide-by-zero as we expect.
|
||||||
// TODO: rewrite this in assembly
|
// TODO: rewrite this in assembly
|
||||||
int div_maybe_zero(int x, int y) {
|
int div_maybe_zero(int x, int y)
|
||||||
return x / y;
|
{
|
||||||
|
return x / y;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr)))
|
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m"(*(addr)))
|
||||||
|
|
||||||
int test_handle_sigfpe() {
|
int test_handle_sigfpe()
|
||||||
// Set up a signal handler that handles divide-by-zero exception
|
{
|
||||||
struct sigaction new_action, old_action;
|
// Set up a signal handler that handles divide-by-zero exception
|
||||||
memset(&new_action, 0, sizeof(struct sigaction));
|
struct sigaction new_action, old_action;
|
||||||
memset(&old_action, 0, sizeof(struct sigaction));
|
memset(&new_action, 0, sizeof(struct sigaction));
|
||||||
new_action.sa_sigaction = handle_sigfpe;
|
memset(&old_action, 0, sizeof(struct sigaction));
|
||||||
new_action.sa_flags = SA_SIGINFO;
|
new_action.sa_sigaction = handle_sigfpe;
|
||||||
if (sigaction(SIGFPE, &new_action, &old_action) < 0) {
|
new_action.sa_flags = SA_SIGINFO;
|
||||||
THROW_ERROR("registering new signal handler failed");
|
if (sigaction(SIGFPE, &new_action, &old_action) < 0) {
|
||||||
}
|
THROW_ERROR("registering new signal handler failed");
|
||||||
if (old_action.sa_handler != SIG_DFL) {
|
}
|
||||||
THROW_ERROR("unexpected old sig handler");
|
if (old_action.sa_handler != SIG_DFL) {
|
||||||
}
|
THROW_ERROR("unexpected old sig handler");
|
||||||
|
}
|
||||||
|
|
||||||
char x[512] __attribute__((aligned(16))) = {};
|
char x[512] __attribute__((aligned(16))) = {};
|
||||||
char y[512] __attribute__((aligned(16))) = {};
|
char y[512] __attribute__((aligned(16))) = {};
|
||||||
|
|
||||||
// Trigger divide-by-zero exception
|
// Trigger divide-by-zero exception
|
||||||
int a = 1;
|
int a = 1;
|
||||||
int b = 0;
|
int b = 0;
|
||||||
// Use volatile to prevent compiler optimization
|
// Use volatile to prevent compiler optimization
|
||||||
volatile int c;
|
volatile int c;
|
||||||
fxsave(x);
|
fxsave(x);
|
||||||
c = div_maybe_zero(a, b);
|
c = div_maybe_zero(a, b);
|
||||||
fxsave(y);
|
fxsave(y);
|
||||||
|
|
||||||
// Asterinas does not save and restore fpregs now, so we emit this check.
|
// Asterinas does not save and restore fpregs now, so we emit this check.
|
||||||
// if (memcmp(x, y, 512) != 0) {
|
// if (memcmp(x, y, 512) != 0) {
|
||||||
// THROW_ERROR("floating point registers are modified");
|
// THROW_ERROR("floating point registers are modified");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
printf("Signal handler successfully jumped over the divide-by-zero instruction\n");
|
printf("Signal handler successfully jumped over the divide-by-zero instruction\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if (sigaction(SIGFPE, &old_action, NULL) < 0) {
|
if (sigaction(SIGFPE, &old_action, NULL) < 0) {
|
||||||
THROW_ERROR("restoring old signal handler failed");
|
THROW_ERROR("restoring old signal handler failed");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rewrite this in assembly
|
// TODO: rewrite this in assembly
|
||||||
int read_maybe_null(int *p) {
|
int read_maybe_null(int *p)
|
||||||
return *p;
|
{
|
||||||
|
return *p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_sigsegv(int num, siginfo_t *info, void *_context) {
|
static void handle_sigsegv(int num, siginfo_t *info, void *_context)
|
||||||
printf("SIGSEGV Caught\n");
|
{
|
||||||
fflush(stdout);
|
printf("SIGSEGV Caught\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
assert(num == SIGSEGV);
|
assert(num == SIGSEGV);
|
||||||
assert(info->si_signo == SIGSEGV);
|
assert(info->si_signo == SIGSEGV);
|
||||||
|
|
||||||
ucontext_t *ucontext = _context;
|
ucontext_t *ucontext = _context;
|
||||||
mcontext_t *mcontext = &ucontext->uc_mcontext;
|
mcontext_t *mcontext = &ucontext->uc_mcontext;
|
||||||
// TODO: how long is the instruction?
|
// TODO: how long is the instruction?
|
||||||
// The faulty instruction should be `idiv %esi` (f7 fe)
|
// The faulty instruction should be `idiv %esi` (f7 fe)
|
||||||
mcontext->gregs[REG_RIP] += 2;
|
mcontext->gregs[REG_RIP] += 2;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_handle_sigsegv()
|
||||||
|
{
|
||||||
|
// Set up a signal handler that handles divide-by-zero exception
|
||||||
|
struct sigaction new_action, old_action;
|
||||||
|
memset(&new_action, 0, sizeof(struct sigaction));
|
||||||
|
memset(&old_action, 0, sizeof(struct sigaction));
|
||||||
|
new_action.sa_sigaction = handle_sigsegv;
|
||||||
|
new_action.sa_flags = SA_SIGINFO;
|
||||||
|
if (sigaction(SIGSEGV, &new_action, &old_action) < 0) {
|
||||||
|
THROW_ERROR("registering new signal handler failed");
|
||||||
|
}
|
||||||
|
if (old_action.sa_handler != SIG_DFL) {
|
||||||
|
THROW_ERROR("unexpected old sig handler");
|
||||||
|
}
|
||||||
|
|
||||||
int test_handle_sigsegv() {
|
int *addr = NULL;
|
||||||
// Set up a signal handler that handles divide-by-zero exception
|
volatile int val = read_maybe_null(addr);
|
||||||
struct sigaction new_action, old_action;
|
(void)val; // to suppress "unused variables" warning
|
||||||
memset(&new_action, 0, sizeof(struct sigaction));
|
|
||||||
memset(&old_action, 0, sizeof(struct sigaction));
|
|
||||||
new_action.sa_sigaction = handle_sigsegv;
|
|
||||||
new_action.sa_flags = SA_SIGINFO;
|
|
||||||
if (sigaction(SIGSEGV, &new_action, &old_action) < 0) {
|
|
||||||
THROW_ERROR("registering new signal handler failed");
|
|
||||||
}
|
|
||||||
if (old_action.sa_handler != SIG_DFL) {
|
|
||||||
THROW_ERROR("unexpected old sig handler");
|
|
||||||
}
|
|
||||||
|
|
||||||
int *addr = NULL;
|
printf("Signal handler successfully jumped over a null-dereferencing instruction\n");
|
||||||
volatile int val = read_maybe_null(addr);
|
fflush(stdout);
|
||||||
(void)val; // to suppress "unused variables" warning
|
|
||||||
|
|
||||||
printf("Signal handler successfully jumped over a null-dereferencing instruction\n");
|
if (sigaction(SIGSEGV, &old_action, NULL) < 0) {
|
||||||
fflush(stdout);
|
THROW_ERROR("restoring old signal handler failed");
|
||||||
|
}
|
||||||
if (sigaction(SIGSEGV, &old_action, NULL) < 0) {
|
return 0;
|
||||||
THROW_ERROR("restoring old signal handler failed");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -254,105 +265,111 @@ int test_handle_sigsegv() {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
int sigchld = 0;
|
int sigchld = 0;
|
||||||
|
|
||||||
void proc_exit() {
|
void proc_exit()
|
||||||
sigchld = 1;
|
{
|
||||||
|
sigchld = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_sigchld() {
|
int test_sigchld()
|
||||||
signal(SIGCHLD, proc_exit);
|
{
|
||||||
printf("Run a parent process has pid = %d\n", getpid());
|
signal(SIGCHLD, proc_exit);
|
||||||
fflush(stdout);
|
printf("Run a parent process has pid = %d\n", getpid());
|
||||||
int pid = fork();
|
fflush(stdout);
|
||||||
if(pid == 0) {
|
int pid = fork();
|
||||||
// child process
|
if (pid == 0) {
|
||||||
printf("create a new proces successfully (pid = %d)\n", getpid());
|
// child process
|
||||||
fflush(stdout);
|
printf("create a new proces successfully (pid = %d)\n",
|
||||||
exit(0);
|
getpid());
|
||||||
} else {
|
fflush(stdout);
|
||||||
// parent process
|
exit(0);
|
||||||
wait(NULL);
|
} else {
|
||||||
printf("sigchld = %d\n", sigchld);
|
// parent process
|
||||||
fflush(stdout);
|
wait(NULL);
|
||||||
}
|
printf("sigchld = %d\n", sigchld);
|
||||||
return 0;
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test handle signal on alternate signal stack
|
// Test handle signal on alternate signal stack
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#define MAX_ALTSTACK_RECURSION_LEVEL 2
|
#define MAX_ALTSTACK_RECURSION_LEVEL 2
|
||||||
|
|
||||||
stack_t g_old_ss;
|
stack_t g_old_ss;
|
||||||
|
|
||||||
static void handle_sigpipe(int num, siginfo_t *info, void *context) {
|
static void handle_sigpipe(int num, siginfo_t *info, void *context)
|
||||||
static volatile int recursion_level = 0;
|
{
|
||||||
printf("Hello from SIGPIPE signal handler on the alternate signal stack (recursion_level = %d)\n",
|
static volatile int recursion_level = 0;
|
||||||
recursion_level);
|
printf("Hello from SIGPIPE signal handler on the alternate signal stack (recursion_level = %d)\n",
|
||||||
|
recursion_level);
|
||||||
|
|
||||||
// save old_ss to check if we are on stack
|
// save old_ss to check if we are on stack
|
||||||
stack_t old_ss;
|
stack_t old_ss;
|
||||||
sigaltstack(NULL, &old_ss);
|
sigaltstack(NULL, &old_ss);
|
||||||
g_old_ss = old_ss;
|
g_old_ss = old_ss;
|
||||||
|
|
||||||
recursion_level++;
|
recursion_level++;
|
||||||
if (recursion_level <= MAX_ALTSTACK_RECURSION_LEVEL) {
|
if (recursion_level <= MAX_ALTSTACK_RECURSION_LEVEL) {
|
||||||
raise(SIGPIPE);
|
raise(SIGPIPE);
|
||||||
}
|
}
|
||||||
recursion_level--;
|
recursion_level--;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SIGSTACKSIZE (4*4096)
|
#define SIGSTACKSIZE (4 * 4096)
|
||||||
|
|
||||||
int test_sigaltstack() {
|
int test_sigaltstack()
|
||||||
static char stack[SIGSTACKSIZE];
|
{
|
||||||
stack_t expected_ss = {
|
static char stack[SIGSTACKSIZE];
|
||||||
.ss_size = SIGSTACKSIZE,
|
stack_t expected_ss = {
|
||||||
.ss_sp = stack,
|
.ss_size = SIGSTACKSIZE,
|
||||||
.ss_flags = 0,
|
.ss_sp = stack,
|
||||||
};
|
.ss_flags = 0,
|
||||||
if (sigaltstack(&expected_ss, NULL) < 0) {
|
};
|
||||||
THROW_ERROR("failed to call sigaltstack");
|
if (sigaltstack(&expected_ss, NULL) < 0) {
|
||||||
}
|
THROW_ERROR("failed to call sigaltstack");
|
||||||
stack_t actual_ss;
|
}
|
||||||
if (sigaltstack(NULL, &actual_ss) < 0) {
|
stack_t actual_ss;
|
||||||
THROW_ERROR("failed to call sigaltstack");
|
if (sigaltstack(NULL, &actual_ss) < 0) {
|
||||||
}
|
THROW_ERROR("failed to call sigaltstack");
|
||||||
if (actual_ss.ss_size != expected_ss.ss_size
|
}
|
||||||
|| actual_ss.ss_sp != expected_ss.ss_sp
|
if (actual_ss.ss_size != expected_ss.ss_size ||
|
||||||
|| actual_ss.ss_flags != expected_ss.ss_flags) {
|
actual_ss.ss_sp != expected_ss.ss_sp ||
|
||||||
THROW_ERROR("failed to check the signal stack after set");
|
actual_ss.ss_flags != expected_ss.ss_flags) {
|
||||||
}
|
THROW_ERROR("failed to check the signal stack after set");
|
||||||
|
}
|
||||||
|
|
||||||
struct sigaction new_action, old_action;
|
struct sigaction new_action, old_action;
|
||||||
memset(&new_action, 0, sizeof(struct sigaction));
|
memset(&new_action, 0, sizeof(struct sigaction));
|
||||||
memset(&old_action, 0, sizeof(struct sigaction));
|
memset(&old_action, 0, sizeof(struct sigaction));
|
||||||
new_action.sa_sigaction = handle_sigpipe;
|
new_action.sa_sigaction = handle_sigpipe;
|
||||||
new_action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
|
new_action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
|
||||||
if (sigaction(SIGPIPE, &new_action, &old_action) < 0) {
|
if (sigaction(SIGPIPE, &new_action, &old_action) < 0) {
|
||||||
THROW_ERROR("registering new signal handler failed");
|
THROW_ERROR("registering new signal handler failed");
|
||||||
}
|
}
|
||||||
if (old_action.sa_handler != SIG_DFL) {
|
if (old_action.sa_handler != SIG_DFL) {
|
||||||
THROW_ERROR("unexpected old sig handler");
|
THROW_ERROR("unexpected old sig handler");
|
||||||
}
|
}
|
||||||
|
|
||||||
raise(SIGPIPE);
|
raise(SIGPIPE);
|
||||||
if (g_old_ss.ss_flags != SS_ONSTACK) {
|
if (g_old_ss.ss_flags != SS_ONSTACK) {
|
||||||
THROW_ERROR("check stack flags failed");
|
THROW_ERROR("check stack flags failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigaction(SIGPIPE, &old_action, NULL) < 0) {
|
if (sigaction(SIGPIPE, &old_action, NULL) < 0) {
|
||||||
THROW_ERROR("restoring old signal handler failed");
|
THROW_ERROR("restoring old signal handler failed");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
test_sigprocmask();
|
{
|
||||||
test_raise();
|
test_sigprocmask();
|
||||||
test_handle_sigfpe();
|
test_raise();
|
||||||
test_handle_sigsegv();
|
test_handle_sigfpe();
|
||||||
test_sigchld();
|
test_handle_sigsegv();
|
||||||
test_sigaltstack();
|
test_sigchld();
|
||||||
return 0;
|
test_sigaltstack();
|
||||||
|
return 0;
|
||||||
}
|
}
|
Reference in New Issue
Block a user