1// SPDX-License-Identifier: GPL-2.0
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <arpa/inet.h>
8
9int main(int argc, char *argv[])
10{
11	struct sockaddr_in saddr = {}, daddr = {};
12	int sd, ret, len = sizeof(daddr);
13	struct timeval tv = {25, 0};
14	char buf[] = "hello";
15
16	if (argc != 6 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) {
17		printf("%s <server|client> <LOCAL_IP> <LOCAL_PORT> <REMOTE_IP> <REMOTE_PORT>\n",
18		       argv[0]);
19		return -1;
20	}
21
22	sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
23	if (sd < 0) {
24		printf("Failed to create sd\n");
25		return -1;
26	}
27
28	saddr.sin_family = AF_INET;
29	saddr.sin_addr.s_addr = inet_addr(argv[2]);
30	saddr.sin_port = htons(atoi(argv[3]));
31
32	ret = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr));
33	if (ret < 0) {
34		printf("Failed to bind to address\n");
35		goto out;
36	}
37
38	ret = listen(sd, 5);
39	if (ret < 0) {
40		printf("Failed to listen on port\n");
41		goto out;
42	}
43
44	daddr.sin_family = AF_INET;
45	daddr.sin_addr.s_addr = inet_addr(argv[4]);
46	daddr.sin_port = htons(atoi(argv[5]));
47
48	/* make test shorter than 25s */
49	ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
50	if (ret < 0) {
51		printf("Failed to setsockopt SO_RCVTIMEO\n");
52		goto out;
53	}
54
55	if (!strcmp(argv[1], "server")) {
56		sleep(1); /* wait a bit for client's INIT */
57		ret = connect(sd, (struct sockaddr *)&daddr, len);
58		if (ret < 0) {
59			printf("Failed to connect to peer\n");
60			goto out;
61		}
62		ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len);
63		if (ret < 0) {
64			printf("Failed to recv msg %d\n", ret);
65			goto out;
66		}
67		ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len);
68		if (ret < 0) {
69			printf("Failed to send msg %d\n", ret);
70			goto out;
71		}
72		printf("Server: sent! %d\n", ret);
73	}
74
75	if (!strcmp(argv[1], "client")) {
76		usleep(300000); /* wait a bit for server's listening */
77		ret = connect(sd, (struct sockaddr *)&daddr, len);
78		if (ret < 0) {
79			printf("Failed to connect to peer\n");
80			goto out;
81		}
82		sleep(1); /* wait a bit for server's delayed INIT_ACK to reproduce the issue */
83		ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len);
84		if (ret < 0) {
85			printf("Failed to send msg %d\n", ret);
86			goto out;
87		}
88		ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len);
89		if (ret < 0) {
90			printf("Failed to recv msg %d\n", ret);
91			goto out;
92		}
93		printf("Client: rcvd! %d\n", ret);
94	}
95	ret = 0;
96out:
97	close(sd);
98	return ret;
99}
100