1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | #include <stdio.h> |
29 | #include <stdlib.h> |
30 | |
31 | #include "containers/containers.h" |
32 | #include "containers/core/containers_common.h" |
33 | #include "containers/core/containers_logging.h" |
34 | #include "net_sockets.h" |
35 | #include "net_sockets_priv.h" |
36 | |
37 | /*****************************************************************************/ |
38 | |
39 | struct vc_container_net_tag |
40 | { |
41 | /** The underlying socket */ |
42 | SOCKET_T socket; |
43 | /** Last error raised on the socket instance. */ |
44 | vc_container_net_status_t status; |
45 | /** Simple socket type */ |
46 | vc_container_net_type_t type; |
47 | /** Socket address, used for sending datagrams. */ |
48 | union { |
49 | struct sockaddr_storage storage; |
50 | struct sockaddr sa; |
51 | struct sockaddr_in in; |
52 | struct sockaddr_in6 in6; |
53 | } to_addr; |
54 | /** Number of bytes in to_addr that have been filled. */ |
55 | SOCKADDR_LEN_T to_addr_len; |
56 | /** Maximum size of datagrams. */ |
57 | size_t max_datagram_size; |
58 | /** Timeout to use when reading from a socket. INFINITE_TIMEOUT_MS waits forever. */ |
59 | uint32_t read_timeout_ms; |
60 | }; |
61 | |
62 | /*****************************************************************************/ |
63 | static void socket_clear_address(struct sockaddr *p_addr) |
64 | { |
65 | switch (p_addr->sa_family) |
66 | { |
67 | case AF_INET: |
68 | { |
69 | struct sockaddr_in *p_addr_v4 = (struct sockaddr_in *)p_addr; |
70 | |
71 | memset(&p_addr_v4->sin_addr, 0, sizeof(p_addr_v4->sin_addr)); |
72 | } |
73 | break; |
74 | case AF_INET6: |
75 | { |
76 | struct sockaddr_in6 *p_addr_v6 = (struct sockaddr_in6 *)p_addr; |
77 | |
78 | memset(&p_addr_v6->sin6_addr, 0, sizeof(p_addr_v6->sin6_addr)); |
79 | } |
80 | break; |
81 | default: |
82 | /* Invalid or unsupported address family */ |
83 | vc_container_assert(0); |
84 | } |
85 | } |
86 | |
87 | /*****************************************************************************/ |
88 | static vc_container_net_status_t socket_set_read_buffer_size(VC_CONTAINER_NET_T *p_ctx, |
89 | uint32_t buffer_size) |
90 | { |
91 | int result; |
92 | const SOCKOPT_CAST_T optptr = (const SOCKOPT_CAST_T)&buffer_size; |
93 | |
94 | result = setsockopt(p_ctx->socket, SOL_SOCKET, SO_RCVBUF, optptr, sizeof(buffer_size)); |
95 | |
96 | if (result == SOCKET_ERROR) |
97 | return vc_container_net_private_last_error(); |
98 | |
99 | return VC_CONTAINER_NET_SUCCESS; |
100 | } |
101 | |
102 | /*****************************************************************************/ |
103 | static vc_container_net_status_t socket_set_read_timeout_ms(VC_CONTAINER_NET_T *p_ctx, |
104 | uint32_t timeout_ms) |
105 | { |
106 | p_ctx->read_timeout_ms = timeout_ms; |
107 | return VC_CONTAINER_NET_SUCCESS; |
108 | } |
109 | |
110 | /*****************************************************************************/ |
111 | static bool socket_wait_for_data( VC_CONTAINER_NET_T *p_ctx, uint32_t timeout_ms ) |
112 | { |
113 | int result; |
114 | fd_set set; |
115 | struct timeval tv; |
116 | |
117 | if (timeout_ms == INFINITE_TIMEOUT_MS) |
118 | return true; |
119 | |
120 | FD_ZERO(&set); |
121 | FD_SET(p_ctx->socket, &set); |
122 | tv.tv_sec = timeout_ms / 1000; |
123 | tv.tv_usec = (timeout_ms - tv.tv_sec * 1000) * 1000; |
124 | result = select(p_ctx->socket + 1, &set, NULL, NULL, &tv); |
125 | |
126 | if (result == SOCKET_ERROR) |
127 | p_ctx->status = vc_container_net_private_last_error(); |
128 | else |
129 | p_ctx->status = VC_CONTAINER_NET_SUCCESS; |
130 | |
131 | return (result == 1); |
132 | } |
133 | |
134 | /*****************************************************************************/ |
135 | VC_CONTAINER_NET_T *vc_container_net_open( const char *address, const char *port, |
136 | vc_container_net_open_flags_t flags, vc_container_net_status_t *p_status ) |
137 | { |
138 | VC_CONTAINER_NET_T *p_ctx; |
139 | struct addrinfo hints, *info, *p; |
140 | int result; |
141 | vc_container_net_status_t status; |
142 | SOCKET_T sock = INVALID_SOCKET; |
143 | |
144 | status = vc_container_net_private_init(); |
145 | if (status != VC_CONTAINER_NET_SUCCESS) |
146 | { |
147 | LOG_ERROR(NULL, "vc_container_net_open: platform initialization failure: %d" , status); |
148 | if (p_status) |
149 | *p_status = status; |
150 | return NULL; |
151 | } |
152 | |
153 | p_ctx = (VC_CONTAINER_NET_T *)malloc(sizeof(VC_CONTAINER_NET_T)); |
154 | if (!p_ctx) |
155 | { |
156 | if (p_status) |
157 | *p_status = VC_CONTAINER_NET_ERROR_NO_MEMORY; |
158 | |
159 | LOG_ERROR(NULL, "vc_container_net_open: malloc fail for VC_CONTAINER_NET_T" ); |
160 | vc_container_net_private_deinit(); |
161 | return NULL; |
162 | } |
163 | |
164 | /* Initialize the net socket instance structure */ |
165 | memset(p_ctx, 0, sizeof(*p_ctx)); |
166 | p_ctx->socket = INVALID_SOCKET; |
167 | if (flags & VC_CONTAINER_NET_OPEN_FLAG_STREAM) |
168 | p_ctx->type = address ? STREAM_CLIENT : STREAM_SERVER; |
169 | else |
170 | p_ctx->type = address ? DATAGRAM_SENDER : DATAGRAM_RECEIVER; |
171 | |
172 | /* Create the address info linked list from the data provided */ |
173 | memset(&hints, 0, sizeof(hints)); |
174 | switch (flags & VC_CONTAINER_NET_OPEN_FLAG_FORCE_MASK) |
175 | { |
176 | case 0: |
177 | hints.ai_family = AF_UNSPEC; |
178 | break; |
179 | case VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP4: |
180 | hints.ai_family = AF_INET; |
181 | break; |
182 | case VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP6: |
183 | hints.ai_family = AF_INET6; |
184 | break; |
185 | default: |
186 | status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER; |
187 | LOG_ERROR(NULL, "vc_container_net_open: invalid address forcing flag" ); |
188 | goto error; |
189 | } |
190 | hints.ai_socktype = (flags & VC_CONTAINER_NET_OPEN_FLAG_STREAM) ? SOCK_STREAM : SOCK_DGRAM; |
191 | |
192 | result = getaddrinfo(address, port, &hints, &info); |
193 | if (result) |
194 | { |
195 | status = vc_container_net_private_last_error(); |
196 | LOG_ERROR(NULL, "vc_container_net_open: unable to get address info: %d" , status); |
197 | goto error; |
198 | } |
199 | |
200 | /* Not all address infos may be useable. Search for one that is by skipping any |
201 | * that provoke errors. */ |
202 | for(p = info; (p != NULL) && (sock == INVALID_SOCKET) ; p = p->ai_next) |
203 | { |
204 | sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol); |
205 | if (sock == INVALID_SOCKET) |
206 | { |
207 | status = vc_container_net_private_last_error(); |
208 | continue; |
209 | } |
210 | |
211 | switch (p_ctx->type) |
212 | { |
213 | case STREAM_CLIENT: |
214 | /* Simply connect to the given address/port */ |
215 | if (connect(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR) |
216 | status = vc_container_net_private_last_error(); |
217 | break; |
218 | |
219 | case DATAGRAM_SENDER: |
220 | /* Nothing further to do */ |
221 | break; |
222 | |
223 | case STREAM_SERVER: |
224 | /* Try to avoid socket reuse timing issues on TCP server sockets */ |
225 | vc_container_net_private_set_reusable(sock, true); |
226 | |
227 | /* Allow any source address */ |
228 | socket_clear_address(p->ai_addr); |
229 | |
230 | if (bind(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR) |
231 | status = vc_container_net_private_last_error(); |
232 | break; |
233 | |
234 | case DATAGRAM_RECEIVER: |
235 | /* Allow any source address */ |
236 | socket_clear_address(p->ai_addr); |
237 | |
238 | if (bind(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR) |
239 | status = vc_container_net_private_last_error(); |
240 | break; |
241 | } |
242 | |
243 | if (status == VC_CONTAINER_NET_SUCCESS) |
244 | { |
245 | /* Save addressing information for later use */ |
246 | p_ctx->to_addr_len = p->ai_addrlen; |
247 | memcpy(&p_ctx->to_addr, p->ai_addr, p->ai_addrlen); |
248 | } else { |
249 | vc_container_net_private_close(sock); /* Try next entry in list */ |
250 | sock = INVALID_SOCKET; |
251 | } |
252 | } |
253 | |
254 | freeaddrinfo(info); |
255 | |
256 | if (sock == INVALID_SOCKET) |
257 | { |
258 | LOG_ERROR(NULL, "vc_container_net_open: failed to open socket: %d" , status); |
259 | goto error; |
260 | } |
261 | |
262 | p_ctx->socket = sock; |
263 | p_ctx->max_datagram_size = vc_container_net_private_maximum_datagram_size(sock); |
264 | p_ctx->read_timeout_ms = INFINITE_TIMEOUT_MS; |
265 | |
266 | if (p_status) |
267 | *p_status = VC_CONTAINER_NET_SUCCESS; |
268 | |
269 | return p_ctx; |
270 | |
271 | error: |
272 | if (p_status) |
273 | *p_status = status; |
274 | (void)vc_container_net_close(p_ctx); |
275 | return NULL; |
276 | } |
277 | |
278 | /*****************************************************************************/ |
279 | vc_container_net_status_t vc_container_net_close( VC_CONTAINER_NET_T *p_ctx ) |
280 | { |
281 | if (!p_ctx) |
282 | return VC_CONTAINER_NET_ERROR_INVALID_SOCKET; |
283 | |
284 | if (p_ctx->socket != INVALID_SOCKET) |
285 | { |
286 | vc_container_net_private_close(p_ctx->socket); |
287 | p_ctx->socket = INVALID_SOCKET; |
288 | } |
289 | free(p_ctx); |
290 | |
291 | vc_container_net_private_deinit(); |
292 | |
293 | return VC_CONTAINER_NET_SUCCESS; |
294 | } |
295 | |
296 | /*****************************************************************************/ |
297 | vc_container_net_status_t vc_container_net_status( VC_CONTAINER_NET_T *p_ctx ) |
298 | { |
299 | if (!p_ctx) |
300 | return VC_CONTAINER_NET_ERROR_INVALID_SOCKET; |
301 | return p_ctx->status; |
302 | } |
303 | |
304 | /*****************************************************************************/ |
305 | size_t vc_container_net_read( VC_CONTAINER_NET_T *p_ctx, void *buffer, size_t size ) |
306 | { |
307 | int result = 0; |
308 | |
309 | if (!p_ctx) |
310 | return 0; |
311 | |
312 | if (!buffer) |
313 | { |
314 | p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER; |
315 | return 0; |
316 | } |
317 | |
318 | p_ctx->status = VC_CONTAINER_NET_SUCCESS; |
319 | |
320 | switch (p_ctx->type) |
321 | { |
322 | case STREAM_CLIENT: |
323 | case STREAM_SERVER: |
324 | /* Receive data from the stream */ |
325 | if (socket_wait_for_data(p_ctx, p_ctx->read_timeout_ms)) |
326 | { |
327 | result = recv(p_ctx->socket, buffer, (int)size, 0); |
328 | if (!result) |
329 | p_ctx->status = VC_CONTAINER_NET_ERROR_CONNECTION_LOST; |
330 | } else |
331 | p_ctx->status = VC_CONTAINER_NET_ERROR_TIMED_OUT; |
332 | break; |
333 | |
334 | case DATAGRAM_RECEIVER: |
335 | { |
336 | /* Receive the packet */ |
337 | /* FIXME Potential for data loss, as rest of packet will be lost if buffer was not large enough */ |
338 | if (socket_wait_for_data(p_ctx, p_ctx->read_timeout_ms)) |
339 | { |
340 | result = recvfrom(p_ctx->socket, buffer, size, 0, &p_ctx->to_addr.sa, &p_ctx->to_addr_len); |
341 | if (!result) |
342 | p_ctx->status = VC_CONTAINER_NET_ERROR_CONNECTION_LOST; |
343 | } else |
344 | p_ctx->status = VC_CONTAINER_NET_ERROR_TIMED_OUT; |
345 | } |
346 | break; |
347 | |
348 | default: /* DATAGRAM_SENDER */ |
349 | p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED; |
350 | result = 0; |
351 | break; |
352 | } |
353 | |
354 | if (result == SOCKET_ERROR) |
355 | { |
356 | p_ctx->status = vc_container_net_private_last_error(); |
357 | result = 0; |
358 | } |
359 | |
360 | return (size_t)result; |
361 | } |
362 | |
363 | /*****************************************************************************/ |
364 | size_t vc_container_net_write( VC_CONTAINER_NET_T *p_ctx, const void *buffer, size_t size ) |
365 | { |
366 | int result; |
367 | |
368 | if (!p_ctx) |
369 | return 0; |
370 | |
371 | if (!buffer) |
372 | { |
373 | p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER; |
374 | return 0; |
375 | } |
376 | |
377 | p_ctx->status = VC_CONTAINER_NET_SUCCESS; |
378 | |
379 | switch (p_ctx->type) |
380 | { |
381 | case STREAM_CLIENT: |
382 | case STREAM_SERVER: |
383 | /* Send data to the stream */ |
384 | result = send(p_ctx->socket, buffer, (int)size, 0); |
385 | break; |
386 | |
387 | case DATAGRAM_SENDER: |
388 | /* Send the datagram */ |
389 | |
390 | if (size > p_ctx->max_datagram_size) |
391 | size = p_ctx->max_datagram_size; |
392 | |
393 | result = sendto(p_ctx->socket, buffer, size, 0, &p_ctx->to_addr.sa, p_ctx->to_addr_len); |
394 | break; |
395 | |
396 | default: /* DATAGRAM_RECEIVER */ |
397 | p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED; |
398 | result = 0; |
399 | break; |
400 | } |
401 | |
402 | if (result == SOCKET_ERROR) |
403 | { |
404 | p_ctx->status = vc_container_net_private_last_error(); |
405 | result = 0; |
406 | } |
407 | |
408 | return (size_t)result; |
409 | } |
410 | |
411 | /*****************************************************************************/ |
412 | vc_container_net_status_t vc_container_net_listen( VC_CONTAINER_NET_T *p_ctx, uint32_t maximum_connections ) |
413 | { |
414 | if (!p_ctx) |
415 | return VC_CONTAINER_NET_ERROR_INVALID_SOCKET; |
416 | |
417 | p_ctx->status = VC_CONTAINER_NET_SUCCESS; |
418 | |
419 | if (p_ctx->type == STREAM_SERVER) |
420 | { |
421 | if (listen(p_ctx->socket, maximum_connections) == SOCKET_ERROR) |
422 | p_ctx->status = vc_container_net_private_last_error(); |
423 | } else { |
424 | p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED; |
425 | } |
426 | |
427 | return p_ctx->status; |
428 | } |
429 | |
430 | /*****************************************************************************/ |
431 | vc_container_net_status_t vc_container_net_accept( VC_CONTAINER_NET_T *p_server_ctx, VC_CONTAINER_NET_T **pp_client_ctx ) |
432 | { |
433 | VC_CONTAINER_NET_T *p_client_ctx = NULL; |
434 | |
435 | if (!p_server_ctx) |
436 | return VC_CONTAINER_NET_ERROR_INVALID_SOCKET; |
437 | |
438 | if (!pp_client_ctx) |
439 | return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER; |
440 | |
441 | *pp_client_ctx = NULL; |
442 | |
443 | if (p_server_ctx->type != STREAM_SERVER) |
444 | { |
445 | p_server_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED; |
446 | goto error; |
447 | } |
448 | |
449 | p_client_ctx = (VC_CONTAINER_NET_T *)malloc(sizeof(VC_CONTAINER_NET_T)); |
450 | if (!p_client_ctx) |
451 | { |
452 | p_server_ctx->status = VC_CONTAINER_NET_ERROR_NO_MEMORY; |
453 | goto error; |
454 | } |
455 | |
456 | /* Initialise the new context with the address information from the server context */ |
457 | memset(p_client_ctx, 0, sizeof(*p_client_ctx)); |
458 | memcpy(&p_client_ctx->to_addr, &p_server_ctx->to_addr, p_server_ctx->to_addr_len); |
459 | p_client_ctx->to_addr_len = p_server_ctx->to_addr_len; |
460 | |
461 | p_client_ctx->socket = accept(p_server_ctx->socket, &p_client_ctx->to_addr.sa, &p_client_ctx->to_addr_len); |
462 | |
463 | if (p_client_ctx->socket == INVALID_SOCKET) |
464 | { |
465 | p_server_ctx->status = vc_container_net_private_last_error(); |
466 | goto error; |
467 | } |
468 | |
469 | /* Need to bump up the initialisation count, as a new context has been created */ |
470 | p_server_ctx->status = vc_container_net_private_init(); |
471 | if (p_server_ctx->status != VC_CONTAINER_NET_SUCCESS) |
472 | goto error; |
473 | |
474 | p_client_ctx->type = STREAM_CLIENT; |
475 | p_client_ctx->max_datagram_size = vc_container_net_private_maximum_datagram_size(p_client_ctx->socket); |
476 | p_client_ctx->read_timeout_ms = INFINITE_TIMEOUT_MS; |
477 | p_client_ctx->status = VC_CONTAINER_NET_SUCCESS; |
478 | |
479 | *pp_client_ctx = p_client_ctx; |
480 | return VC_CONTAINER_NET_SUCCESS; |
481 | |
482 | error: |
483 | if (p_client_ctx) |
484 | free(p_client_ctx); |
485 | return p_server_ctx->status; |
486 | } |
487 | |
488 | /*****************************************************************************/ |
489 | bool vc_container_net_is_data_available( VC_CONTAINER_NET_T *p_ctx ) |
490 | { |
491 | if (!p_ctx) |
492 | return false; |
493 | |
494 | if (p_ctx->type == DATAGRAM_SENDER) |
495 | { |
496 | p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED; |
497 | return false; |
498 | } |
499 | |
500 | return socket_wait_for_data(p_ctx, 0); |
501 | } |
502 | |
503 | /*****************************************************************************/ |
504 | size_t vc_container_net_maximum_datagram_size( VC_CONTAINER_NET_T *p_ctx ) |
505 | { |
506 | return p_ctx ? p_ctx->max_datagram_size : 0; |
507 | } |
508 | |
509 | /*****************************************************************************/ |
510 | static vc_container_net_status_t translate_getnameinfo_error( int error ) |
511 | { |
512 | switch (error) |
513 | { |
514 | case EAI_AGAIN: return VC_CONTAINER_NET_ERROR_TRY_AGAIN; |
515 | case EAI_FAIL: return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND; |
516 | case EAI_MEMORY: return VC_CONTAINER_NET_ERROR_NO_MEMORY; |
517 | case EAI_NONAME: return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND; |
518 | |
519 | /* All other errors are unexpected, so just map to a general purpose error code. */ |
520 | default: |
521 | return VC_CONTAINER_NET_ERROR_GENERAL; |
522 | } |
523 | } |
524 | |
525 | /*****************************************************************************/ |
526 | vc_container_net_status_t vc_container_net_get_client_name( VC_CONTAINER_NET_T *p_ctx, char *name, size_t name_len ) |
527 | { |
528 | int result; |
529 | |
530 | if (!p_ctx) |
531 | return VC_CONTAINER_NET_ERROR_INVALID_SOCKET; |
532 | |
533 | if (p_ctx->socket == INVALID_SOCKET) |
534 | p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_CONNECTED; |
535 | else if (!name || !name_len) |
536 | p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER; |
537 | else if ((result = getnameinfo(&p_ctx->to_addr.sa, p_ctx->to_addr_len, name, name_len, NULL, 0, 0)) != 0) |
538 | p_ctx->status = translate_getnameinfo_error(result); |
539 | else |
540 | p_ctx->status = VC_CONTAINER_NET_SUCCESS; |
541 | |
542 | return p_ctx->status; |
543 | } |
544 | |
545 | /*****************************************************************************/ |
546 | vc_container_net_status_t vc_container_net_get_client_port( VC_CONTAINER_NET_T *p_ctx , unsigned short *port ) |
547 | { |
548 | if (!p_ctx) |
549 | return VC_CONTAINER_NET_ERROR_INVALID_SOCKET; |
550 | |
551 | if (p_ctx->socket == INVALID_SOCKET) |
552 | p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_CONNECTED; |
553 | else if (!port) |
554 | p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER; |
555 | else |
556 | { |
557 | p_ctx->status = VC_CONTAINER_NET_SUCCESS; |
558 | switch (p_ctx->to_addr.sa.sa_family) |
559 | { |
560 | case AF_INET: |
561 | *port = ntohs(p_ctx->to_addr.in.sin_port); |
562 | break; |
563 | case AF_INET6: |
564 | *port = ntohs(p_ctx->to_addr.in6.sin6_port); |
565 | break; |
566 | default: |
567 | /* Highly unexepcted address family! */ |
568 | p_ctx->status = VC_CONTAINER_NET_ERROR_GENERAL; |
569 | } |
570 | } |
571 | |
572 | return p_ctx->status; |
573 | } |
574 | |
575 | /*****************************************************************************/ |
576 | vc_container_net_status_t vc_container_net_control( VC_CONTAINER_NET_T *p_ctx, |
577 | vc_container_net_control_t operation, |
578 | va_list args) |
579 | { |
580 | vc_container_net_status_t status; |
581 | |
582 | switch (operation) |
583 | { |
584 | case VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE: |
585 | status = socket_set_read_buffer_size(p_ctx, va_arg(args, uint32_t)); |
586 | break; |
587 | case VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS: |
588 | status = socket_set_read_timeout_ms(p_ctx, va_arg(args, uint32_t)); |
589 | break; |
590 | default: |
591 | status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED; |
592 | } |
593 | |
594 | return status; |
595 | } |
596 | |
597 | /*****************************************************************************/ |
598 | uint32_t vc_container_net_to_host( uint32_t value ) |
599 | { |
600 | return ntohl(value); |
601 | } |
602 | |
603 | /*****************************************************************************/ |
604 | uint32_t vc_container_net_from_host( uint32_t value ) |
605 | { |
606 | return htonl(value); |
607 | } |
608 | |
609 | /*****************************************************************************/ |
610 | uint16_t vc_container_net_to_host_16( uint16_t value ) |
611 | { |
612 | return ntohs(value); |
613 | } |
614 | |
615 | /*****************************************************************************/ |
616 | uint16_t vc_container_net_from_host_16( uint16_t value ) |
617 | { |
618 | return htons(value); |
619 | } |
620 | |