/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 | void us_socket_shutdown_read(int ssl, struct us_socket_t *s) { |
38 | | /* This syscall is idempotent so no extra check is needed */ |
39 | 0 | bsd_shutdown_socket_read(us_poll_fd((struct us_poll_t *) s)); |
40 | 0 | } |
41 | | |
42 | 0 | void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *length) { |
43 | 0 | struct bsd_addr_t addr; |
44 | 0 | if (bsd_remote_addr(us_poll_fd(&s->p), &addr) || *length < bsd_addr_get_ip_length(&addr)) { |
45 | 0 | *length = 0; |
46 | 0 | } else { |
47 | 0 | *length = bsd_addr_get_ip_length(&addr); |
48 | 0 | memcpy(buf, bsd_addr_get_ip(&addr), *length); |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | 14.2M | struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s) { |
53 | 14.2M | return s->context; |
54 | 14.2M | } |
55 | | |
56 | 1.29M | void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds) { |
57 | 1.29M | if (seconds) { |
58 | 1.21M | s->timeout = ((unsigned int)s->context->timestamp + ((seconds + 3) >> 2)) % 240; |
59 | 1.21M | } else { |
60 | 79.4k | s->timeout = 255; |
61 | 79.4k | } |
62 | 1.29M | } |
63 | | |
64 | 64.9k | void us_socket_long_timeout(int ssl, struct us_socket_t *s, unsigned int minutes) { |
65 | 64.9k | if (minutes) { |
66 | 0 | s->long_timeout = ((unsigned int)s->context->long_timestamp + minutes) % 240; |
67 | 64.9k | } else { |
68 | 64.9k | s->long_timeout = 255; |
69 | 64.9k | } |
70 | 64.9k | } |
71 | | |
72 | 0 | void us_socket_flush(int ssl, struct us_socket_t *s) { |
73 | 0 | if (!us_socket_is_shut_down(0, s)) { |
74 | 0 | bsd_socket_flush(us_poll_fd((struct us_poll_t *) s)); |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | 5.14M | int us_socket_is_closed(int ssl, struct us_socket_t *s) { |
79 | 5.14M | return s->prev == (struct us_socket_t *) s->context; |
80 | 5.14M | } |
81 | | |
82 | 0 | int us_socket_is_established(int ssl, struct us_socket_t *s) { |
83 | | /* Everything that is not POLL_TYPE_SEMI_SOCKET is established */ |
84 | 0 | return us_internal_poll_type((struct us_poll_t *) s) != POLL_TYPE_SEMI_SOCKET; |
85 | 0 | } |
86 | | |
87 | | /* Exactly the same as us_socket_close but does not emit on_close event */ |
88 | 0 | struct us_socket_t *us_socket_close_connecting(int ssl, struct us_socket_t *s) { |
89 | 0 | if (!us_socket_is_closed(0, s)) { |
90 | 0 | us_internal_socket_context_unlink_socket(s->context, s); |
91 | 0 | us_poll_stop((struct us_poll_t *) s, s->context->loop); |
92 | 0 | bsd_close_socket(us_poll_fd((struct us_poll_t *) s)); |
93 | | |
94 | | /* Link this socket to the close-list and let it be deleted after this iteration */ |
95 | 0 | s->next = s->context->loop->data.closed_head; |
96 | 0 | s->context->loop->data.closed_head = s; |
97 | | |
98 | | /* Any socket with prev = context is marked as closed */ |
99 | 0 | s->prev = (struct us_socket_t *) s->context; |
100 | | |
101 | | //return s->context->on_close(s, code, reason); |
102 | 0 | } |
103 | 0 | return s; |
104 | 0 | } |
105 | | |
106 | | /* Same as above but emits on_close */ |
107 | 998k | struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) { |
108 | 998k | if (!us_socket_is_closed(0, s)) { |
109 | 998k | if (s->low_prio_state == 1) { |
110 | | /* Unlink this socket from the low-priority queue */ |
111 | 0 | if (!s->prev) s->context->loop->data.low_prio_head = s->next; |
112 | 0 | else s->prev->next = s->next; |
113 | |
|
114 | 0 | if (s->next) s->next->prev = s->prev; |
115 | |
|
116 | 0 | s->prev = 0; |
117 | 0 | s->next = 0; |
118 | 0 | s->low_prio_state = 0; |
119 | 998k | } else { |
120 | 998k | us_internal_socket_context_unlink_socket(s->context, s); |
121 | 998k | } |
122 | 998k | us_poll_stop((struct us_poll_t *) s, s->context->loop); |
123 | 998k | bsd_close_socket(us_poll_fd((struct us_poll_t *) s)); |
124 | | |
125 | | /* Link this socket to the close-list and let it be deleted after this iteration */ |
126 | 998k | s->next = s->context->loop->data.closed_head; |
127 | 998k | s->context->loop->data.closed_head = s; |
128 | | |
129 | | /* Any socket with prev = context is marked as closed */ |
130 | 998k | s->prev = (struct us_socket_t *) s->context; |
131 | | |
132 | 998k | return s->context->on_close(s, code, reason); |
133 | 998k | } |
134 | 0 | return s; |
135 | 998k | } |
136 | | |
137 | | /* Not shared with SSL */ |
138 | | |
139 | 0 | void *us_socket_get_native_handle(int ssl, struct us_socket_t *s) { |
140 | | #ifndef LIBUS_NO_SSL |
141 | | if (ssl) { |
142 | | return us_internal_ssl_socket_get_native_handle((struct us_internal_ssl_socket_t *) s); |
143 | | } |
144 | | #endif |
145 | |
|
146 | 0 | return (void *) (uintptr_t) us_poll_fd((struct us_poll_t *) s); |
147 | 0 | } |
148 | | |
149 | | /* This is not available for SSL sockets as it makes no sense. */ |
150 | 0 | int us_socket_write2(int ssl, struct us_socket_t *s, const char *header, int header_length, const char *payload, int payload_length) { |
151 | |
|
152 | 0 | if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) { |
153 | 0 | return 0; |
154 | 0 | } |
155 | | |
156 | 0 | int written = bsd_write2(us_poll_fd(&s->p), header, header_length, payload, payload_length); |
157 | 0 | if (written != header_length + payload_length) { |
158 | 0 | us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); |
159 | 0 | } |
160 | |
|
161 | 0 | return written < 0 ? 0 : written; |
162 | 0 | } |
163 | | |
164 | 473k | int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) { |
165 | | #ifndef LIBUS_NO_SSL |
166 | | if (ssl) { |
167 | | return us_internal_ssl_socket_write((struct us_internal_ssl_socket_t *) s, data, length, msg_more); |
168 | | } |
169 | | #endif |
170 | | |
171 | 473k | if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) { |
172 | 0 | return 0; |
173 | 0 | } |
174 | | |
175 | 473k | int written = bsd_send(us_poll_fd(&s->p), data, length, msg_more); |
176 | 473k | if (written != length) { |
177 | 465k | s->context->loop->data.last_write_failed = 1; |
178 | 465k | us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); |
179 | 465k | } |
180 | | |
181 | 473k | return written < 0 ? 0 : written; |
182 | 473k | } |
183 | | |
184 | 12.4M | void *us_socket_ext(int ssl, struct us_socket_t *s) { |
185 | | #ifndef LIBUS_NO_SSL |
186 | | if (ssl) { |
187 | | return us_internal_ssl_socket_ext((struct us_internal_ssl_socket_t *) s); |
188 | | } |
189 | | #endif |
190 | | |
191 | 12.4M | return s + 1; |
192 | 12.4M | } |
193 | | |
194 | 1.27M | int us_socket_is_shut_down(int ssl, struct us_socket_t *s) { |
195 | | #ifndef LIBUS_NO_SSL |
196 | | if (ssl) { |
197 | | return us_internal_ssl_socket_is_shut_down((struct us_internal_ssl_socket_t *) s); |
198 | | } |
199 | | #endif |
200 | | |
201 | 1.27M | return us_internal_poll_type(&s->p) == POLL_TYPE_SOCKET_SHUT_DOWN; |
202 | 1.27M | } |
203 | | |
204 | 304k | void us_socket_shutdown(int ssl, struct us_socket_t *s) { |
205 | | #ifndef LIBUS_NO_SSL |
206 | | if (ssl) { |
207 | | us_internal_ssl_socket_shutdown((struct us_internal_ssl_socket_t *) s); |
208 | | return; |
209 | | } |
210 | | #endif |
211 | | |
212 | | /* Todo: should we emit on_close if calling shutdown on an already half-closed socket? |
213 | | * We need more states in that case, we need to track RECEIVED_FIN |
214 | | * so far, the app has to track this and call close as needed */ |
215 | 304k | if (!us_socket_is_closed(ssl, s) && !us_socket_is_shut_down(ssl, s)) { |
216 | 304k | us_internal_poll_set_type(&s->p, POLL_TYPE_SOCKET_SHUT_DOWN); |
217 | 304k | us_poll_change(&s->p, s->context->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE); |
218 | 304k | bsd_shutdown_socket(us_poll_fd((struct us_poll_t *) s)); |
219 | 304k | } |
220 | 304k | } |
221 | | |
222 | | #endif |