Whamcloud - gitweb
LU-10391 lnet: change various function to return pointer
[fs/lustre-release.git] / lnet / lnet / lib-socket.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2015, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32 #define DEBUG_SUBSYSTEM S_LNET
33
34 #include <linux/if.h>
35 #include <linux/in.h>
36 #include <linux/net.h>
37 #include <linux/file.h>
38 #include <linux/pagemap.h>
39 /* For sys_open & sys_close */
40 #include <linux/syscalls.h>
41 #include <net/sock.h>
42
43 #include <libcfs/libcfs.h>
44 #include <lnet/lib-lnet.h>
45
46 /*
47  * kernel 5.1: commit 7f1bc6e95d7840d4305595b3e4025cddda88cee5
48  * Y2038 64-bit time.
49  *  SO_TIMESTAMP, SO_TIMESTAMPNS and SO_TIMESTAMPING options, the
50  *  way they are currently defined, are not y2038 safe.
51  *  Subsequent patches in the series add new y2038 safe versions
52  *  of these options which provide 64 bit timestamps on all
53  *  architectures uniformly.
54  *  Hence, rename existing options with OLD tag suffixes.
55  *
56  * NOTE: When updating to timespec64 change change these to '_NEW'.
57  *
58  */
59 #ifndef SO_SNDTIMEO
60 #define SO_SNDTIMEO SO_SNDTIMEO_OLD
61 #endif
62
63 #ifndef SO_RCVTIMEO
64 #define SO_RCVTIMEO SO_RCVTIMEO_OLD
65 #endif
66
67 int
68 lnet_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
69 {
70         int             rc;
71         long            jiffies_left = cfs_time_seconds(timeout);
72         unsigned long   then;
73         struct timeval  tv;
74
75         LASSERT(nob > 0);
76         /* Caller may pass a zero timeout if she thinks the socket buffer is
77          * empty enough to take the whole message immediately */
78
79         for (;;) {
80                 struct kvec  iov = {
81                         .iov_base = buffer,
82                         .iov_len  = nob
83                 };
84                 struct msghdr msg = {
85                         .msg_flags      = (timeout == 0) ? MSG_DONTWAIT : 0
86                 };
87
88                 if (timeout != 0) {
89                         /* Set send timeout to remaining time */
90                         jiffies_to_timeval(jiffies_left, &tv);
91                         rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
92                                                (char *)&tv, sizeof(tv));
93                         if (rc != 0) {
94                                 CERROR("Can't set socket send timeout "
95                                        "%ld.%06d: %d\n",
96                                        (long)tv.tv_sec, (int)tv.tv_usec, rc);
97                                 return rc;
98                         }
99                 }
100
101                 then = jiffies;
102                 rc = kernel_sendmsg(sock, &msg, &iov, 1, nob);
103                 jiffies_left -= jiffies - then;
104
105                 if (rc == nob)
106                         return 0;
107
108                 if (rc < 0)
109                         return rc;
110
111                 if (rc == 0) {
112                         CERROR("Unexpected zero rc\n");
113                         return -ECONNABORTED;
114                 }
115
116                 if (jiffies_left <= 0)
117                         return -EAGAIN;
118
119                 buffer = ((char *)buffer) + rc;
120                 nob -= rc;
121         }
122         return 0;
123 }
124 EXPORT_SYMBOL(lnet_sock_write);
125
126 int
127 lnet_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
128 {
129         int             rc;
130         long            jiffies_left = cfs_time_seconds(timeout);
131         unsigned long   then;
132         struct timeval  tv;
133
134         LASSERT(nob > 0);
135         LASSERT(jiffies_left > 0);
136
137         for (;;) {
138                 struct kvec  iov = {
139                         .iov_base = buffer,
140                         .iov_len  = nob
141                 };
142                 struct msghdr msg = {
143                         .msg_flags      = 0
144                 };
145
146                 /* Set receive timeout to remaining time */
147                 jiffies_to_timeval(jiffies_left, &tv);
148                 rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
149                                        (char *)&tv, sizeof(tv));
150                 if (rc != 0) {
151                         CERROR("Can't set socket recv timeout %ld.%06d: %d\n",
152                                (long)tv.tv_sec, (int)tv.tv_usec, rc);
153                         return rc;
154                 }
155
156                 then = jiffies;
157                 rc = kernel_recvmsg(sock, &msg, &iov, 1, nob, 0);
158                 jiffies_left -= jiffies - then;
159
160                 if (rc < 0)
161                         return rc;
162
163                 if (rc == 0)
164                         return -ECONNRESET;
165
166                 buffer = ((char *)buffer) + rc;
167                 nob -= rc;
168
169                 if (nob == 0)
170                         return 0;
171
172                 if (jiffies_left <= 0)
173                         return -ETIMEDOUT;
174         }
175 }
176 EXPORT_SYMBOL(lnet_sock_read);
177
178 static struct socket *
179 lnet_sock_create(__u32 local_ip, int local_port, struct net *ns)
180 {
181         struct sockaddr_in  locaddr;
182         struct socket      *sock;
183         int                 rc;
184         int                 option;
185
186 #ifdef HAVE_SOCK_CREATE_KERN_USE_NET
187         rc = sock_create_kern(ns, PF_INET, SOCK_STREAM, 0, &sock);
188 #else
189         rc = sock_create_kern(PF_INET, SOCK_STREAM, 0, &sock);
190 #endif
191         if (rc) {
192                 CERROR("Can't create socket: %d\n", rc);
193                 return ERR_PTR(rc);
194         }
195
196         option = 1;
197         rc = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
198                                (char *)&option, sizeof(option));
199         if (rc) {
200                 CERROR("Can't set SO_REUSEADDR for socket: %d\n", rc);
201                 goto failed;
202         }
203
204         if (local_ip != 0 || local_port != 0) {
205                 memset(&locaddr, 0, sizeof(locaddr));
206                 locaddr.sin_family = AF_INET;
207                 locaddr.sin_port = htons(local_port);
208                 locaddr.sin_addr.s_addr = (local_ip == 0) ?
209                                           INADDR_ANY : htonl(local_ip);
210
211                 rc = kernel_bind(sock, (struct sockaddr *)&locaddr,
212                                  sizeof(locaddr));
213                 if (rc == -EADDRINUSE) {
214                         CDEBUG(D_NET, "Port %d already in use\n", local_port);
215                         goto failed;
216                 }
217                 if (rc != 0) {
218                         CERROR("Error trying to bind to port %d: %d\n",
219                                local_port, rc);
220                         goto failed;
221                 }
222         }
223         return sock;
224
225 failed:
226         sock_release(sock);
227         return ERR_PTR(rc);
228 }
229
230 int
231 lnet_sock_setbuf(struct socket *sock, int txbufsize, int rxbufsize)
232 {
233         int                 option;
234         int                 rc;
235
236         if (txbufsize != 0) {
237                 option = txbufsize;
238                 rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
239                                        (char *)&option, sizeof(option));
240                 if (rc != 0) {
241                         CERROR("Can't set send buffer %d: %d\n",
242                                 option, rc);
243                         return rc;
244                 }
245         }
246
247         if (rxbufsize != 0) {
248                 option = rxbufsize;
249                 rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
250                                        (char *)&option, sizeof(option));
251                 if (rc != 0) {
252                         CERROR("Can't set receive buffer %d: %d\n",
253                                 option, rc);
254                         return rc;
255                 }
256         }
257         return 0;
258 }
259 EXPORT_SYMBOL(lnet_sock_setbuf);
260
261 int
262 lnet_sock_getaddr(struct socket *sock, bool remote, __u32 *ip, int *port)
263 {
264         struct sockaddr_in sin;
265         int rc;
266 #ifndef HAVE_KERN_SOCK_GETNAME_2ARGS
267         int len = sizeof(sin);
268 #endif
269
270         if (remote)
271                 rc = lnet_kernel_getpeername(sock,
272                                              (struct sockaddr *)&sin, &len);
273         else
274                 rc = lnet_kernel_getsockname(sock,
275                                              (struct sockaddr *)&sin, &len);
276         if (rc < 0) {
277                 CERROR("Error %d getting sock %s IP/port\n",
278                         rc, remote ? "peer" : "local");
279                 return rc;
280         }
281
282         if (ip != NULL)
283                 *ip = ntohl(sin.sin_addr.s_addr);
284
285         if (port != NULL)
286                 *port = ntohs(sin.sin_port);
287
288         return 0;
289 }
290 EXPORT_SYMBOL(lnet_sock_getaddr);
291
292 int
293 lnet_sock_getbuf(struct socket *sock, int *txbufsize, int *rxbufsize)
294 {
295         if (txbufsize != NULL)
296                 *txbufsize = sock->sk->sk_sndbuf;
297
298         if (rxbufsize != NULL)
299                 *rxbufsize = sock->sk->sk_rcvbuf;
300
301         return 0;
302 }
303 EXPORT_SYMBOL(lnet_sock_getbuf);
304
305 struct socket *
306 lnet_sock_listen(__u32 local_ip, int local_port, int backlog, struct net *ns)
307 {
308         struct socket *sock;
309         int rc;
310
311         sock = lnet_sock_create(local_ip, local_port, ns);
312         if (IS_ERR(sock)) {
313                 rc = PTR_ERR(sock);
314                 if (rc == -EADDRINUSE)
315                         CERROR("Can't create socket: port %d already in use\n",
316                                local_port);
317                 return ERR_PTR(rc);
318         }
319
320         rc = kernel_listen(sock, backlog);
321         if (rc == 0)
322                 return sock;
323
324         CERROR("Can't set listen backlog %d: %d\n", backlog, rc);
325         sock_release(sock);
326         return ERR_PTR(rc);
327 }
328
329 struct socket *
330 lnet_sock_connect(__u32 local_ip, int local_port,
331                   __u32 peer_ip, int peer_port,
332                   struct net *ns)
333 {
334         struct socket *sock;
335         struct sockaddr_in srvaddr;
336         int rc;
337
338         sock = lnet_sock_create(local_ip, local_port, ns);
339         if (IS_ERR(sock))
340                 return sock;
341
342         memset(&srvaddr, 0, sizeof(srvaddr));
343         srvaddr.sin_family = AF_INET;
344         srvaddr.sin_port = htons(peer_port);
345         srvaddr.sin_addr.s_addr = htonl(peer_ip);
346
347         rc = kernel_connect(sock, (struct sockaddr *)&srvaddr,
348                             sizeof(srvaddr), 0);
349         if (rc == 0)
350                 return sock;
351
352         /* EADDRNOTAVAIL probably means we're already connected to the same
353          * peer/port on the same local port on a differently typed
354          * connection.  Let our caller retry with a different local
355          * port... */
356
357         CDEBUG_LIMIT(rc == -EADDRNOTAVAIL ? D_NET : D_NETERROR,
358                      "Error %d connecting %pI4h/%d -> %pI4h/%d\n", rc,
359                      &local_ip, local_port, &peer_ip, peer_port);
360
361         sock_release(sock);
362         return ERR_PTR(rc);
363 }