From 2c88f979ac1146a3af46503e6a25ae55af5c847e Mon Sep 17 00:00:00 2001 From: Jelle van Kraaij Date: Mon, 3 Jul 2023 22:11:49 +0200 Subject: [PATCH] WIP add crude Socket class --- .clang-format | 226 ++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- include/Socket.hpp | 28 +++++ include/hello-world.hpp | 5 - src/Socket.cpp | 97 +++++++++++++++++ src/hello-world.cpp | 6 -- src/main.cpp | 29 +++++- test/test.cpp | 7 +- 8 files changed, 378 insertions(+), 22 deletions(-) create mode 100644 .clang-format create mode 100644 include/Socket.hpp delete mode 100644 include/hello-world.hpp create mode 100644 src/Socket.cpp delete mode 100644 src/hello-world.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..2049ee5 --- /dev/null +++ b/.clang-format @@ -0,0 +1,226 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 150 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: NextLine +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/CMakeLists.txt b/CMakeLists.txt index 18b8509..245d810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set (SRCS_MAIN ) set (SRCS - src/hello-world.cpp + src/Socket.cpp ) set (EXEC_NAME webserv) diff --git a/include/Socket.hpp b/include/Socket.hpp new file mode 100644 index 0000000..a1ce38c --- /dev/null +++ b/include/Socket.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +class Socket { + public: + Socket(int port, int backlog = 5); + Socket(const Socket &other); + ~Socket(); + + int accept(); + void close(); + + bool pending() const; + + Socket &operator=(const Socket &other); + + private: + int _socket_fd = -1; + + void _socket(); + void _bind(int port); + void _listen(int backlog); + + // Protected c function as a static private method + static int _dup(int fd); + static void _close(int fd); +}; diff --git a/include/hello-world.hpp b/include/hello-world.hpp deleted file mode 100644 index 5a688ed..0000000 --- a/include/hello-world.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -std::string hello_world(); diff --git a/src/Socket.cpp b/src/Socket.cpp new file mode 100644 index 0000000..62d4727 --- /dev/null +++ b/src/Socket.cpp @@ -0,0 +1,97 @@ +#include "Socket.hpp" + +#include +#include +#include +#include + +#include + +Socket::Socket(int port, int backlog) { + _socket(); + _bind(port); + _listen(backlog); +} + +Socket::Socket(const Socket &other) { + *this = other; +} + +Socket::~Socket() { + close(); +} + +Socket &Socket::operator=(const Socket &other) { + if (this == &other) + return *this; + close(); + _socket_fd = _dup(other._socket_fd); + return *this; +} + +int Socket::accept() { + int client_fd = ::accept(_socket_fd, NULL, NULL); + if (client_fd < 0) { + throw std::runtime_error("Failed to accept connection"); + } + return client_fd; +} + +bool Socket::pending() const { + static const int fd_count = 1; + struct pollfd fds[fd_count]; + + fds[0].fd = _socket_fd; + fds[0].events = POLLIN; + + return poll(fds, fd_count, 0) > 0; +} + +void Socket::_socket() { + _socket_fd = socket(AF_INET, SOCK_STREAM, 0); + + if (_socket_fd < 0) { + throw std::runtime_error("Failed to create socket"); + } +} + +void Socket::_bind(int port) { + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(_socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + throw std::runtime_error("Failed to bind socket"); + } +} + +void Socket::_listen(int backlog) { + if (listen(_socket_fd, backlog) < 0) { + throw std::runtime_error("Failed to listen on socket"); + } +} + +void Socket::close() { + if (_socket_fd < 0) { + return; + } + _close(_socket_fd); + _socket_fd = -1; +} + +// Protected c function as a static private method + +int Socket::_dup(int fd) { + int new_fd = dup(fd); + if (new_fd < 0) { + throw std::runtime_error("Failed to duplicate file descriptor"); + } + return new_fd; +} + +void Socket::_close(int fd) { + if (::close(fd) < 0) { + throw std::runtime_error("Failed to close file descriptor"); + } +} diff --git a/src/hello-world.cpp b/src/hello-world.cpp deleted file mode 100644 index e3a55b8..0000000 --- a/src/hello-world.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "hello-world.hpp" - -std::string hello_world() -{ - return "Hello, World!"; -} diff --git a/src/main.cpp b/src/main.cpp index e0b5c81..25e0738 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,28 @@ +#include + #include -#include "hello-world.hpp" +#include "Socket.hpp" + +int main() { + Socket socket(80); + + while (1) { + if (!socket.pending()) + continue; + std::cout << "Pending socket" << std::endl; + int client_fd = socket.accept(); + std::cout << "Accepted connection" << std::endl; + + if (close(client_fd) < 0) { + std::cerr << "Failed to close client socket" << std::endl; + return 1; + } + std::cout << "Closed connection" << std::endl; + } -int main() -{ - std::cout << hello_world() << std::endl; - return 0; + // optional + socket.close(); + std::cout << "Closed socket" << std::endl; + return 0; } diff --git a/test/test.cpp b/test/test.cpp index ef95686..bc344b2 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,8 +1,5 @@ #include -#include "hello-world.hpp" - -TEST(hello_world, basic) -{ - EXPECT_EQ(hello_world(), "Hello, World!"); +TEST(test, basic) { + EXPECT_EQ(1, 1); }