1#!/bin/sh 2 3# 4# Copyright (c) 2014 EMC Corp. 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# Default unix domain socket limits causes hang: 30# 1001 880 871 0 52 0 5780 1524 keglimit D+ 0 0:00.35 /tmp/socketpair2 31 32# Test scenario by peter@ 33 34# Fixed in r269489. 35 36. ../default.cfg 37 38here=`pwd` 39cd /tmp 40sed '1,/^EOF/d' < $here/$0 > socketpair2.c 41mycc -o socketpair2 -Wall -Wextra -O2 socketpair2.c || exit 42rm -f socketpair2.c 43 44/tmp/socketpair2 > /dev/null 2>&1 45 46rm -f /tmp/socketpair2 47exit 0 48EOF 49/* 50 Peter Wemm <peter wemm org> 51 52 Some systems seem to base how much can be written to the pipe based 53 on the size of the socket receive buffer (read-side), while others 54 on the size of the socket send buffer (send-side). 55 56 This little hack tries to make an educated guess as to what is the 57 case on this particular system. 58*/ 59 60#include <sys/types.h> 61#include <sys/socket.h> 62 63#include <stdio.h> 64#include <stdlib.h> 65#include <string.h> 66#include <unistd.h> 67#include <fcntl.h> 68#include <errno.h> 69 70#ifndef MIN 71#define MIN(a,b) ((a) < (b) ? (a) : (b)) 72#endif /* !MIN */ 73 74#ifndef MAX 75#define MAX(a,b) ((a) > (b) ? (a) : (b)) 76#endif /* !MAX */ 77 78#if NEED_AF_LOCAL 79#define AF_LOCAL AF_UNIX 80#endif /* NEED_AF_LOCAL */ 81 82#define PACKETSIZE (1024) 83 84#define SEND_PIPE (0) 85#define RECV_PIPE (1) 86 87#define EXIT_SENDSIDE (1) 88#define EXIT_READSIDE (0) /* looking for readside - exit 0 */ 89#define EXIT_UNKNOWN (1) 90 91static void 92setsockets(const int doreverse, const size_t packetsize, 93 const int s, const int r, 94 size_t *sndbuf, size_t *sndbuf_set, 95 size_t *rcvbuf, size_t *rcvbuf_set); 96 97static size_t 98sendtest(const int s, const char *buf, const size_t buflen); 99 100int 101main(void) 102{ 103 size_t sent, packetcount, sndbuf, sndbuf_set, rcvbuf, rcvbuf_set; 104 char buf[PACKETSIZE - 64]; /* allow for some padding between messages. */ 105 int datapipev[2]; 106 107 if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, datapipev) != 0) { 108 perror("socketpair()"); 109 exit(EXIT_UNKNOWN); 110 } 111 112 setsockets(0, 113 PACKETSIZE, 114 datapipev[SEND_PIPE], 115 datapipev[RECV_PIPE], 116 &sndbuf, &sndbuf_set, 117 &rcvbuf, &rcvbuf_set); 118 119 packetcount = MIN(sndbuf, sndbuf_set) / PACKETSIZE; 120 fprintf(stderr, "Requested sndbuf to be %ld, is %ld. " 121 "Requested rcvbuf to be %ld, is %ld.\n" 122 "Calculated packetcount is %lu\n", 123 (long)sndbuf, (long)sndbuf_set, 124 (long)rcvbuf, (long)rcvbuf_set, (unsigned long)packetcount); 125 126 sent = sendtest(datapipev[SEND_PIPE], buf, sizeof(buf)); 127 if (sent >= (size_t)sndbuf) { 128 fprintf(stderr, "status determined by send-side\n"); 129 return EXIT_SENDSIDE; 130 } 131 132 /* 133 * Try the reverse. Perhaps this system wants a large rcvbuf rather than 134 * a large sndbuf. 135 */ 136 close(datapipev[SEND_PIPE]); 137 close(datapipev[RECV_PIPE]); 138 139 if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, datapipev) != 0) { 140 perror("socketpair()"); 141 exit(EXIT_UNKNOWN); 142 } 143 144 setsockets(1, 145 PACKETSIZE, 146 datapipev[SEND_PIPE], 147 datapipev[RECV_PIPE], 148 &sndbuf, &sndbuf_set, 149 &rcvbuf, &rcvbuf_set); 150 151 packetcount = MIN(rcvbuf, rcvbuf_set) / PACKETSIZE; 152 fprintf(stderr, "Requested sndbuf to be %ld, is %ld. " 153 "Requested rcvbuf to be %ld, is %ld.\n" 154 "Calculated packetcount is %lu\n", 155 (long)sndbuf, (long)sndbuf_set, 156 (long)rcvbuf, (long)rcvbuf_set, (unsigned long)packetcount); 157 158 sent = sendtest(datapipev[SEND_PIPE], buf, sizeof(buf)); 159 if (sent >= (size_t)rcvbuf) { 160 fprintf(stderr, "status determined by read-side\n"); 161 return EXIT_READSIDE; 162 } 163 164 fprintf(stderr, "status is unknown\n"); 165 return EXIT_UNKNOWN; 166} 167 168static void 169setsockets(doreverse, packetsize, s, r, sndbuf, sndbuf_set, rcvbuf, rcvbuf_set) 170 const int doreverse; 171 const size_t packetsize; 172 const int s; 173 const int r; 174 size_t *sndbuf, *sndbuf_set; 175 size_t *rcvbuf, *rcvbuf_set; 176{ 177 socklen_t len; 178 int p; 179 180 if ((p = fcntl(s, F_GETFL, 0)) == -1 181 || fcntl(s, F_SETFL, p | O_NONBLOCK) == -1 182 || fcntl(r, F_SETFL, p | O_NONBLOCK) == -1) { 183 perror("fcntl(F_SETFL/F_GETFL, O_NONBLOCK) failed"); 184 exit(EXIT_UNKNOWN); 185 } 186 187 len = sizeof(*sndbuf_set); 188 189 if (doreverse) { 190 *sndbuf = packetsize; 191 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, sndbuf, sizeof(*sndbuf)) != 0) { 192 perror("setsockopt(SO_SNDBUF)"); 193 exit(EXIT_UNKNOWN); 194 } 195 196 if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, sndbuf_set, &len) != 0) { 197 perror("getsockopt(SO_SNDBUF)"); 198 exit(EXIT_UNKNOWN); 199 } 200 201 *rcvbuf = *sndbuf_set * 10; 202 if (setsockopt(r, SOL_SOCKET, SO_RCVBUF, rcvbuf, sizeof(*rcvbuf)) != 0) { 203 perror("setsockopt(SO_RCVBUF)"); 204 exit(EXIT_UNKNOWN); 205 } 206 } 207 else { 208 *rcvbuf = packetsize; 209 if (setsockopt(r, SOL_SOCKET, SO_RCVBUF, rcvbuf, sizeof(*rcvbuf)) != 0) { 210 perror("setsockopt(SO_RCVBUF)"); 211 exit(EXIT_UNKNOWN); 212 } 213 214 if (getsockopt(r, SOL_SOCKET, SO_RCVBUF, rcvbuf_set, &len) != 0) { 215 perror("getsockopt(SO_RCVBUF)"); 216 exit(EXIT_UNKNOWN); 217 } 218 219 *sndbuf = *rcvbuf_set * 10; 220 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, sndbuf, sizeof(*sndbuf)) != 0) { 221 perror("setsockopt(SO_SNDBUF)"); 222 exit(EXIT_UNKNOWN); 223 } 224 } 225 226 if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, sndbuf_set, &len) != 0 227 || getsockopt(r, SOL_SOCKET, SO_RCVBUF, rcvbuf_set, &len) != 0) { 228 perror("getsockopt(SO_SNDBUF/SO_RCVBUF)"); 229 exit(EXIT_UNKNOWN); 230 } 231 232 fprintf(stderr, "sndbuf is %lu, rcvbuf is %lu\n", 233 (unsigned long)*sndbuf_set, (unsigned long)*rcvbuf_set); 234 235 if (doreverse) { 236 if (*rcvbuf_set < *rcvbuf) { 237 fprintf(stderr, "failed to set rcvbuf to %lu. Is %lu\n", 238 (unsigned long)*rcvbuf, (unsigned long)*rcvbuf_set); 239 exit(EXIT_UNKNOWN); 240 } 241 } 242 else { 243 if (*sndbuf_set < *sndbuf) { 244 fprintf(stderr, "failed to set sndbuf to %lu (is %lu)\n", 245 (unsigned long)*sndbuf, (unsigned long)*sndbuf_set); 246 exit(EXIT_UNKNOWN); 247 } 248 } 249} 250 251static size_t 252sendtest(s, buf, buflen) 253 const int s; 254 const char *buf; 255 const size_t buflen; 256{ 257 ssize_t rc; 258 int i; 259 260 i = 1; 261 errno = 0; 262 while (errno == 0) { 263 if ((rc = sendto(s, buf, buflen, 0, NULL, 0)) != (ssize_t)buflen) 264 fprintf(stderr, "sendto(2) failed on iteration %d, sent %ld/%lu. " 265 "Total bytes sent: %lu. Error on last packet: %s\n", 266 i, (long)rc, (unsigned long)buflen, 267 (unsigned long)(i * buflen + MAX(rc, 0)), strerror(errno)); 268 else 269 ++i; 270 } 271 272 return (size_t)(i * buflen + MAX(rc, 0)); 273} 274