1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 4 #include <assert.h> 5 #include <errno.h> 6 #include <stdio.h> 7 #include <sys/ioctl.h> 8 #include <sys/socket.h> 9 #include <sys/types.h> 10 #include <netinet/tcp.h> 11 12 #include <net/gen/in.h> 13 #include <net/gen/tcp.h> 14 #include <net/gen/tcp_io.h> 15 #include <net/gen/udp.h> 16 #include <net/gen/udp_io.h> 17 18 #define DEBUG 0 19 20 static int _tcp_setsockopt(int sock, int level, int option_name, 21 const void *option_value, socklen_t option_len); 22 23 static int _udp_setsockopt(int sock, int level, int option_name, 24 const void *option_value, socklen_t option_len); 25 26 static int _uds_setsockopt(int sock, int level, int option_name, 27 const void *option_value, socklen_t option_len); 28 29 int setsockopt(int sock, int level, int option_name, 30 const void *option_value, socklen_t option_len) 31 { 32 int r; 33 nwio_tcpopt_t tcpopt; 34 nwio_udpopt_t udpopt; 35 struct sockaddr_un uds_addr; 36 37 r= ioctl(sock, NWIOGTCPOPT, &tcpopt); 38 if (r != -1 || errno != ENOTTY) 39 { 40 if (r == -1) 41 { 42 /* Bad file descriptor */ 43 return -1; 44 } 45 return _tcp_setsockopt(sock, level, option_name, 46 option_value, option_len); 47 } 48 49 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 50 if (r != -1 || errno != ENOTTY) 51 { 52 if (r == -1) 53 { 54 /* Bad file descriptor */ 55 return -1; 56 } 57 return _udp_setsockopt(sock, level, option_name, 58 option_value, option_len); 59 } 60 61 r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 62 if (r != -1 || errno != ENOTTY) 63 { 64 if (r == -1) 65 { 66 /* Bad file descriptor */ 67 return -1; 68 } 69 return _uds_setsockopt(sock, level, option_name, 70 option_value, option_len); 71 } 72 73 74 #if DEBUG 75 fprintf(stderr, "setsockopt: not implemented for fd %d\n", sock); 76 #endif 77 errno= ENOTSOCK; 78 return -1; 79 } 80 81 static int _tcp_setsockopt(int sock, int level, int option_name, 82 const void *option_value, socklen_t option_len) 83 { 84 int i; 85 86 if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 87 { 88 if (option_len != sizeof(i)) 89 { 90 errno= EINVAL; 91 return -1; 92 } 93 i= *(const int *)option_value; 94 if (!i) 95 { 96 /* At the moment there is no way to turn off 97 * reusing addresses. 98 */ 99 errno= ENOSYS; 100 return -1; 101 } 102 return 0; 103 } 104 if (level == SOL_SOCKET && option_name == SO_KEEPALIVE) 105 { 106 if (option_len != sizeof(i)) 107 { 108 errno= EINVAL; 109 return -1; 110 } 111 i= *(const int *)option_value; 112 if (!i) 113 { 114 /* At the moment there is no way to turn off 115 * keepalives. 116 */ 117 errno= ENOSYS; 118 return -1; 119 } 120 return 0; 121 } 122 if (level == SOL_SOCKET && option_name == SO_RCVBUF) 123 { 124 if (option_len != sizeof(i)) 125 { 126 errno= EINVAL; 127 return -1; 128 } 129 i= *(const int *)option_value; 130 if (i > 32*1024) 131 { 132 /* The receive buffer is limited to 32K at the moment. 133 */ 134 errno= ENOSYS; 135 return -1; 136 } 137 /* There is no way to reduce the receive buffer, do we have to 138 * let this call fail for smaller buffers? 139 */ 140 return 0; 141 } 142 if (level == SOL_SOCKET && option_name == SO_SNDBUF) 143 { 144 if (option_len != sizeof(i)) 145 { 146 errno= EINVAL; 147 return -1; 148 } 149 i= *(const int *)option_value; 150 if (i > 32*1024) 151 { 152 /* The send buffer is limited to 32K at the moment. 153 */ 154 errno= ENOSYS; 155 return -1; 156 } 157 /* There is no way to reduce the send buffer, do we have to 158 * let this call fail for smaller buffers? 159 */ 160 return 0; 161 } 162 if (level == IPPROTO_TCP && option_name == TCP_NODELAY) 163 { 164 if (option_len != sizeof(i)) 165 { 166 errno= EINVAL; 167 return -1; 168 } 169 i= *(const int *)option_value; 170 if (i) 171 { 172 /* At the moment there is no way to turn on 173 * nodelay. 174 */ 175 errno= ENOSYS; 176 return -1; 177 } 178 return 0; 179 } 180 #if DEBUG 181 fprintf(stderr, "_tcp_setsocketopt: level %d, name %d\n", 182 level, option_name); 183 #endif 184 185 errno= ENOSYS; 186 return -1; 187 } 188 189 static int _udp_setsockopt(int sock, int level, int option_name, 190 const void *option_value, socklen_t option_len) 191 { 192 #if DEBUG 193 fprintf(stderr, "_udp_setsocketopt: level %d, name %d\n", 194 level, option_name); 195 #endif 196 197 errno= ENOSYS; 198 return -1; 199 } 200 201 202 static int _uds_setsockopt(int sock, int level, int option_name, 203 const void *option_value, socklen_t option_len) 204 { 205 int i; 206 size_t size; 207 208 if (level == SOL_SOCKET && option_name == SO_RCVBUF) 209 { 210 if (option_len != sizeof(size)) 211 { 212 errno= EINVAL; 213 return -1; 214 } 215 size= *(const size_t *)option_value; 216 return ioctl(sock, NWIOSUDSRCVBUF, &size); 217 } 218 219 if (level == SOL_SOCKET && option_name == SO_SNDBUF) 220 { 221 if (option_len != sizeof(size)) 222 { 223 errno= EINVAL; 224 return -1; 225 } 226 size= *(const size_t *)option_value; 227 return ioctl(sock, NWIOSUDSSNDBUF, &size); 228 } 229 230 if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 231 { 232 if (option_len != sizeof(i)) 233 { 234 errno= EINVAL; 235 return -1; 236 } 237 i= *(const int *)option_value; 238 if (!i) 239 { 240 /* At the moment there is no way to turn off 241 * reusing addresses. 242 */ 243 errno= ENOSYS; 244 return -1; 245 } 246 return 0; 247 } 248 249 if (level == SOL_SOCKET && option_name == SO_PASSCRED) 250 { 251 if (option_len != sizeof(i)) 252 { 253 errno= EINVAL; 254 return -1; 255 } 256 i= *(const int *)option_value; 257 if (!i) 258 { 259 /* credentials can always be received. */ 260 errno= ENOSYS; 261 return -1; 262 } 263 return 0; 264 } 265 266 #if DEBUG 267 fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n", 268 level, option_name); 269 #endif 270 271 errno= ENOSYS; 272 return -1; 273 } 274