Coverage Report

Created: 2025-08-29 06:30

/src/unit/src/nxt_conn_connect.c
Line
Count
Source (jump to first uncovered line)
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
#include <nxt_main.h>
8
9
10
static nxt_err_t nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c);
11
12
13
void
14
nxt_conn_sys_socket(nxt_task_t *task, void *obj, void *data)
15
0
{
16
0
    nxt_conn_t          *c;
17
0
    nxt_work_handler_t  handler;
18
19
0
    c = obj;
20
21
0
    if (nxt_conn_socket(task, c) == NXT_OK) {
22
0
        c->socket.write_work_queue = c->write_work_queue;
23
0
        handler = c->io->connect;
24
25
0
    } else {
26
0
        handler = c->write_state->error_handler;
27
0
    }
28
29
0
    nxt_work_queue_add(&task->thread->engine->connect_work_queue,
30
0
                       handler, task, c, data);
31
0
}
32
33
34
void
35
nxt_conn_io_connect(nxt_task_t *task, void *obj, void *data)
36
0
{
37
0
    nxt_conn_t              *c;
38
0
    nxt_work_handler_t      handler;
39
0
    nxt_event_engine_t      *engine;
40
0
    const nxt_conn_state_t  *state;
41
42
0
    c = obj;
43
44
0
    state = c->write_state;
45
46
0
    switch (nxt_socket_connect(task, c->socket.fd, c->remote)) {
47
48
0
    case NXT_OK:
49
0
        c->socket.write_ready = 1;
50
0
        handler = state->ready_handler;
51
0
        break;
52
53
0
    case NXT_AGAIN:
54
0
        c->socket.write_handler = nxt_conn_connect_test;
55
0
        c->socket.error_handler = nxt_conn_connect_error;
56
57
0
        engine = task->thread->engine;
58
59
0
        nxt_conn_timer(engine, c, state, &c->write_timer);
60
61
0
        nxt_fd_event_enable_write(engine, &c->socket);
62
0
        return;
63
64
0
    case NXT_DECLINED:
65
0
        handler = state->close_handler;
66
0
        break;
67
68
0
    default: /* NXT_ERROR */
69
0
        handler = state->error_handler;
70
0
        break;
71
0
    }
72
73
0
    nxt_work_queue_add(c->write_work_queue, handler, task, c, data);
74
0
}
75
76
77
nxt_int_t
78
nxt_conn_socket(nxt_task_t *task, nxt_conn_t *c)
79
0
{
80
0
    nxt_uint_t    family;
81
0
    nxt_socket_t  s;
82
83
0
    nxt_debug(task, "event conn socket");
84
85
0
    family = c->remote->u.sockaddr.sa_family;
86
87
0
    s = nxt_socket_create(task, family, c->remote->type, 0, NXT_NONBLOCK);
88
89
0
    if (nxt_slow_path(s == -1)) {
90
0
        return NXT_ERROR;
91
0
    }
92
93
0
    c->sendfile = 1;
94
95
#if (NXT_HAVE_UNIX_DOMAIN && NXT_SOLARIS)
96
97
    if (family == AF_UNIX) {
98
        /* Solaris AF_UNIX does not support sendfilev(). */
99
        c->sendfile = 0;
100
    }
101
102
#endif
103
104
0
    c->socket.fd = s;
105
106
0
    c->socket.task = task;
107
0
    c->read_timer.task = task;
108
0
    c->write_timer.task = task;
109
110
0
    if (c->local != NULL) {
111
0
        if (nxt_slow_path(nxt_socket_bind(task, s, c->local) != NXT_OK)) {
112
0
            nxt_socket_close(task, s);
113
0
            return NXT_ERROR;
114
0
        }
115
0
    }
116
117
0
    return NXT_OK;
118
0
}
119
120
121
void
122
nxt_conn_connect_test(nxt_task_t *task, void *obj, void *data)
123
0
{
124
0
    nxt_err_t   err;
125
0
    nxt_conn_t  *c;
126
127
0
    c = obj;
128
129
0
    nxt_debug(task, "event connect test fd:%d", c->socket.fd);
130
131
0
    nxt_fd_event_block_write(task->thread->engine, &c->socket);
132
133
0
    if (c->write_state->timer_autoreset) {
134
0
        nxt_timer_disable(task->thread->engine, &c->write_timer);
135
0
    }
136
137
0
    err = nxt_conn_connect_test_error(task, c);
138
139
0
    if (err == 0) {
140
0
        nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler,
141
0
                           task, c, data);
142
0
    } else {
143
0
        nxt_conn_connect_error(task, c, data);
144
0
    }
145
0
}
146
147
148
void
149
nxt_conn_connect_error(nxt_task_t *task, void *obj, void *data)
150
0
{
151
0
    nxt_err_t               err;
152
0
    nxt_conn_t              *c;
153
0
    nxt_work_handler_t      handler;
154
0
    const nxt_conn_state_t  *state;
155
156
0
    c = obj;
157
0
    err = c->socket.error;
158
159
0
    if (err == 0) {
160
0
        err = nxt_conn_connect_test_error(task, c);
161
0
    }
162
163
0
    state = c->write_state;
164
165
0
    switch (err) {
166
167
0
    case NXT_ECONNREFUSED:
168
0
#if (NXT_LINUX)
169
0
    case NXT_EAGAIN:
170
        /*
171
         * Linux returns EAGAIN instead of ECONNREFUSED
172
         * for UNIX sockets if a listen queue is full.
173
         */
174
0
#endif
175
0
        handler = state->close_handler;
176
0
        break;
177
178
0
    default:
179
0
        handler = state->error_handler;
180
0
        break;
181
0
    }
182
183
0
    nxt_work_queue_add(c->write_work_queue, handler, task, c, data);
184
0
}
185
186
187
static nxt_err_t
188
nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c)
189
0
{
190
0
    nxt_err_t  err;
191
192
0
    err = nxt_socket_error(c->socket.fd);
193
194
0
    if (err != 0) {
195
0
        c->socket.error = err;
196
197
0
        nxt_log(task, nxt_socket_error_level(err), "connect(%d, %*s) failed %E",
198
0
                c->socket.fd, (size_t) c->remote->length,
199
0
                nxt_sockaddr_start(c->remote), err);
200
0
    }
201
202
0
    return err;
203
0
}