| 1 | /* Tests for socket address type definitions. |
| 2 | Copyright (C) 2016-2024 Free Software Foundation, Inc. |
| 3 | This file is part of the GNU C Library. |
| 4 | |
| 5 | The GNU C Library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public License as |
| 7 | published by the Free Software Foundation; either version 2.1 of the |
| 8 | License, or (at your option) any later version. |
| 9 | |
| 10 | The GNU C Library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with the GNU C Library; see the file COPYING.LIB. If |
| 17 | not, see <https://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | #include <netinet/in.h> |
| 20 | #include <stdbool.h> |
| 21 | #include <stddef.h> |
| 22 | #include <stdio.h> |
| 23 | #include <stdlib.h> |
| 24 | #include <string.h> |
| 25 | #include <sys/socket.h> |
| 26 | #include <sys/un.h> |
| 27 | |
| 28 | /* This is a copy of the previous definition of struct |
| 29 | sockaddr_storage. It is not equal to the old value of _SS_SIZE |
| 30 | (128) on all architectures. We must stay compatible with the old |
| 31 | definition. */ |
| 32 | |
| 33 | #define OLD_REFERENCE_SIZE 128 |
| 34 | #define OLD_PADSIZE (OLD_REFERENCE_SIZE - (2 * sizeof (__ss_aligntype))) |
| 35 | struct sockaddr_storage_old |
| 36 | { |
| 37 | __SOCKADDR_COMMON (old_); |
| 38 | __ss_aligntype old_align; |
| 39 | char old_padding[OLD_PADSIZE]; |
| 40 | }; |
| 41 | |
| 42 | static bool errors; |
| 43 | |
| 44 | static void |
| 45 | check (bool ok, const char *message) |
| 46 | { |
| 47 | if (!ok) |
| 48 | { |
| 49 | printf (format: "error: failed check: %s\n" , message); |
| 50 | errors = true; |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | static int |
| 55 | do_test (void) |
| 56 | { |
| 57 | check (OLD_REFERENCE_SIZE >= _SS_SIZE, |
| 58 | message: "old target size is not smaller than actual size" ); |
| 59 | check (ok: sizeof (struct sockaddr_storage_old) |
| 60 | == sizeof (struct sockaddr_storage), |
| 61 | message: "old and new sizes match" ); |
| 62 | check (ok: __alignof (struct sockaddr_storage_old) |
| 63 | == __alignof (struct sockaddr_storage), |
| 64 | message: "old and new alignment matches" ); |
| 65 | check (offsetof (struct sockaddr_storage_old, old_family) |
| 66 | == offsetof (struct sockaddr_storage, ss_family), |
| 67 | message: "old and new family offsets match" ); |
| 68 | check (ok: sizeof (struct sockaddr_storage) == _SS_SIZE, |
| 69 | message: "struct sockaddr_storage size" ); |
| 70 | |
| 71 | /* Check for lack of holes in the struct definition. */ |
| 72 | check (offsetof (struct sockaddr_storage, __ss_padding) |
| 73 | == __SOCKADDR_COMMON_SIZE, |
| 74 | message: "implicit padding before explicit padding" ); |
| 75 | check (offsetof (struct sockaddr_storage, __ss_align) |
| 76 | == __SOCKADDR_COMMON_SIZE |
| 77 | + sizeof (((struct sockaddr_storage) {}).__ss_padding), |
| 78 | message: "implicit padding before explicit padding" ); |
| 79 | |
| 80 | /* Check for POSIX compatibility requirements between struct |
| 81 | sockaddr_storage and struct sockaddr_un. */ |
| 82 | check (ok: sizeof (struct sockaddr_storage) >= sizeof (struct sockaddr_un), |
| 83 | message: "sockaddr_storage is at least as large as sockaddr_un" ); |
| 84 | check (ok: __alignof (struct sockaddr_storage) |
| 85 | >= __alignof (struct sockaddr_un), |
| 86 | message: "sockaddr_storage is at least as aligned as sockaddr_un" ); |
| 87 | check (offsetof (struct sockaddr_storage, ss_family) |
| 88 | == offsetof (struct sockaddr_un, sun_family), |
| 89 | message: "family offsets match" ); |
| 90 | |
| 91 | /* Check that the compiler preserves bit patterns in aggregate |
| 92 | copies. Based on <https://gcc.gnu.org/PR71120>. */ |
| 93 | check (ok: sizeof (struct sockaddr_storage) >= sizeof (struct sockaddr_in), |
| 94 | message: "sockaddr_storage is at least as large as sockaddr_in" ); |
| 95 | { |
| 96 | struct sockaddr_storage addr; |
| 97 | memset (&addr, 0, sizeof (addr)); |
| 98 | { |
| 99 | struct sockaddr_in *sinp = (struct sockaddr_in *)&addr; |
| 100 | sinp->sin_family = AF_INET; |
| 101 | sinp->sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
| 102 | sinp->sin_port = htons (80); |
| 103 | } |
| 104 | struct sockaddr_storage copy; |
| 105 | copy = addr; |
| 106 | |
| 107 | struct sockaddr_storage *p = malloc (size: sizeof (*p)); |
| 108 | if (p == NULL) |
| 109 | { |
| 110 | printf (format: "error: malloc: %m\n" ); |
| 111 | return 1; |
| 112 | } |
| 113 | *p = copy; |
| 114 | const struct sockaddr_in *sinp = (const struct sockaddr_in *)p; |
| 115 | check (ok: sinp->sin_family == AF_INET, message: "sin_family" ); |
| 116 | check (ok: sinp->sin_addr.s_addr == htonl (INADDR_LOOPBACK), message: "sin_addr" ); |
| 117 | check (ok: sinp->sin_port == htons (80), message: "sin_port" ); |
| 118 | free (ptr: p); |
| 119 | } |
| 120 | |
| 121 | return errors; |
| 122 | } |
| 123 | |
| 124 | #define TEST_FUNCTION do_test () |
| 125 | #include "../test-skeleton.c" |
| 126 | |