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