xref: /unit/src/nxt_socket.c (revision 0:a63ceefd6ab0)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 
9 
10 static const char *nxt_socket_sockopt_name(nxt_uint_t level,
11     nxt_uint_t sockopt);
12 
13 
14 nxt_socket_t
15 nxt_socket_create(nxt_uint_t domain, nxt_uint_t type, nxt_uint_t protocol,
16     nxt_uint_t flags)
17 {
18     nxt_socket_t  s;
19 
20 #if (NXT_HAVE_SOCK_NONBLOCK)
21 
22     if (flags & NXT_NONBLOCK) {
23         type |= SOCK_NONBLOCK;
24     }
25 
26 #endif
27 
28     s = socket(domain, type, protocol);
29 
30     if (nxt_slow_path(s == -1)) {
31         nxt_thread_log_alert("socket(%ui, 0x%uXi, %ui) failed %E",
32                              domain, type, protocol, nxt_socket_errno);
33         return s;
34     }
35 
36     nxt_thread_log_debug("socket(): %d", s);
37 
38 #if !(NXT_HAVE_SOCK_NONBLOCK)
39 
40     if (flags & NXT_NONBLOCK) {
41         if (nxt_slow_path(nxt_socket_nonblocking(s) != NXT_OK)) {
42             nxt_socket_close(s);
43             return -1;
44         }
45     }
46 
47 #endif
48 
49     return s;
50 }
51 
52 
53 void
54 nxt_socket_close(nxt_socket_t s)
55 {
56     if (nxt_fast_path(close(s) == 0)) {
57         nxt_thread_log_debug("socket close(%d)", s);
58 
59     } else {
60         nxt_thread_log_alert("socket close(%d) failed %E", s, nxt_socket_errno);
61     }
62 }
63 
64 
65 nxt_int_t
66 nxt_socket_getsockopt(nxt_socket_t s, nxt_uint_t level, nxt_uint_t sockopt)
67 {
68     int        val;
69     socklen_t  len;
70 
71     len = sizeof(val);
72 
73     if (nxt_fast_path(getsockopt(s, level, sockopt, &val, &len) == 0)) {
74         nxt_thread_log_debug("getsockopt(%d, %ui, %s): %d",
75                              s, level,
76                              nxt_socket_sockopt_name(level, sockopt), val);
77         return val;
78     }
79 
80     nxt_thread_log_error(NXT_LOG_CRIT, "getsockopt(%d, %ui, %s) failed %E",
81                          s, level, nxt_socket_sockopt_name(level, sockopt),
82                          val, nxt_socket_errno);
83 
84     return -1;
85 }
86 
87 
88 nxt_int_t
89 nxt_socket_setsockopt(nxt_socket_t s, nxt_uint_t level, nxt_uint_t sockopt,
90     int val)
91 {
92     socklen_t  len;
93 
94     len = sizeof(val);
95 
96     if (nxt_fast_path(setsockopt(s, level, sockopt, &val, len) == 0)) {
97         nxt_thread_log_debug("setsockopt(%d, %ui, %s): %d",
98                              s, level,
99                              nxt_socket_sockopt_name(level, sockopt), val);
100         return NXT_OK;
101     }
102 
103     nxt_thread_log_error(NXT_LOG_CRIT, "setsockopt(%d, %ui, %s, %d) failed %E",
104                          s, level, nxt_socket_sockopt_name(level, sockopt),
105                          val, nxt_socket_errno);
106 
107     return NXT_ERROR;
108 }
109 
110 
111 static const char *
112 nxt_socket_sockopt_name(nxt_uint_t level, nxt_uint_t sockopt)
113 {
114     switch (level) {
115 
116     case SOL_SOCKET:
117         switch (sockopt) {
118 
119         case SO_SNDBUF:
120             return "SO_SNDBUF";
121 
122         case SO_RCVBUF:
123             return "SO_RCVBUF";
124 
125         case SO_REUSEADDR:
126             return "SO_TYPE";
127 
128         case SO_TYPE:
129             return "SO_TYPE";
130         }
131 
132         break;
133 
134     case IPPROTO_TCP:
135         switch (sockopt) {
136 
137         case TCP_NODELAY:
138             return "TCP_NODELAY";
139 
140 #ifdef TCP_DEFER_ACCEPT
141         case TCP_DEFER_ACCEPT:
142             return "TCP_DEFER_ACCEPT";
143 #endif
144         }
145 
146         break;
147 
148 #if (NXT_INET6 && defined IPV6_V6ONLY)
149     case IPPROTO_IPV6:
150 
151         switch (sockopt) {
152 
153         case IPV6_V6ONLY:
154             return "IPV6_V6ONLY";
155         }
156 
157         break;
158 #endif
159 
160     }
161 
162     return "";
163 }
164 
165 
166 nxt_int_t
167 nxt_socket_bind(nxt_socket_t s, nxt_sockaddr_t *sa, nxt_bool_t test)
168 {
169     nxt_err_t  err;
170 
171     nxt_thread_log_debug("bind(%d, %*s)", s, sa->text_len, sa->text);
172 
173     if (nxt_fast_path(bind(s, &sa->u.sockaddr, nxt_socklen(sa)) == 0)) {
174         return NXT_OK;
175     }
176 
177     err = nxt_socket_errno;
178 
179     if (err == NXT_EADDRINUSE && test) {
180         return NXT_DECLINED;
181     }
182 
183     nxt_thread_log_error(NXT_LOG_CRIT, "bind(%d, %*s) failed %E",
184                          s, sa->text_len, sa->text, err);
185 
186     return NXT_ERROR;
187 }
188 
189 
190 nxt_int_t
191 nxt_socket_connect(nxt_socket_t s, nxt_sockaddr_t *sa)
192 {
193     nxt_err_t   err;
194     nxt_int_t   ret;
195     nxt_uint_t  level;
196 
197     nxt_thread_log_debug("connect(%d, %*s)", s, sa->text_len, sa->text);
198 
199     if (connect(s, &sa->u.sockaddr, nxt_socklen(sa)) == 0) {
200         return NXT_OK;
201     }
202 
203     err = nxt_socket_errno;
204 
205     switch (err) {
206 
207     case NXT_EINPROGRESS:
208         nxt_thread_log_debug("connect(%d) in progress", s);
209         return NXT_AGAIN;
210 
211     case NXT_ECONNREFUSED:
212 #if (NXT_LINUX)
213     case NXT_EAGAIN:
214         /*
215          * Linux returns EAGAIN instead of ECONNREFUSED
216          * for UNIX sockets if a listen queue is full.
217          */
218 #endif
219         level = NXT_LOG_ERR;
220         ret = NXT_DECLINED;
221         break;
222 
223     case NXT_ECONNRESET:
224     case NXT_ENETDOWN:
225     case NXT_ENETUNREACH:
226     case NXT_EHOSTDOWN:
227     case NXT_EHOSTUNREACH:
228         level = NXT_LOG_ERR;
229         ret = NXT_ERROR;
230         break;
231 
232     default:
233         level = NXT_LOG_CRIT;
234         ret = NXT_ERROR;
235     }
236 
237     nxt_thread_log_error(level, "connect(%d, %*s) failed %E",
238                          s, sa->text_len, sa->text, err);
239 
240     return ret;
241 }
242 
243 
244 void
245 nxt_socket_shutdown(nxt_socket_t s, nxt_uint_t how)
246 {
247     nxt_err_t   err;
248     nxt_uint_t  level;
249 
250     if (nxt_fast_path(shutdown(s, how) == 0)) {
251         nxt_thread_log_debug("shutdown(%d, %ui)", s, how);
252         return;
253     }
254 
255     err = nxt_socket_errno;
256 
257     switch (err) {
258 
259     case NXT_ENOTCONN:
260         level = NXT_LOG_INFO;
261         break;
262 
263     case NXT_ECONNRESET:
264     case NXT_ENETDOWN:
265     case NXT_ENETUNREACH:
266     case NXT_EHOSTDOWN:
267     case NXT_EHOSTUNREACH:
268         level = NXT_LOG_ERR;
269         break;
270 
271     default:
272         level = NXT_LOG_CRIT;
273     }
274 
275     nxt_thread_log_error(level, "shutdown(%d, %ui) failed %E", s, how, err);
276 }
277 
278 
279 nxt_uint_t
280 nxt_socket_error_level(nxt_err_t err, nxt_socket_error_level_t level)
281 {
282     switch (err) {
283 
284     case NXT_ECONNRESET:
285 
286         if ((level & NXT_SOCKET_ECONNRESET_IGNORE) != 0) {
287             return NXT_LOG_DEBUG;
288         }
289 
290         return NXT_LOG_ERR;
291 
292     case NXT_EINVAL:
293 
294         if ((level & NXT_SOCKET_EINVAL_IGNORE) != 0) {
295             return NXT_LOG_DEBUG;
296         }
297 
298         return NXT_LOG_ALERT;
299 
300     case NXT_EPIPE:
301     case NXT_ENOTCONN:
302     case NXT_ETIMEDOUT:
303     case NXT_ENETDOWN:
304     case NXT_ENETUNREACH:
305     case NXT_EHOSTDOWN:
306     case NXT_EHOSTUNREACH:
307 
308         if ((level & NXT_SOCKET_ERROR_IGNORE) != 0) {
309             return NXT_LOG_INFO;
310         }
311 
312         return NXT_LOG_ERR;
313 
314     default:
315         return NXT_LOG_ALERT;
316     }
317 }
318