Skip to content

Commit 5e4e70f

Browse files
Merge branch 'master' into can_deprecated_member
2 parents e686511 + 0e26ec0 commit 5e4e70f

File tree

7 files changed

+223
-21
lines changed

7 files changed

+223
-21
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ add_subdirectory(TCP)
77
add_subdirectory(UDP)
88
add_subdirectory(Unix)
99
add_subdirectory(CAN)
10-
add_subdirectory(Netlink)
10+
add_subdirectory(Netlink)
11+
add_subdirectory(Virtio)

Netlink/CMakeLists.txt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
project(Netlink_Sockets)
22

3+
# Find the path to make binary and strip the newline character
4+
# NOTE We cannot use CMAKE_MAKE_PROGRAM instead because it is set based on cmake generator used which could also be Ninja
5+
execute_process(COMMAND which make
6+
OUTPUT_VARIABLE MAKE_PROGRAM
7+
)
8+
string(STRIP ${MAKE_PROGRAM} MAKE_PROGRAM)
9+
310
set(NETLINK_KERN_MODULE kernel_client)
411
set(NETLINK_MOD_FILE ${NETLINK_KERN_MODULE}.ko)
512
set(NETLINK_MOD_SRC_FILES ${NETLINK_KERN_MODULE}.c)
@@ -13,9 +20,9 @@ foreach(source_file ${SRC_FILES})
1320
endforeach(source_file ${SRC_FILES})
1421

1522
add_custom_command(OUTPUT ${NETLINK_MOD_FILE}
16-
COMMAND ${CMAKE_MAKE_PROGRAM} all
23+
COMMAND ${MAKE_PROGRAM} all
1724
COMMAND ${CMAKE_COMMAND} -E copy ${NETLINK_MOD_FILE} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
18-
COMMAND ${CMAKE_MAKE_PROGRAM} clean
25+
COMMAND ${MAKE_PROGRAM} clean
1926
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
2027
DEPENDS ${NETLINK_MOD_SRC_FILES}
2128
COMMENT "Building netlink kernel module"
@@ -24,4 +31,6 @@ add_custom_command(OUTPUT ${NETLINK_MOD_FILE}
2431

2532
add_custom_target(${NETLINK_KERN_MODULE} ALL DEPENDS ${NETLINK_MOD_FILE})
2633
# Clean netlink module output from the output directory on running a clean cmake target
27-
set_target_properties(${NETLINK_KERN_MODULE} PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${NETLINK_MOD_FILE})
34+
set_target_properties(${NETLINK_KERN_MODULE}
35+
PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${NETLINK_MOD_FILE}
36+
)

README.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
# SocketProgramming
2-
Sockets are a fascinating concept as communication endpoints between 2 processes running on the same host using the same filesystem or on totally different hosts and filesystem miles apart but of course connected by a network
3-
When I was new to socket programming it was very confusing for me to understand the concept with the code on the internet which was either too complex, lacked annotations or didn't cover enough
4-
This prodded me to create this repo with some socket programming examples in C with annotations to demonstrate how sockets work
2+
Sockets are a fascinating concept as communication endpoints between 2 or more entities running on the same host using the same filesystem or on totally different hosts and filesystem miles apart but of course connected by a network
3+
When I was new to socket programming, it was very difficult for me to understand various types of sockets and how they work with the resources on the internet which were scattered, lacked annotations or didn't cover enough.
4+
This prodded me to create a unified repo containing some examples in C with copious annotations for different types of sockets. I also created some real world applications like a network file server/sender to demonstrate their possible applications
55

6-
There are primarily 2 socket domains (Internet and Unix)
7-
In this project, I have laid down examples with elaborate comments for 3 most commonly used types of sockets:
6+
In this project, I have created examples and sample apps for following type of sockets:
87
- **TCP** (Stream socket used for secure reliable connection between 2 processes running on the same or different hosts on the same network)
98
- **UDP** (Datagram socket used for fast data exchange between 2 processes running on the same or different hosts on the same network)
109
- **Unix** (Stream/Datagram socket residing on the same filesystem as the 2 processes using it to communicate)
10+
- **CAN** (Raw sockets used to transmit and receive CAN messages using a can interface created by a CAN bus controller)
11+
- **Netlink** (Raw sockets used mostly for kernel-userspace communication and also for interprocess communication)
12+
- **Virtio** (Virtio sockets used for communication between host and virtual machine using the virtio-vsock driver and vhost-vsock backend)
13+
14+
**Note:** If you're working with SocketCAN and do not have a real CAN bus to work with, you can create a virtual CAN bus interface using can-utils package. A script `vcan-setup.sh` has been created for the same under *Misc* directory of this repo https://github.com/amoldhamale1105/CodingPlayground
1115

1216
## Build Instructions
13-
This project is setup with a hierarchical cmake structure. The top level cmake adds downstream directories which in turn have their own cmake to build the sources enclosed
14-
By default it will generate binaries for all sources within this repo under the `bin` directory
17+
This project is setup with a hierarchical cmake structure. The top level cmake adds downstream directories which in turn have their own cmake to build the sources enclosed. By default it will generate binaries for all sources within this repo under the `bin` directory
18+
1519
If you working with one particular type of socket, for instance `TCP`, comment out the `add_subdirectory()` calls which are not required. The top-level cmake in our example would look something like this:
1620
```
1721
add_subdirectory(TCP)
1822
#add_subdirectory(UDP)
1923
#add_subdirectory(Unix)
2024
```
21-
This will save build time and unncessary build instructions when you're not intending to execute the output binaries
22-
Once the target directories are set in cmake, run `Clean Reconfigure All` or `Clean Rebuild All` in case you've loaded the project using VSCode
23-
Enter the following commands at the project root if you work with the command line
25+
This will save you some time if you're dedicatedly working on a specific type of socket
26+
27+
Once the target directories are set in cmake, run the build script with or without options depending on your build configuration. Defaults for each option will appear between `{}` in the usage instruction. Print the script usage by running the following command
28+
```
29+
./build.sh -h
30+
```
31+
As an example, if you want to use the script to build for release mode with `Unix Makefiles` cmake generator, it can be executed as follows
2432
```
25-
mkdir build
26-
cd build
27-
cmake ..
28-
make
33+
./build.sh -a -r -g "Unix Makefiles"
2934
```
3035
On a successful build, required binaries will be generated under the `bin` directory at the root of the project
3136

3237
## Contribution
33-
This is a repository catering to new programmers and experienced developers alike who like to tinker with sockets. I'd love people to contribute by adding to this project any fun experiments they conducted using raw socket programming
34-
Also, any other version of code or in a different language (for instance, python) which explains socket programming in a much better manner would be great.
35-
Contribution in any way is appreciable. Send me an email ([email protected]) if you happen to face issues creating branches, issues or raising pull requests
38+
This is a repository catering to new programmers and experienced developers alike who like to tinker with sockets. I'd love to see you contribute by adding to this project any fun experiments you conducted using raw socket programming. Be sure to share this with people who are new to socket programming and wish to have working examples with explanation for all types of sockets in one place.
39+
Contribution in any way is welcome. Get in touch with me in case of any questions or suggestions [email protected]

Virtio/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
project(Virtio_Sockets)
2+
3+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${PROJECT_NAME})
4+
file(GLOB SRC_FILES *.c *.cpp)
5+
6+
foreach(source_file ${SRC_FILES})
7+
get_filename_component(BINARY_NAME ${source_file} NAME_WE)
8+
add_executable(${BINARY_NAME} ${source_file})
9+
endforeach(source_file ${SRC_FILES})

Virtio/vsock_client.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <sys/socket.h>
2+
#include <stdio.h>
3+
#include <linux/vm_sockets.h>
4+
#include <string.h>
5+
#include <stdlib.h>
6+
#include <unistd.h>
7+
8+
void error(const char *);
9+
10+
int main(int argc, char **argv)
11+
{
12+
struct sockaddr_vm addr;
13+
char buf[256];
14+
15+
/* Check if required number of args are provided to the program */
16+
if (argc < 2){
17+
fprintf(stderr, "usage: %s <port> [cid]\n", argv[0]);
18+
exit(1);
19+
}
20+
/* Create a virtio socket */
21+
int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
22+
if (sockfd < 0)
23+
error("ERROR: Failed to open socket");
24+
25+
memset(&addr, 0, sizeof(struct sockaddr_vm));
26+
addr.svm_family = AF_VSOCK;
27+
addr.svm_port = atoi(argv[1]);
28+
addr.svm_cid = argc > 2 ? atoi(argv[2]) : VMADDR_CID_HOST; /* Connect to VM with specified context ID or host */
29+
30+
if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_vm)) < 0)
31+
error("ERROR: Failed to connect to the virtio server");
32+
33+
const char *msg = "Hey there! I'm using virtio";
34+
int numBytes = send(sockfd, msg, strlen(msg), 0);
35+
if (numBytes < 0)
36+
error("ERROR: Failed to write to socket");
37+
38+
/* Clear the buffer and prepare it to receive a response from the server */
39+
bzero(buf, 256);
40+
numBytes = recv(sockfd, buf, 255, 0);
41+
if (numBytes < 0)
42+
error("ERROR: Failed to read from socket");
43+
printf("%s\n", buf);
44+
45+
/* Clean up */
46+
close(sockfd);
47+
48+
return 0;
49+
}
50+
51+
void error(const char *msg)
52+
{
53+
perror(msg);
54+
exit(1);
55+
}

Virtio/vsock_server.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <sys/socket.h>
2+
#include <linux/vm_sockets.h>
3+
#include <string.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <unistd.h>
7+
8+
void error(const char *);
9+
10+
int main(int argc, char **argv)
11+
{
12+
struct sockaddr_vm addr, peer_addr;
13+
char buf[256];
14+
15+
/* Check if required number of args are provided to the program */
16+
if (argc < 2){
17+
fprintf(stderr, "usage: %s <port>\n", argv[0]);
18+
exit(1);
19+
}
20+
/* Create a virtio socket */
21+
int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
22+
if (sockfd < 0)
23+
error("ERROR: Failed to open socket");
24+
25+
memset(&addr, 0, sizeof(struct sockaddr_vm));
26+
addr.svm_family = AF_VSOCK;
27+
addr.svm_port = atoi(argv[1]);
28+
addr.svm_cid = VMADDR_CID_ANY; /* Bind to any CID to facilitate client connection from host or nested VM */
29+
30+
if (bind(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_vm)) < 0)
31+
error("ERROR: Failed to bind with socket");
32+
33+
listen(sockfd, 5);
34+
35+
socklen_t peer_addr_size = sizeof(struct sockaddr_vm);
36+
int peer_fd = accept(sockfd, (struct sockaddr *)&peer_addr, &peer_addr_size);
37+
if (peer_fd < 0)
38+
error("ERROR: Failed to establish connection with client");
39+
40+
/* Send and receive to a connected virtio client */
41+
bzero(buf, 256);
42+
int numBytes = recv(peer_fd, buf, 255, 0);
43+
if (numBytes < 0)
44+
error("ERROR: Failed to receive from client");
45+
46+
printf("Message from the client: %s\n", buf);
47+
48+
const char *response = "Server response: I got your message";
49+
numBytes = send(peer_fd, response, strlen(response), 0);
50+
if (numBytes < 0)
51+
error("ERROR: Failed to send to client");
52+
53+
/* Clean up */
54+
close(peer_fd);
55+
close(sockfd);
56+
57+
return 0;
58+
}
59+
60+
void error(const char *msg)
61+
{
62+
perror(msg);
63+
exit(1);
64+
}

build.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/bash
2+
3+
usage() { echo "usage: $0 [-a|c {a} (all|clean)] [-r|d {d} (release|debug)] [-g <cmake-generator> {Ninja}]" 2>&1; exit 0; }
4+
5+
BUILD_TYPE="Debug"
6+
GENERATOR="Ninja"
7+
TARGET="all"
8+
ACTION="Build"
9+
10+
while getopts ":acrdg:h" arg; do
11+
case "${arg}" in
12+
a)
13+
TARGET="all"
14+
ACTION="Build"
15+
;;
16+
c)
17+
TARGET="clean"
18+
ACTION="Clean"
19+
;;
20+
r)
21+
BUILD_TYPE="Release"
22+
;;
23+
d)
24+
BUILD_TYPE="Debug"
25+
;;
26+
g)
27+
GENERATOR=${OPTARG}
28+
;;
29+
h|*)
30+
usage
31+
;;
32+
esac
33+
done
34+
shift $((OPTIND-1))
35+
36+
if [ -z "${GENERATOR}" ]; then
37+
usage
38+
fi
39+
40+
if [ ${TARGET} = "all" ]; then
41+
if [ -d ${PWD}/build ]; then
42+
rm -rf build/{.[!.]*,*}
43+
fi
44+
echo "Configuring project in ${BUILD_TYPE} mode..."
45+
cmake -DCMAKE_BUILD_TYPE:STRING=${BUILD_TYPE} -S . -B ${PWD}/build -G "${GENERATOR}"
46+
fi
47+
48+
echo "${ACTION}ing project..."
49+
if [ ! -z "$(ls -A ${PWD}/build)" ]; then
50+
cmake --build ${PWD}/build --config ${BUILD_TYPE} --target ${TARGET}
51+
fi
52+
53+
if [ ${TARGET} = "clean" ]; then
54+
if [ -d ${PWD}/build ]; then
55+
rm -rf build/{.[!.]*,*}
56+
fi
57+
if [ -d ${PWD}/bin ]; then
58+
rm -rf bin/*
59+
fi
60+
fi

0 commit comments

Comments
 (0)