Coverage Report

Created: 2026-07-16 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzmq/src/ipc_connecter.cpp
Line
Count
Source
1
/* SPDX-License-Identifier: MPL-2.0 */
2
3
#include "precompiled.hpp"
4
#include "ipc_connecter.hpp"
5
6
#if defined ZMQ_HAVE_IPC
7
8
#include <new>
9
#include <string>
10
11
#include "io_thread.hpp"
12
#include "random.hpp"
13
#include "err.hpp"
14
#include "ip.hpp"
15
#include "address.hpp"
16
#include "ipc_address.hpp"
17
#include "session_base.hpp"
18
19
#if defined ZMQ_HAVE_WINDOWS
20
#include <afunix.h>
21
#else
22
#include <unistd.h>
23
#include <sys/types.h>
24
#include <sys/socket.h>
25
#include <sys/un.h>
26
#endif
27
28
zmq::ipc_connecter_t::ipc_connecter_t (class io_thread_t *io_thread_,
29
                                       class session_base_t *session_,
30
                                       const options_t &options_,
31
                                       address_t *addr_,
32
                                       bool delayed_start_) :
33
0
    stream_connecter_base_t (
34
0
      io_thread_, session_, options_, addr_, delayed_start_)
35
0
{
36
0
    zmq_assert (_addr->protocol == protocol_name::ipc);
37
0
}
38
39
void zmq::ipc_connecter_t::out_event ()
40
0
{
41
0
    const fd_t fd = connect ();
42
0
    rm_handle ();
43
44
    //  Handle the error condition by attempt to reconnect.
45
0
    if (fd == retired_fd) {
46
0
        close ();
47
0
        add_reconnect_timer ();
48
0
        return;
49
0
    }
50
51
0
    create_engine (fd, get_socket_name<ipc_address_t> (fd, socket_end_local));
52
0
}
53
54
void zmq::ipc_connecter_t::start_connecting ()
55
0
{
56
    //  Open the connecting socket.
57
0
    const int rc = open ();
58
59
    //  Connect may succeed in synchronous manner.
60
0
    if (rc == 0) {
61
0
        _handle = add_fd (_s);
62
0
        out_event ();
63
0
    }
64
65
    //  Connection establishment may be delayed. Poll for its completion.
66
0
    else if (rc == -1 && errno == EINPROGRESS) {
67
0
        _handle = add_fd (_s);
68
0
        set_pollout (_handle);
69
0
        _socket->event_connect_delayed (
70
0
          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());
71
72
        // TODO, tcp_connecter_t adds a connect timer in this case; maybe this
73
        // should be done here as well (and then this could be pulled up to
74
        // stream_connecter_base_t).
75
0
    }
76
    //stop connecting after called zmq_disconnect
77
0
    else if (rc == -1
78
0
             && (options.reconnect_stop & ZMQ_RECONNECT_STOP_AFTER_DISCONNECT)
79
0
             && errno == ECONNREFUSED && _socket->is_disconnected ()) {
80
0
        if (_s != retired_fd)
81
0
            close ();
82
0
    }
83
84
    //  Handle any other error condition by eventual reconnect.
85
0
    else {
86
0
        if (_s != retired_fd)
87
0
            close ();
88
0
        add_reconnect_timer ();
89
0
    }
90
0
}
91
92
int zmq::ipc_connecter_t::open ()
93
0
{
94
0
    zmq_assert (_s == retired_fd);
95
96
    //  Create the socket.
97
0
    _s = open_socket (AF_UNIX, SOCK_STREAM, 0);
98
0
    if (_s == retired_fd)
99
0
        return -1;
100
101
    //  Set the non-blocking flag.
102
0
    unblock_socket (_s);
103
104
    //  Connect to the remote peer.
105
0
    const int rc = ::connect (_s, _addr->resolved.ipc_addr->addr (),
106
0
                              _addr->resolved.ipc_addr->addrlen ());
107
108
    //  Connect was successful immediately.
109
0
    if (rc == 0)
110
0
        return 0;
111
112
        //  Translate other error codes indicating asynchronous connect has been
113
        //  launched to a uniform EINPROGRESS.
114
#ifdef ZMQ_HAVE_WINDOWS
115
    const int last_error = WSAGetLastError ();
116
    if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)
117
        errno = EINPROGRESS;
118
    else
119
        errno = wsa_error_to_errno (last_error);
120
#else
121
0
    if (rc == -1 && errno == EINTR) {
122
0
        errno = EINPROGRESS;
123
0
    }
124
0
#endif
125
126
    //  Forward the error.
127
0
    return -1;
128
0
}
129
130
zmq::fd_t zmq::ipc_connecter_t::connect ()
131
0
{
132
    //  Following code should handle both Berkeley-derived socket
133
    //  implementations and Solaris.
134
0
    int err = 0;
135
0
    zmq_socklen_t len = static_cast<zmq_socklen_t> (sizeof (err));
136
0
    const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,
137
0
                               reinterpret_cast<char *> (&err), &len);
138
0
    if (rc == -1) {
139
0
        if (errno == ENOPROTOOPT)
140
0
            errno = 0;
141
0
        err = errno;
142
0
    }
143
0
    if (err != 0) {
144
        //  Assert if the error was caused by 0MQ bug.
145
        //  Networking problems are OK. No need to assert.
146
0
        errno = err;
147
0
        errno_assert (errno == ECONNREFUSED || errno == ECONNRESET
148
0
                      || errno == ETIMEDOUT || errno == EHOSTUNREACH
149
0
                      || errno == ENETUNREACH || errno == ENETDOWN);
150
151
0
        return retired_fd;
152
0
    }
153
154
0
    const fd_t result = _s;
155
0
    _s = retired_fd;
156
0
    return result;
157
0
}
158
159
#endif