xref: /aosp_15_r20/external/ublksrv/nbd/cliserv.c (revision 94c4a1e103eb1715230460aab379dff275992c20)
1*94c4a1e1SFrank Piva // SPDX-License-Identifier: GPL-2.0
2*94c4a1e1SFrank Piva #include <config.h>
3*94c4a1e1SFrank Piva #include <fcntl.h>
4*94c4a1e1SFrank Piva #include <stdio.h>
5*94c4a1e1SFrank Piva #include <syslog.h>
6*94c4a1e1SFrank Piva #include <unistd.h>
7*94c4a1e1SFrank Piva #include <sys/types.h>
8*94c4a1e1SFrank Piva #include <sys/socket.h>
9*94c4a1e1SFrank Piva 
10*94c4a1e1SFrank Piva #include "cliserv.h"
11*94c4a1e1SFrank Piva #include "nbd-debug.h"
12*94c4a1e1SFrank Piva 
13*94c4a1e1SFrank Piva const u64 cliserv_magic = 0x00420281861253LL;
14*94c4a1e1SFrank Piva const u64 opts_magic = 0x49484156454F5054LL;
15*94c4a1e1SFrank Piva const u64 rep_magic = 0x3e889045565a9LL;
16*94c4a1e1SFrank Piva 
17*94c4a1e1SFrank Piva /**
18*94c4a1e1SFrank Piva  * Set a socket to blocking or non-blocking
19*94c4a1e1SFrank Piva  *
20*94c4a1e1SFrank Piva  * @param fd The socket's FD
21*94c4a1e1SFrank Piva  * @param nb nonzero to set to non-blocking, else 0 to set to blocking
22*94c4a1e1SFrank Piva  * @return 0 - OK, -1 failed
23*94c4a1e1SFrank Piva  */
set_nonblocking(int fd,int nb)24*94c4a1e1SFrank Piva int set_nonblocking(int fd, int nb) {
25*94c4a1e1SFrank Piva 	int sf = fcntl (fd, F_GETFL, 0);
26*94c4a1e1SFrank Piva 	if (sf == -1)
27*94c4a1e1SFrank Piva 		return -1;
28*94c4a1e1SFrank Piva 	return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK));
29*94c4a1e1SFrank Piva }
30*94c4a1e1SFrank Piva 
31*94c4a1e1SFrank Piva 
setmysockopt(int sock)32*94c4a1e1SFrank Piva void setmysockopt(int sock) {
33*94c4a1e1SFrank Piva 	int size = 1;
34*94c4a1e1SFrank Piva #if 0
35*94c4a1e1SFrank Piva 	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0)
36*94c4a1e1SFrank Piva 		 INFO("(no sockopt/1: %m)");
37*94c4a1e1SFrank Piva #endif
38*94c4a1e1SFrank Piva #ifdef	IPPROTO_TCP
39*94c4a1e1SFrank Piva 	size = 1;
40*94c4a1e1SFrank Piva 	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &size, sizeof(int)) < 0)
41*94c4a1e1SFrank Piva 		 INFO("(no sockopt/2: %m)");
42*94c4a1e1SFrank Piva #endif
43*94c4a1e1SFrank Piva #if 0
44*94c4a1e1SFrank Piva 	size = 1024;
45*94c4a1e1SFrank Piva 	if (setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &size, sizeof(int)) < 0)
46*94c4a1e1SFrank Piva 		 INFO("(no sockopt/3: %m)");
47*94c4a1e1SFrank Piva #endif
48*94c4a1e1SFrank Piva }
49*94c4a1e1SFrank Piva 
err_nonfatal(const char * s)50*94c4a1e1SFrank Piva void err_nonfatal(const char *s) {
51*94c4a1e1SFrank Piva 	char s1[150], *s2;
52*94c4a1e1SFrank Piva #pragma GCC diagnostic push
53*94c4a1e1SFrank Piva #pragma GCC diagnostic ignored "-Wstringop-truncation"
54*94c4a1e1SFrank Piva 	strncpy(s1, s, sizeof(s1));
55*94c4a1e1SFrank Piva #pragma GCC diagnostic pop
56*94c4a1e1SFrank Piva 	if ((s2 = strstr(s, "%m"))) {
57*94c4a1e1SFrank Piva 		strncpy(s1 + (s2 - s), strerror(errno), sizeof(s1) - (s2 - s));
58*94c4a1e1SFrank Piva 		s2 += 2;
59*94c4a1e1SFrank Piva 		strncpy(s1 + strlen(s1), s2, sizeof(s1) - strlen(s1));
60*94c4a1e1SFrank Piva 	}
61*94c4a1e1SFrank Piva #ifndef	sun
62*94c4a1e1SFrank Piva 	/* Solaris doesn't have %h in syslog */
63*94c4a1e1SFrank Piva 	else if ((s2 = strstr(s, "%h"))) {
64*94c4a1e1SFrank Piva 		strncpy(s1 + (s2 - s), hstrerror(h_errno), sizeof(s1) - (s2 - s));
65*94c4a1e1SFrank Piva 		s2 += 2;
66*94c4a1e1SFrank Piva 		strncpy(s1 + strlen(s1), s2, sizeof(s1) - strlen(s1));
67*94c4a1e1SFrank Piva 	}
68*94c4a1e1SFrank Piva #endif
69*94c4a1e1SFrank Piva 
70*94c4a1e1SFrank Piva 	s1[sizeof(s1)-1] = '\0';
71*94c4a1e1SFrank Piva #ifdef ISSERVER
72*94c4a1e1SFrank Piva 	syslog(LOG_ERR, "%s", s1);
73*94c4a1e1SFrank Piva 	syslog(LOG_ERR, "Exiting.");
74*94c4a1e1SFrank Piva #endif
75*94c4a1e1SFrank Piva 	fprintf(stderr, "Error: %s\n", s1);
76*94c4a1e1SFrank Piva }
77*94c4a1e1SFrank Piva 
err(const char * s)78*94c4a1e1SFrank Piva void err(const char *s) {
79*94c4a1e1SFrank Piva 	err_nonfatal(s);
80*94c4a1e1SFrank Piva 	fprintf(stderr, "Exiting.\n");
81*94c4a1e1SFrank Piva 	exit(EXIT_FAILURE);
82*94c4a1e1SFrank Piva }
83*94c4a1e1SFrank Piva 
logging(const char * name)84*94c4a1e1SFrank Piva void logging(const char* name) {
85*94c4a1e1SFrank Piva #ifdef ISSERVER
86*94c4a1e1SFrank Piva 	openlog(name, LOG_PID, LOG_DAEMON);
87*94c4a1e1SFrank Piva #endif
88*94c4a1e1SFrank Piva 	setvbuf(stdout, NULL, _IONBF, 0);
89*94c4a1e1SFrank Piva 	setvbuf(stderr, NULL, _IONBF, 0);
90*94c4a1e1SFrank Piva }
91*94c4a1e1SFrank Piva 
92*94c4a1e1SFrank Piva #ifndef ntohll
93*94c4a1e1SFrank Piva #ifdef WORDS_BIGENDIAN
ntohll(uint64_t a)94*94c4a1e1SFrank Piva uint64_t ntohll(uint64_t a) {
95*94c4a1e1SFrank Piva 	return a;
96*94c4a1e1SFrank Piva }
97*94c4a1e1SFrank Piva #else
ntohll(uint64_t a)98*94c4a1e1SFrank Piva uint64_t ntohll(uint64_t a) {
99*94c4a1e1SFrank Piva 	u32 lo = a & 0xffffffff;
100*94c4a1e1SFrank Piva 	u32 hi = a >> 32U;
101*94c4a1e1SFrank Piva 	lo = ntohl(lo);
102*94c4a1e1SFrank Piva 	hi = ntohl(hi);
103*94c4a1e1SFrank Piva 	return ((uint64_t) lo) << 32U | hi;
104*94c4a1e1SFrank Piva }
105*94c4a1e1SFrank Piva #endif
106*94c4a1e1SFrank Piva #endif
107*94c4a1e1SFrank Piva 
108*94c4a1e1SFrank Piva /**
109*94c4a1e1SFrank Piva  * Read data from a file descriptor into a buffer
110*94c4a1e1SFrank Piva  *
111*94c4a1e1SFrank Piva  * @param f a file descriptor
112*94c4a1e1SFrank Piva  * @param buf a buffer
113*94c4a1e1SFrank Piva  * @param len the number of bytes to be read
114*94c4a1e1SFrank Piva  * @return 0 on completion, or -1 on failure
115*94c4a1e1SFrank Piva  **/
readit(int f,void * buf,size_t len)116*94c4a1e1SFrank Piva int readit(int f, void *buf, size_t len) {
117*94c4a1e1SFrank Piva 	ssize_t res;
118*94c4a1e1SFrank Piva 	while (len > 0) {
119*94c4a1e1SFrank Piva 		NBD_DEBUG("*");
120*94c4a1e1SFrank Piva 		res = read(f, buf, len);
121*94c4a1e1SFrank Piva 		if (res > 0) {
122*94c4a1e1SFrank Piva 			len -= res;
123*94c4a1e1SFrank Piva 			buf += res;
124*94c4a1e1SFrank Piva 		} else if (res < 0) {
125*94c4a1e1SFrank Piva 			if(errno != EAGAIN) {
126*94c4a1e1SFrank Piva 				err_nonfatal("Read failed: %m");
127*94c4a1e1SFrank Piva 				return -1;
128*94c4a1e1SFrank Piva 			}
129*94c4a1e1SFrank Piva 		} else {
130*94c4a1e1SFrank Piva 			errno = ECONNRESET;
131*94c4a1e1SFrank Piva 			return -1;
132*94c4a1e1SFrank Piva 		}
133*94c4a1e1SFrank Piva 	}
134*94c4a1e1SFrank Piva 	return 0;
135*94c4a1e1SFrank Piva }
136*94c4a1e1SFrank Piva 
137*94c4a1e1SFrank Piva /**
138*94c4a1e1SFrank Piva  * Write data from a buffer into a filedescriptor
139*94c4a1e1SFrank Piva  *
140*94c4a1e1SFrank Piva  * @param f a file descriptor
141*94c4a1e1SFrank Piva  * @param buf a buffer containing data
142*94c4a1e1SFrank Piva  * @param len the number of bytes to be written
143*94c4a1e1SFrank Piva  * @return 0 on success, or -1 if the socket was closed
144*94c4a1e1SFrank Piva  **/
writeit(int f,void * buf,size_t len)145*94c4a1e1SFrank Piva int writeit(int f, void *buf, size_t len) {
146*94c4a1e1SFrank Piva 	ssize_t res;
147*94c4a1e1SFrank Piva 	while (len > 0) {
148*94c4a1e1SFrank Piva 		NBD_DEBUG("+");
149*94c4a1e1SFrank Piva 		if ((res = write(f, buf, len)) <= 0) {
150*94c4a1e1SFrank Piva 			switch(errno) {
151*94c4a1e1SFrank Piva 				case EAGAIN:
152*94c4a1e1SFrank Piva 					break;
153*94c4a1e1SFrank Piva 				default:
154*94c4a1e1SFrank Piva 					err_nonfatal("Send failed: %m");
155*94c4a1e1SFrank Piva 					return -1;
156*94c4a1e1SFrank Piva 			}
157*94c4a1e1SFrank Piva 		}
158*94c4a1e1SFrank Piva 		len -= res;
159*94c4a1e1SFrank Piva 		buf += res;
160*94c4a1e1SFrank Piva 	}
161*94c4a1e1SFrank Piva 	return 0;
162*94c4a1e1SFrank Piva }
163