Binglong's space

Random notes on computer, phone, life, anything

Posts Tagged ‘Mermaid’

Build Project with CMake

Posted by binglongx on July 10, 2024

While some projects use traditional configure and make approach, a lot of projects now use CMake to help building.

CMake is a meta build system. CMake itself does not build your project.

  • Projects using CMake would store project settings in CMakeLists.txt files.
  • You can run cmake to create actual project files suitable for concrete build tools to build. Examples are:
    • cmake generates Makefile, to be consumed by make to build the project;
    • cmake generates Xcode project files, to be consumed by Xcode to build the project on macOS;
    • cmake generates Visual Studio project files, to be consumed by Visual Studio/C++ to build the project on Windows;

As you can see, CMake enables you to create projects with build portability.

The diagram above is generated from Mermaid:

%% Mermaid drawing, view with https://mermaid.live/
flowchart LR

    classDef Executable fill:#411,stroke-width:2px;
    classDef File fill:#141,stroke-width:2px;

    src[source code]:::File
    cmake_list[CMakeLists.txt]:::File 

    cmake([cmake]):::Executable
    cmakex([cmake -G Xcode]):::Executable

    makefile[Makefile]
    xproj[Xcode project]
    
    make([make]):::Executable
    make_c([cmake --build]):::Executable
    xcode([Xcode]):::Executable

    exe[executable]
    exe_x[executable]

    cmake_list --> cmake --> makefile
    cmake_list --> cmakex --> xproj

    makefile --> make --> exe
    makefile --> make_c --> exe
    xproj --> xcode --> exe_x

    src --> make
    src --> make_c
    src --> xcode

    subgraph source code repo
        cmake_list
        src
    end

    subgraph cmake stage
        cmake
        cmakex
        makefile
        xproj
    end

    subgraph build stage
        make
        make_c
        xcode
        exe
        exe_x
    end

Posted in C++ | Tagged: , , , , , , , | 1 Comment »

Unix project: configure and make

Posted by binglongx on May 25, 2024

For a project distributed as source code in Unix-like systems, upon getting the source, normally you would run:

./configure
make

The magic behind configure, make, make install – How it works in Unix explains what’s happening. Below is a simple drawing of the flow. Note that “project startup” was done when the project was first created by the project owner.

The corresponding Mermaid flow char diagram source code:

%% Mermaid drawing, view with https://mermaid.live/
flowchart LR

    classDef Executable fill:#411,stroke-width:2px;
    classDef File fill:#141,stroke-width:2px;

    subgraph project startup
    a[Makefile.am]:::File
    b([automake]):::Executable
    d[configure.ac]:::File
    e([autoconfig]):::Executable
    end

    subgraph source code repo
    c[Makefile.in]:::File 
    f([configure]):::Executable
    j[source code]:::File
    end

    g[Makefile]:::File
    h([make]):::Executable
    i[executable]:::Executable

    a[Makefile.am] --> b([automake]) --> c[Makefile.in]
    d[configure.ac] --> e([autoconfig]) --> f([configure])
    c[Makefile.in] --> f([configure]) --> g[Makefile]
     j[source code] --> h([make])
    g[Makefile] --> h([make]) --> i[executable]

See also: Build Project with CMake

Posted in C++ | Tagged: , , , , , , , , | Leave a Comment »

Socket API At A Glance

Posted by binglongx on February 22, 2024

Introduction

  • socket address: For TCP/IP, the socket address is IP address and port number.
  • a socket is the file descriptor;
  • local_addr is the socket address on local computer.
  • remote_addr is the socket address on remote computer.

Socket States

In this diagram there are a few different states a socket can be in. Socket conceptually contains different information and allows different oprations in each state.

  • detached: a socket file discriptor is created through socket(), but there is no socket address associated. This socket conceptually cannot do anything.
    • If you call sendto(remote_addr), socket implementation automatically binds it to a good local socket address (IP and a random port), and moves to bound state, before sending data.
    • connect(remote_addr) moves directly to connected state.
  • bound: the socket is associated with a local socket address (e.g. IP and port). For connection-less socket, you can now receive data from remote party because they can address to you. You can send data as long as you know the remote party’s socket address from a bound socket. Note that when bind() a socket, you can specify “any” IP (INADDR_ANY for IPv4, and in6addr_any for IPv6); when a message from client arrives, it can come though any network interface if your host has multiple interfaces (with different IPs). In bound state, you can choose to bind to a port together with a specific IP, or a floating “any” IP.
  • listening: This is like a special bound state for a connection-oriented socket on server.
  • connected: A connected socket has the full information about both local and remote addresses.

Connection-less Socket (like UDP)

  • The server uses socket() -> bind() , then it can call recvfrom() to get (potentially blocking) for incoming messages;
  • The client uses socket() then it can use sendto(remote_addr) / sendmsg(remote_addr) to send a message to remote server. The socket implementation automatically binds the socket to a local socket address. You can also manually bind() it before using sendto(remote_addr) / sendmsg(remote_addr), but you have to choose IP / port carefully yourself.
  • The receiver end can choose to obtain sender’s socket address when recvfrom() / recvmsg() is called. This address can be used to reply the message, if reply is needed.
  • A connection-less socket can stay in bound state for ever, and it can be used to talk with different remote parties.
  • It is however possible to move the connection-less socket to connected state, by calling connect(remote_addr). After that, you can send message with write()/send() without specifying remote_addr explicitly. You can call connect() again to let the socket point to a different remote socket address, or connect(null) to clear that association to return to bound state.
  • Keep in mind, UDP does not guarantee reliable transfer, therefore a receiver may not receive all the datagrams the sender sent.

Connection-Oriented Socket (like TCP)

  • The server uses socket() -> bind() -> listen() -> accept() sequence.
  • The client uses socket() -> connect(remote_addr).
    • The client may use socket() -> bind(local_addr) -> connect(remote_addr), but binding is automatically done if it uses socket() -> connect(remote_addr).
  • The server’s listening socket is not for data communication. It serves as a mother socket, and the only purpose is to take in a new incoming connection from client. If that incoming connection request is accepted, a new server side socket is spawned in connected state for data communication. The listening server socket never moves into connected state.
    • The new server socket uses the same port number as the listening socket, but since this is a connected socket, it has both local/server IP+port and client IP+port, so incoming data to the port from different clients can be properly distributed to their corresponding server sockets.
    • The client side socket is also moved into connected state, associated with the socket address of the server side, appearing like to the same one it tries to connect() to, althoug on server side it’s served by a different socket.
  • Once the connection is established, both client and server now have a socket in connected state, and they can use read()/write()/send()/recv() to exchange data.

The State Machine Diagram

The state machine diagram is generated by Mermaid tool, see https://mermaid.js.org/syntax/stateDiagram.html. There is the Online Mermaid Editor you can try at https://mermaid.live/, paste the following in there:

%% Mermaid diagram https://mermaid.js.org/syntax/stateDiagram.html
stateDiagram-v2
    detached: detached\n-----------\n(socket)
    bound: bound\n--------------\n(socket)\n(local_addr)
    listening: listening\n--------------\n(socket)\n(local_addr)
    connected: connected\n-----------------\n(socket)\n(local_addr)\n(remote_addr)
    all: all states
 
    classDef VirtualState font-style:italic;
 
    [*] -->  detached : socket()
    detached --> bound : bind(local_addr)
    detached --> bound : sendto(remote_addr)
    bound --> bound : sendto()/recvfrom()/sendmsg()/recvmsg()
    detached --> connected : connect(remote_addr)
    bound --> listening: listen()
    listening --> connected: accept() spawns new
    bound --> connected : connect(remote_addr)
    connected --> connected: read()/write()/readv()/writev()/send()/recv()/\nsendto()/recvfrom()/sendmsg()/recvmsg()/\nconnect()
    connected --> bound: connect(null)
    all:::VirtualState --> [*] : close()
 
    note left of [*]
        Socket API At A Glance, 
        Connection-oriented: SOCK_STREAM (TCP) etc.
        Connection-less: SOCK_DGRAM (UDP) etc.
         
        https://en.wikipedia.org/wiki/Berkeley_sockets
    end note
 
    note left of bound
        Connection-less sockets often stay here,
        using sendto()/recvfrom()/sendmsg()/recvmsg()
        getsockname() returns local socket address.
    end note
 
    note right of listening
        Connection-oriented socket as "mother socket" at server.
        client connecting to it results in a different connected socket.
    end note
 
    note right of connected
        Most Connection-oriented sockets stay here, using read()/write()/readv()/writev()/send()/recv().
         
        Connection-less sockets rarely here. If they are, they
        - can still use sendto()/recvfrom()/sendmsg()/recvmsg();
        - allows connect() to change remote_addr, or connect(null) to go to bound state.

        getpeername() returns remote socket address.
    end note


Some C++ wrapper code for socket is in C++ Wrapper for Socket API.

Posted in Computer and Internet | Tagged: , , , , , , , , , | 1 Comment »