blob: e62720826d30575819ee5f7c1eb22369084ae0d0 [file] [log] [blame]
Ming Lei7b9e0592023-01-19 10:48:50 +00001// 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
13const u64 cliserv_magic = 0x00420281861253LL;
14const u64 opts_magic = 0x49484156454F5054LL;
15const 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 */
24int 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
32void 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
50void err_nonfatal(const char *s) {
51 char s1[150], *s2;
Ming Leibeb37d32023-06-18 14:37:54 +000052#pragma GCC diagnostic push
53#pragma GCC diagnostic ignored "-Wstringop-truncation"
Ming Lei7b9e0592023-01-19 10:48:50 +000054 strncpy(s1, s, sizeof(s1));
Ming Leibeb37d32023-06-18 14:37:54 +000055#pragma GCC diagnostic pop
Ming Lei7b9e0592023-01-19 10:48:50 +000056 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
78void err(const char *s) {
79 err_nonfatal(s);
80 fprintf(stderr, "Exiting.\n");
81 exit(EXIT_FAILURE);
82}
83
84void 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
94uint64_t ntohll(uint64_t a) {
95 return a;
96}
97#else
98uint64_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 **/
116int 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 **/
145int 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}