commit 092dd205568705ac43b6270913e82eb7acc1d95e Author: Hizenberg Date: Thu Apr 25 11:46:12 2024 +0530 Unix Domain Socket diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3914244 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*vsidx +*.opendb +.vs +out diff --git a/AF_UNIX/CMakeLists.txt b/AF_UNIX/CMakeLists.txt new file mode 100644 index 0000000..7c8bf55 --- /dev/null +++ b/AF_UNIX/CMakeLists.txt @@ -0,0 +1,24 @@ +# CMakeList.txt : CMake project for AF_UNIX, include source and define +# project specific logic here. +# +cmake_minimum_required (VERSION 3.8) + +# Enable Hot Reload for MSVC compilers if supported. +if (POLICY CMP0141) + cmake_policy(SET CMP0141 NEW) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") +endif() + +project ( AF_UNIX VERSION 1.0.0 LANGUAGES C CXX) + +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + +# Add source to this project's executable. +add_executable (server "server.c") +add_executable (client "client.c") + + + +# TODO: Add tests and install targets if needed. diff --git a/AF_UNIX/CMakePresets.json b/AF_UNIX/CMakePresets.json new file mode 100644 index 0000000..f4bc98b --- /dev/null +++ b/AF_UNIX/CMakePresets.json @@ -0,0 +1,101 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "windows-base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_C_COMPILER": "cl.exe", + "CMAKE_CXX_COMPILER": "cl.exe" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "x64-debug", + "displayName": "x64 Debug", + "inherits": "windows-base", + "architecture": { + "value": "x64", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "x64-release", + "displayName": "x64 Release", + "inherits": "x64-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "x86-debug", + "displayName": "x86 Debug", + "inherits": "windows-base", + "architecture": { + "value": "x86", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "x86-release", + "displayName": "x86 Release", + "inherits": "x86-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "linux-debug", + "displayName": "Linux Debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + }, + "vendor": { + "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { + "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" + } + } + }, + { + "name": "macos-debug", + "displayName": "macOS Debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + }, + "vendor": { + "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { + "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" + } + } + } + ] +} diff --git a/AF_UNIX/client.c b/AF_UNIX/client.c new file mode 100644 index 0000000..aedd8da --- /dev/null +++ b/AF_UNIX/client.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include + +#define SOCKET_NAME "/tmp/DemoSocket" +#define BUFFER_SIZE 128 + +int +main(int argc, char* argv[]) { + + struct sockaddr_un addr; + int i; + int ret; + int data_socket; + char buffer[BUFFER_SIZE]; + + /* Create data socket */ + /* Client side don't have any concept of Master socket. + It directly use data socket to communicate with server. */ + + data_socket = socket(AF_UNIX, SOCK_STREAM, 0); + + if (data_socket == -1) { + perror("socket"); + exit(EXIT_FAILURE); + } + + /* + For portability clear the whole structure, since some implementation + have additional (nonstandard) fields in the structure. + */ + + memset(&addr, 0, sizeof(struct sockaddr_un)); + + /* Connect socket to socket address. */ + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); + + ret = connect(data_socket, (const struct sockaddr*)&addr, + sizeof(struct sockaddr_un)); + + if (ret == -1) { + fprintf(stderr, "The server is down.\n"); + exit(EXIT_FAILURE); + } + + /* Send arguments */ + do { + + printf("Enter number to send to server :\n"); + scanf("%d", &i); + ret = write(data_socket, &i, sizeof(int)); + if (ret == -1) { + perror("write"); + exit(EXIT_FAILURE); + } + + printf("No of bytes sent = %d, data sent = %d\n", ret, i); + } while (i); + + /* Request result */ + + memset(buffer, 0, BUFFER_SIZE); + strncpy(buffer, "RES", strlen("RES")); + buffer[strlen(buffer)] = '\0'; + + ret = read(data_socket, buffer, BUFFER_SIZE); + if (ret == -1) { + perror("read"); + exit(EXIT_FAILURE); + } + + /* Ensure buffer is 0 - terminated */ + + buffer[BUFFER_SIZE - 1] = 0; + printf("%s\n", buffer); + + /* Close socket */ + + close(data_socket); + exit(EXIT_SUCCESS); + return 0; +} \ No newline at end of file diff --git a/AF_UNIX/server.c b/AF_UNIX/server.c new file mode 100644 index 0000000..496e647 --- /dev/null +++ b/AF_UNIX/server.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include +#include +#include + + +#define SOCKET_NAME "/tmp/DemoSocket" /* Unique name of the socket */ +#define BUFFER_SIZE 128 /* Size of the buffer which will be used by + for Communication. */ + +int +main(int argc, char* argv[]) { + + /* Structure provided by Unix library for using + it as an identifier for managing the socket */ + + struct sockaddr_un name; + +#if 0 + + struct sockaddr_un { + + /* This member describe what type of data it + will handle. Define the family of the + socket. Here, we are using UNIX DOMAIN socket + so AF_UNIX constant should be used for + classification. */ + sa_family_t sun_family; /* AF_UNIX */ + + /* Hold the name of the socket with the path where it + is created. */ + char sun_path[108]; /* pathname */ + }; +#endif + + int ret; + int connection_socket; + int data_socket; + int result; + int data; + char buffer[BUFFER_SIZE]; + + /* In case the program exited inadvertently on the last run, + remove the socket. */ + + + unlink(SOCKET_NAME); + + /* Create Master socket */ + + /* SOCK_DGRAM for Datagram based communication */ + connection_socket = socket(AF_UNIX, SOCK_STREAM, 0); + + if (connection_socket == -1) { + + perror("socket"); + exit(EXIT_FAILURE); + + } + + printf("Master socket created\n"); + + /* initialize */ + memset(&name, 0, sizeof(struct sockaddr_un)); + + /* Specify the socket Cridentials */ + name.sun_family = AF_UNIX; + strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1); + + /* Bind Socket to socket name. */ + /* Purpose of bind() system call is that application() dictate the underlying + operating system the criteria of receiving the data. Here, bind() system call + is telling the OS that if sender process sends the data destined to socket + "tmp/DemoSocket", then such data needs to be delievered to this server process + ( the server process ) */ + + ret = bind(connection_socket, (const struct sockaddr* )&name, + sizeof(struct sockaddr_un)); + + if (ret == -1) { + perror("bind"); + exit(EXIT_FAILURE); + } + + + printf("bind() call succeed\n"); + + /* Prepare for accepting connections. The backlog size is set to 20. + So, while one request is being processed other requests can be + waiting. + */ + + ret = listen(connection_socket, 20); + + if (ret == -1) { + perror("listen"); + exit(EXIT_FAILURE); + } + + /* This is the main loop for handling connections. */ + /* All Server process usually runs 24 x 7. Good Servers should always up + running and should never go down. */ + + for (;;) { + + /* Wait for incoming connection. */ + + printf("Waiting on accept() sys call\n"); + + data_socket = accept(connection_socket, NULL, NULL); + + if (data_socket == -1) { + perror("accept"); + exit(EXIT_FAILURE); + } + + printf("Connection accepted from client\n"); + + result = 0; + for (;;) { + + /* Prepare the buffer to recv the data*/ + memset(buffer, 0, BUFFER_SIZE); + + /*Wait for next data packet. */ + /* Server is blocked here. Waiting for the data to arrive from client + 'read' is a blocking system call. */ + printf("Waiting for data from the client\n"); + + ret = read(data_socket, buffer, BUFFER_SIZE); + + if (ret == -1) { + perror("read"); + exit(EXIT_FAILURE); + } + + /* Add received summand */ + + memcpy(&data, buffer, sizeof(int)); + if (data == 0) break; + result += data; + + } + + /* Send result. */ + memset(buffer, 0, BUFFER_SIZE); + sprintf(buffer, "Result = %d", result); + + + printf("Sending final result back to client\n"); + + /* non-blockding system call */ + ret = write(data_socket, buffer, BUFFER_SIZE); + if (ret == -1) { + perror("write"); + exit(EXIT_FAILURE); + } + + /*close socket*/ + close(data_socket); + + + } + + /*close the master socket*/ + close(connection_socket); + printf("connection closed..\n"); + + /* Server should release resources before getting terminated. + Unlink the socket. */ + + unlink(SOCKET_NAME); + exit(EXIT_SUCCESS); + return 0; +} +