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