/src/uWebSockets/uSockets/src/socket.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Authored by Alex Hultman, 2018-2021. |
3 | | * Intellectual property of third-party. |
4 | | |
5 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | * you may not use this file except in compliance with the License. |
7 | | * You may obtain a copy of the License at |
8 | | |
9 | | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | | |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | |
18 | | #ifndef LIBUS_USE_IO_URING |
19 | | |
20 | | #include "libusockets.h" |
21 | | #include "internal/internal.h" |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | #include <stdint.h> |
25 | | |
26 | | /* Shared with SSL */ |
27 | | |
28 | 0 | int us_socket_local_port(int ssl, struct us_socket_t *s) { |
29 | 0 | struct bsd_addr_t addr; |
30 | 0 | if (bsd_local_addr(us_poll_fd(&s->p), &addr)) { |
31 | 0 | return -1; |
32 | 0 | } else { |
33 | 0 | return bsd_addr_get_port(&addr); |
34 | 0 | } |
35 | 0 | } |
36 | | |
37 | 0 | int us_socket_remote_port(int ssl, struct us_socket_t *s) { |
38 | 0 | struct bsd_addr_t addr; |
39 | 0 | if (bsd_remote_addr(us_poll_fd(&s->p), &addr)) { |
40 | 0 | return -1; |
41 | 0 | } else { |
42 | 0 | return bsd_addr_get_port(&addr); |
43 | 0 | } |
44 | 0 | } |
45 | | |
46 | 0 | void us_socket_shutdown_read(int ssl, struct us_socket_t *s) { |
47 | | /* This syscall is idempotent so no extra check is needed */ |
48 | 0 | bsd_shutdown_socket_read(us_poll_fd((struct us_poll_t *) s)); |
49 | 0 | } |
50 | | |
51 | 0 | void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *length) { |
52 | 0 | struct bsd_addr_t addr; |
53 | 0 | if (bsd_remote_addr(us_poll_fd(&s->p), &addr) || *length < bsd_addr_get_ip_length(&addr)) { |
54 | 0 | *length = 0; |
55 | 0 | } else { |
56 | 0 | *length = bsd_addr_get_ip_length(&addr); |
57 | 0 | memcpy(buf, bsd_addr_get_ip(&addr), *length); |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | 13.6M | struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s) { |
62 | 13.6M | return s->context; |
63 | 13.6M | } |
64 | | |
65 | 2.23M | void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds) { |
66 | 2.23M | if (seconds) { |
67 | 2.06M | s->timeout = ((unsigned int)s->context->timestamp + ((seconds + 3) >> 2)) % 240; |
68 | 2.06M | } else { |
69 | 171k | s->timeout = 255; |
70 | 171k | } |
71 | 2.23M | } |
72 | | |
73 | 164k | void us_socket_long_timeout(int ssl, struct us_socket_t *s, unsigned int minutes) { |
74 | 164k | if (minutes) { |
75 | 0 | s->long_timeout = ((unsigned int)s->context->long_timestamp + minutes) % 240; |
76 | 164k | } else { |
77 | 164k | s->long_timeout = 255; |
78 | 164k | } |
79 | 164k | } |
80 | | |
81 | 0 | void us_socket_flush(int ssl, struct us_socket_t *s) { |
82 | 0 | if (!us_socket_is_shut_down(0, s)) { |
83 | 0 | bsd_socket_flush(us_poll_fd((struct us_poll_t *) s)); |
84 | 0 | } |
85 | 0 | } |
86 | | |
87 | 9.58M | int us_socket_is_closed(int ssl, struct us_socket_t *s) { |
88 | 9.58M | return s->prev == (struct us_socket_t *) s->context; |
89 | 9.58M | } |
90 | | |
91 | 0 | int us_socket_is_established(int ssl, struct us_socket_t *s) { |
92 | | /* Everything that is not POLL_TYPE_SEMI_SOCKET is established */ |
93 | 0 | return us_internal_poll_type((struct us_poll_t *) s) != POLL_TYPE_SEMI_SOCKET; |
94 | 0 | } |
95 | | |
96 | | /* Exactly the same as us_socket_close but does not emit on_close event */ |
97 | 0 | struct us_socket_t *us_socket_close_connecting(int ssl, struct us_socket_t *s) { |
98 | 0 | if (!us_socket_is_closed(0, s)) { |
99 | 0 | us_internal_socket_context_unlink_socket(s->context, s); |
100 | 0 | us_poll_stop((struct us_poll_t *) s, s->context->loop); |
101 | 0 | bsd_close_socket(us_poll_fd((struct us_poll_t *) s)); |
102 | | |
103 | | /* Link this socket to the close-list and let it be deleted after this iteration */ |
104 | 0 | s->next = s->context->loop->data.closed_head; |
105 | 0 | s->context->loop->data.closed_head = s; |
106 | | |
107 | | /* Any socket with prev = context is marked as closed */ |
108 | 0 | s->prev = (struct us_socket_t *) s->context; |
109 | | |
110 | | //return s->context->on_close(s, code, reason); |
111 | 0 | } |
112 | 0 | return s; |
113 | 0 | } |
114 | | |
115 | | /* Same as above but emits on_close */ |
116 | 1.63M | struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) { |
117 | 1.63M | if (!us_socket_is_closed(0, s)) { |
118 | 1.63M | if (s->low_prio_state == 1) { |
119 | | /* Unlink this socket from the low-priority queue */ |
120 | 0 | if (!s->prev) s->context->loop->data.low_prio_head = s->next; |
121 | 0 | else s->prev->next = s->next; |
122 | |
|
123 | 0 | if (s->next) s->next->prev = s->prev; |
124 | |
|
125 | 0 | s->prev = 0; |
126 | 0 | s->next = 0; |
127 | 0 | s->low_prio_state = 0; |
128 | 1.63M | } else { |
129 | 1.63M | us_internal_socket_context_unlink_socket(s->context, s); |
130 | 1.63M | } |
131 | 1.63M | us_poll_stop((struct us_poll_t *) s, s->context->loop); |
132 | 1.63M | bsd_close_socket(us_poll_fd((struct us_poll_t *) s)); |
133 | | |
134 | | /* Link this socket to the close-list and let it be deleted after this iteration */ |
135 | 1.63M | s->next = s->context->loop->data.closed_head; |
136 | 1.63M | s->context->loop->data.closed_head = s; |
137 | | |
138 | | /* Any socket with prev = context is marked as closed */ |
139 | 1.63M | s->prev = (struct us_socket_t *) s->context; |
140 | | |
141 | 1.63M | return s->context->on_close(s, code, reason); |
142 | 1.63M | } |
143 | 0 | return s; |
144 | 1.63M | } |
145 | | |
146 | | /* Not shared with SSL */ |
147 | | |
148 | 0 | void *us_socket_get_native_handle(int ssl, struct us_socket_t *s) { |
149 | | #ifndef LIBUS_NO_SSL |
150 | | if (ssl) { |
151 | | return us_internal_ssl_socket_get_native_handle((struct us_internal_ssl_socket_t *) s); |
152 | | } |
153 | | #endif |
154 | |
|
155 | 0 | return (void *) (uintptr_t) us_poll_fd((struct us_poll_t *) s); |
156 | 0 | } |
157 | | |
158 | | /* This is not available for SSL sockets as it makes no sense. */ |
159 | 0 | int us_socket_write2(int ssl, struct us_socket_t *s, const char *header, int header_length, const char *payload, int payload_length) { |
160 | |
|
161 | 0 | if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) { |
162 | 0 | return 0; |
163 | 0 | } |
164 | | |
165 | 0 | int written = bsd_write2(us_poll_fd(&s->p), header, header_length, payload, payload_length); |
166 | 0 | if (written != header_length + payload_length) { |
167 | 0 | us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); |
168 | 0 | } |
169 | |
|
170 | 0 | return written < 0 ? 0 : written; |
171 | 0 | } |
172 | | |
173 | 696k | int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) { |
174 | | #ifndef LIBUS_NO_SSL |
175 | | if (ssl) { |
176 | | return us_internal_ssl_socket_write((struct us_internal_ssl_socket_t *) s, data, length, msg_more); |
177 | | } |
178 | | #endif |
179 | | |
180 | 696k | if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) { |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | 696k | int written = bsd_send(us_poll_fd(&s->p), data, length, msg_more); |
185 | 696k | if (written != length) { |
186 | 665k | s->context->loop->data.last_write_failed = 1; |
187 | 665k | us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); |
188 | 665k | } |
189 | | |
190 | 696k | return written < 0 ? 0 : written; |
191 | 696k | } |
192 | | |
193 | 11.4M | void *us_socket_ext(int ssl, struct us_socket_t *s) { |
194 | | #ifndef LIBUS_NO_SSL |
195 | | if (ssl) { |
196 | | return us_internal_ssl_socket_ext((struct us_internal_ssl_socket_t *) s); |
197 | | } |
198 | | #endif |
199 | | |
200 | 11.4M | return s + 1; |
201 | 11.4M | } |
202 | | |
203 | 1.83M | int us_socket_is_shut_down(int ssl, struct us_socket_t *s) { |
204 | | #ifndef LIBUS_NO_SSL |
205 | | if (ssl) { |
206 | | return us_internal_ssl_socket_is_shut_down((struct us_internal_ssl_socket_t *) s); |
207 | | } |
208 | | #endif |
209 | | |
210 | 1.83M | return us_internal_poll_type(&s->p) == POLL_TYPE_SOCKET_SHUT_DOWN; |
211 | 1.83M | } |
212 | | |
213 | 401k | void us_socket_shutdown(int ssl, struct us_socket_t *s) { |
214 | | #ifndef LIBUS_NO_SSL |
215 | | if (ssl) { |
216 | | us_internal_ssl_socket_shutdown((struct us_internal_ssl_socket_t *) s); |
217 | | return; |
218 | | } |
219 | | #endif |
220 | | |
221 | | /* Todo: should we emit on_close if calling shutdown on an already half-closed socket? |
222 | | * We need more states in that case, we need to track RECEIVED_FIN |
223 | | * so far, the app has to track this and call close as needed */ |
224 | 401k | if (!us_socket_is_closed(ssl, s) && !us_socket_is_shut_down(ssl, s)) { |
225 | 401k | us_internal_poll_set_type(&s->p, POLL_TYPE_SOCKET_SHUT_DOWN); |
226 | 401k | us_poll_change(&s->p, s->context->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE); |
227 | 401k | bsd_shutdown_socket(us_poll_fd((struct us_poll_t *) s)); |
228 | 401k | } |
229 | 401k | } |
230 | | |
231 | | #endif |