1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 4 #include <assert.h> 5 #include <errno.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <sys/ioctl.h> 9 #include <sys/socket.h> 10 #include <sys/types.h> 11 #include <sys/ucred.h> 12 #include <netinet/tcp.h> 13 14 #include <net/gen/in.h> 15 #include <net/gen/tcp.h> 16 #include <net/gen/tcp_io.h> 17 #include <net/gen/udp.h> 18 #include <net/gen/udp_io.h> 19 20 #include <minix/type.h> 21 22 #define DEBUG 0 23 24 static int _tcp_getsockopt(int sock, int level, int option_name, 25 void *__restrict option_value, socklen_t *__restrict option_len); 26 static int _udp_getsockopt(int sock, int level, int option_name, 27 void *__restrict option_value, socklen_t *__restrict option_len); 28 static int _uds_getsockopt(int sock, int level, int option_name, 29 void *__restrict option_value, socklen_t *__restrict option_len); 30 static void getsockopt_copy(void *return_value, size_t return_len, 31 void *__restrict option_value, socklen_t *__restrict option_len); 32 33 int getsockopt(int sock, int level, int option_name, 34 void *__restrict option_value, socklen_t *__restrict option_len) 35 { 36 int r; 37 nwio_tcpopt_t tcpopt; 38 nwio_udpopt_t udpopt; 39 struct sockaddr_un uds_addr; 40 41 r= ioctl(sock, NWIOGTCPOPT, &tcpopt); 42 if (r != -1 || errno != ENOTTY) 43 { 44 if (r == -1) 45 { 46 /* Bad file descriptor */ 47 return -1; 48 } 49 return _tcp_getsockopt(sock, level, option_name, 50 option_value, option_len); 51 } 52 53 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 54 if (r != -1 || errno != ENOTTY) 55 { 56 if (r == -1) 57 { 58 /* Bad file descriptor */ 59 return -1; 60 } 61 return _udp_getsockopt(sock, level, option_name, 62 option_value, option_len); 63 } 64 65 r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 66 if (r != -1 || errno != ENOTTY) 67 { 68 if (r == -1) 69 { 70 /* Bad file descriptor */ 71 return -1; 72 } 73 return _uds_getsockopt(sock, level, option_name, 74 option_value, option_len); 75 } 76 77 78 #if DEBUG 79 fprintf(stderr, "getsockopt: not implemented for fd %d\n", sock); 80 #endif 81 errno= ENOTSOCK; 82 return -1; 83 } 84 85 static void getsockopt_copy(void *return_value, size_t return_len, 86 void *__restrict option_value, socklen_t *__restrict option_len) 87 { 88 /* copy as much data as possible */ 89 if (*option_len < return_len) 90 memcpy(option_value, return_value, *option_len); 91 else 92 memcpy(option_value, return_value, return_len); 93 94 /* return length */ 95 *option_len = return_len; 96 } 97 98 static int _tcp_getsockopt(int sock, int level, int option_name, 99 void *__restrict option_value, socklen_t *__restrict option_len) 100 { 101 int i, r, err; 102 103 if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 104 { 105 i = 1; /* Binds to TIME_WAIT sockets never cause errors */ 106 getsockopt_copy(&i, sizeof(i), option_value, option_len); 107 return 0; 108 } 109 if (level == SOL_SOCKET && option_name == SO_KEEPALIVE) 110 { 111 i = 1; /* Keepalive is always on */ 112 getsockopt_copy(&i, sizeof(i), option_value, option_len); 113 return 0; 114 } 115 if (level == SOL_SOCKET && option_name == SO_ERROR) 116 { 117 r = ioctl(sock, NWIOTCPGERROR, &err); 118 if (r != 0) 119 return r; 120 121 getsockopt_copy(&err, sizeof(err), option_value, option_len); 122 return 0; 123 } 124 if (level == SOL_SOCKET && option_name == SO_RCVBUF) 125 { 126 i = 32 * 1024; /* Receive buffer in the current 127 * implementation 128 */ 129 getsockopt_copy(&i, sizeof(i), option_value, option_len); 130 return 0; 131 } 132 if (level == SOL_SOCKET && option_name == SO_SNDBUF) 133 { 134 i = 32 * 1024; /* Send buffer in the current implementation */ 135 getsockopt_copy(&i, sizeof(i), option_value, option_len); 136 return 0; 137 } 138 if (level == SOL_SOCKET && option_name == SO_TYPE) 139 { 140 i = SOCK_STREAM; /* this is a TCP socket */ 141 getsockopt_copy(&i, sizeof(i), option_value, option_len); 142 return 0; 143 } 144 if (level == IPPROTO_TCP && option_name == TCP_NODELAY) 145 { 146 i = 0; /* nodelay is always off */ 147 getsockopt_copy(&i, sizeof(i), option_value, option_len); 148 return 0; 149 } 150 #if DEBUG 151 fprintf(stderr, "_tcp_getsocketopt: level %d, name %d\n", 152 level, option_name); 153 #endif 154 155 errno= ENOPROTOOPT; 156 return -1; 157 } 158 159 static int _udp_getsockopt(int sock, int level, int option_name, 160 void *__restrict option_value, socklen_t *__restrict option_len) 161 { 162 int i; 163 164 if (level == SOL_SOCKET && option_name == SO_TYPE) 165 { 166 i = SOCK_DGRAM; /* this is a UDP socket */ 167 getsockopt_copy(&i, sizeof(i), option_value, option_len); 168 return 0; 169 } 170 #if DEBUG 171 fprintf(stderr, "_udp_getsocketopt: level %d, name %d\n", 172 level, option_name); 173 #endif 174 175 errno= ENOSYS; 176 return -1; 177 } 178 179 static int _uds_getsockopt(int sock, int level, int option_name, 180 void *__restrict option_value, socklen_t *__restrict option_len) 181 { 182 int i, r; 183 size_t size; 184 185 if (level == SOL_SOCKET && option_name == SO_RCVBUF) 186 { 187 r= ioctl(sock, NWIOGUDSRCVBUF, &size); 188 if (r == -1) { 189 return r; 190 } 191 192 getsockopt_copy(&size, sizeof(size), option_value, option_len); 193 return 0; 194 } 195 196 if (level == SOL_SOCKET && option_name == SO_SNDBUF) 197 { 198 r= ioctl(sock, NWIOGUDSSNDBUF, &size); 199 if (r == -1) { 200 return r; 201 } 202 203 getsockopt_copy(&size, sizeof(size), option_value, option_len); 204 return 0; 205 } 206 207 if (level == SOL_SOCKET && option_name == SO_TYPE) 208 { 209 r= ioctl(sock, NWIOGUDSSOTYPE, &i); 210 if (r == -1) { 211 return r; 212 } 213 214 getsockopt_copy(&i, sizeof(i), option_value, option_len); 215 return 0; 216 } 217 218 if (level == SOL_SOCKET && option_name == SO_PEERCRED) 219 { 220 struct uucred cred; 221 222 r= ioctl(sock, NWIOGUDSPEERCRED, &cred); 223 if (r == -1) { 224 return -1; 225 } 226 227 getsockopt_copy(&cred, sizeof(struct uucred), option_value, 228 option_len); 229 return 0; 230 } 231 232 233 if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 234 { 235 i = 1; /* as long as nobody is listen()ing on the address, 236 * it can be reused without waiting for a 237 * timeout to expire. 238 */ 239 getsockopt_copy(&i, sizeof(i), option_value, option_len); 240 return 0; 241 } 242 243 if (level == SOL_SOCKET && option_name == SO_PASSCRED) 244 { 245 i = 1; /* option is always 'on' */ 246 getsockopt_copy(&i, sizeof(i), option_value, option_len); 247 return 0; 248 } 249 250 #if DEBUG 251 fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n", 252 level, option_name); 253 #endif 254 255 errno= ENOSYS; 256 return -1; 257 } 258