1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2022 Huawei Device Co., Ltd.
4 *
5 * Description: Demo example of NewIP udp client.
6 *
7 * Author: Yang Yanjun <yangyanjun@huawei.com>
8 *
9 * Data: 2022-09-06
10 */
11#include <stdio.h>
12#include <unistd.h>
13#include <string.h>
14#include <arpa/inet.h>
15#include <sys/socket.h>
16#include <sys/time.h>
17
18#define __USE_GNU
19#include <sched.h>
20#include <pthread.h>
21
22#include "nip_uapi.h"
23#include "nip_lib.h"
24#include "newip_route.h"
25
26int _sendto(int cfd, struct sockaddr_nin *si_server, int pkt_num)
27{
28	char buf[BUFLEN] = {0};
29	struct timeval sys_time;
30	socklen_t slen = sizeof(struct sockaddr_nin);
31	int ret;
32
33	gettimeofday(&sys_time, NULL);
34	ret = sprintf(buf, "%ld %6ld NIP_UDP # %6d", sys_time.tv_sec, sys_time.tv_usec, pkt_num);
35	if (ret < 0) {
36		printf("sprintf failed");
37		return -1;
38	}
39	if (sendto(cfd, buf, BUFLEN, 0, (struct sockaddr *)si_server, slen) < 0) {
40		printf("client sendto fail, pkt_num=%d", pkt_num);
41		return -1;
42	}
43
44	return 0;
45}
46
47int _recvfrom(int cfd, struct sockaddr_nin *si_server, int pkt_num, int *success)
48{
49	char buf[BUFLEN] = {0};
50	fd_set readfds;
51	int tmp;
52	struct timeval tv;
53	socklen_t slen = sizeof(struct sockaddr_nin);
54
55	FD_ZERO(&readfds);
56	FD_SET(cfd, &readfds);
57	tv.tv_sec = TIMEOUT_SEC;
58	tv.tv_usec = 0;
59	if (select(cfd + 1, &readfds, NULL, NULL, &tv) < 0) {
60		printf("client select fail, pkt_num=%d", pkt_num);
61		return -1;
62	}
63
64	if (FD_ISSET(cfd, &readfds)) {
65		int ret;
66		int no = 0;
67
68		ret = recvfrom(cfd, buf, BUFLEN, 0, (struct sockaddr *)si_server, &slen);
69		if (ret > 0) {
70			*success += 1;
71			ret = sscanf(buf, "%d %d NIP_UDP # %d", &tmp, &tmp, &no);
72			if (ret)
73				printf("Received --%s sock %d success:%6d/%6d/no=%6d\n",
74				       buf, cfd, *success, pkt_num + 1, no);
75		} else {
76			printf("client recvfrom fail, ret=%d\n", ret);
77			return -1;
78		}
79	}
80
81	return 0;
82}
83
84void *send_recv(void *args)
85{
86	int success = 0;
87	int cfd = ((struct thread_args *)args)->cfd;
88	struct sockaddr_nin si_server = ((struct thread_args *)args)->si_server;
89
90	for (int i = 0; i < PKTCNT; i++) {
91		if (_sendto(cfd, &si_server, i) != 0)
92			goto END;
93
94		if (_recvfrom(cfd, &si_server, i, &success) != 0)
95			goto END;
96
97		usleep(SLEEP_US);
98	}
99
100END:	return NULL;
101}
102
103int main(int argc, char **argv)
104{
105	pthread_t th;
106	int cfd;
107	struct thread_args th_args;
108	struct sockaddr_nin si_server;
109
110	cfd = socket(AF_NINET, SOCK_DGRAM, IPPROTO_UDP);
111	if (cfd < 0) {
112		perror("socket");
113		return -1;
114	}
115
116	memset((char *)&si_server, 0, sizeof(si_server));
117	si_server.sin_family = AF_NINET;
118	si_server.sin_port = htons(UDP_SERVER_PORT);
119	// 2-byte address of the server: 0xDE00
120	si_server.sin_addr.NIP_ADDR_FIELD8[INDEX_0] = 0xDE;
121	si_server.sin_addr.NIP_ADDR_FIELD8[INDEX_1] = 0x00;
122	si_server.sin_addr.bitlen = NIP_ADDR_BIT_LEN_16; // 2-byte: 16bit
123
124	th_args.si_server = si_server;
125	th_args.si_server.sin_port = htons(UDP_SERVER_PORT);
126	th_args.cfd = cfd;
127	pthread_create(&th, NULL, send_recv, &th_args);
128	/* Wait for the thread to end and synchronize operations between threads */
129	pthread_join(th, NULL);
130	close(cfd);
131	return 0;
132}
133
134