Merge branch 'master' into issues-199
commit
ebd98bf966
|
@ -0,0 +1,36 @@
|
|||
Changes since 1.11.0
|
||||
|
||||
Add a new mkdir2 command that also takes a mode argument.
|
||||
|
||||
Add support for RPC timeouts for the async interface.
|
||||
|
||||
Fix NULL pointer read in nfs_link()
|
||||
|
||||
Clamp read/write size for servers (Ganesha) that offer very large io sizes
|
||||
instead of failing to connect to the export
|
||||
|
||||
Tell the server to commit all data to stable storage when we close files.
|
||||
|
||||
Double free fix: don't call rpc_free_pdu() after rpc_queue_pdu() failure
|
||||
|
||||
bootstrap updates
|
||||
|
||||
Build fixes for Mingw and Cygwin
|
||||
|
||||
Update README to document two new Windows builds
|
||||
|
||||
Fix for memory leak in rpc_allocate_*()
|
||||
|
||||
Use SOCK_CLOEXEC for the sockets
|
||||
|
||||
Make rpc_set{g|u}id() public
|
||||
|
||||
Performance optimization: socket: Batch pdu read in rpc_read_from_socket
|
||||
|
||||
Low level support for NFSv4 and some examples
|
||||
|
||||
Support for building RPC servers
|
||||
|
||||
README updates
|
||||
|
||||
Fixes to build nfs-ls and nfs-cp on win32
|
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS = doc mount nfs nlm nsm portmap rquota lib include $(MAYBE_UTILS) . $(MAYBE_EXAMPLES)
|
||||
SUBDIRS = doc mount nfs nfs4 nlm nsm portmap rquota lib include $(MAYBE_UTILS) . $(MAYBE_EXAMPLES)
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
|
35
README
35
README
|
@ -23,9 +23,21 @@ stat(), read(), ...
|
|||
|
||||
examples/nfsclient-sync.c provides examples on how to use this API
|
||||
|
||||
NFSv4:
|
||||
======
|
||||
NFSv4 is supported but only for the RAW ASYNC interface.
|
||||
Examples/nfsv4-cat.c is a "simple" example to illustrate how to use
|
||||
NFSv4 to connect to a server and read a file off the server.
|
||||
|
||||
SERVER SUPPORT:
|
||||
===============
|
||||
Libnfs supports building RPC servers.
|
||||
Examples/portmapper-server.c is a small "portmapper" example written using
|
||||
libnfs.
|
||||
|
||||
URL-FORMAT:
|
||||
===========
|
||||
Libnfs uses RFC2224 style URLs extended with libnfs specific url arguments some minor extensions.
|
||||
Libnfs uses RFC2224 style URLs extended with some minor libnfs extensions.
|
||||
The basic syntax of these URLs is :
|
||||
|
||||
nfs://<server|ipv4|ipv6>/path[?arg=val[&arg=val]*]
|
||||
|
@ -54,9 +66,9 @@ both these exports as well.
|
|||
The reason is because the NFSv3 protocol does not allow a client request
|
||||
to return data for an object in a different filesystem/mount.
|
||||
(legacy, but it is what it is. One reason for this restriction is to
|
||||
guarantee that inodes are uniqe across the mounted system.)
|
||||
guarantee that inodes are unique across the mounted system.)
|
||||
|
||||
This option, when enabled will make libnfs perform all these mounts
|
||||
This option, when enabled, will make libnfs perform all these mounts
|
||||
internally for you. This means that one libnfs mount may now have files
|
||||
with duplicate inode values so if you cache files based on inode
|
||||
make sure you cache files based on BOTH st.st_ino and st.st_dev.
|
||||
|
@ -72,16 +84,19 @@ ports from connecting.
|
|||
These servers require you use the "insecure" export option in /etc/exports
|
||||
in order to allow libnfs clients to be able to connect.
|
||||
|
||||
Some versions of Linux support special capabilities that can be assigned to
|
||||
programs to allow non-root users to bind to system ports.
|
||||
On Linux we can get around this restriction by setting the NET_BIND_SERVICE
|
||||
capability for the application binary.
|
||||
|
||||
This is set up by running
|
||||
sudo setcap 'cap_net_bind_service=+ep' /path/to/executable
|
||||
When libnfs is linked against an executable with this special capability
|
||||
assigned to it, libnfs may be able to use system ports even when executing
|
||||
under the privilege of a non-root user account.
|
||||
This capability allows the binary to use systems ports like this even when
|
||||
not running as root. Thus if you set this capability for your application
|
||||
you no longer need to edit the export on the NFS server to set "insecure".
|
||||
|
||||
This is highly non-portable so IF this works on your linux system, count
|
||||
yourself lucky.
|
||||
|
||||
I do not know what equivalent "capability" support is available on other
|
||||
platforms. Please drop me an email if your os of choice has something similar
|
||||
and I can add it to the README.
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
|
|
|
@ -22,7 +22,7 @@ if test "$SAVE_CFLAGS" = "x"; then
|
|||
fi
|
||||
|
||||
# We always want 64 bit file offsets
|
||||
CFLAGS="${CFLAGS} -D_FILE_OFFSET_BITS=64"
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
#option: utils
|
||||
AC_ARG_ENABLE([utils],
|
||||
|
@ -42,29 +42,19 @@ AC_ARG_ENABLE([examples],
|
|||
# We need popt to compile the examples
|
||||
if test x$ENABLE_EXAMPLES = xyes; then
|
||||
AC_MSG_CHECKING(whether libpopt is available)
|
||||
ac_save_CFLAGS="$CFLAGS"
|
||||
ac_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $GLIB_CFLAGS"
|
||||
LIBS="$GLIB_LIBS $LIBS -lpopt"
|
||||
AC_TRY_RUN([
|
||||
LIBS="$LIBS -lpopt"
|
||||
AC_TRY_LINK([#include <popt.h>], [
|
||||
/*
|
||||
* Just see if we can compile/link with popt
|
||||
*/
|
||||
#include <popt.h>
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int _argc;
|
||||
char **_argv;
|
||||
struct poptOption popt_options[] = {
|
||||
POPT_TABLEEND
|
||||
};
|
||||
poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
], ac_cv_have_popt=yes, ac_cv_have_popt=no,
|
||||
[echo $ac_n "compile with POPT. Assuming OK... $ac_c"
|
||||
ac_cv_have_popt=yes])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
poptGetContext(_argv[0], _argc, _argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
|
||||
], ac_cv_have_popt=yes, ac_cv_have_popt=no)
|
||||
LIBS="$ac_save_LIBS"
|
||||
if test "$ac_cv_have_popt" = yes ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
|
@ -79,20 +69,9 @@ fi
|
|||
AC_SUBST(MAYBE_EXAMPLES)
|
||||
|
||||
AC_MSG_CHECKING(whether SO_BINDTODEVICE is available)
|
||||
AC_TRY_RUN([
|
||||
/*
|
||||
* Just see if we can compile with SO_BINDTODEVICE
|
||||
*/
|
||||
#include <net/if.h>
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
AC_TRY_COMPILE([#include <net/if.h>], [
|
||||
int i = SO_BINDTODEVICE;
|
||||
return 0;
|
||||
}
|
||||
], ac_cv_have_so_bindtodevice=yes, ac_cv_have_so_bindtodevice=no,
|
||||
[echo $ac_n "compile with SO_BINDTODEVICE. Assuming OK... $ac_c"
|
||||
ac_cv_have_so_bindtodevice=yes])
|
||||
], ac_cv_have_so_bindtodevice=yes, ac_cv_have_so_bindtodevice=no)
|
||||
if test "$ac_cv_have_so_bindtodevice" = yes ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_SO_BINDTODEVICE, 1, [Whether our sockets support SO_BINDTODEVICE])
|
||||
|
@ -123,7 +102,7 @@ case $host in
|
|||
AC_CHECK_LIB([socket], [main], , [AC_MSG_ERROR([Can not find required library])])
|
||||
AC_CHECK_LIB([nsl], [main], , [AC_MSG_ERROR([Can not find required library])])
|
||||
;;
|
||||
*mingw32* | *cygwin* | *wince* | *mingwce*)
|
||||
*mingw32* | *wince* | *mingwce*)
|
||||
LIBSOCKET='-lws2_32'
|
||||
SYS=mingw32
|
||||
;;
|
||||
|
@ -133,6 +112,10 @@ esac
|
|||
AM_CONDITIONAL(HAVE_WIN32, test "${SYS}" = "mingw32")
|
||||
AC_SUBST([LIBSOCKET])
|
||||
|
||||
# check for sys/sysmacros.h
|
||||
dnl Check for sys/sysmacros.h
|
||||
AC_CHECK_HEADERS([sys/sysmacros.h])
|
||||
|
||||
# check for poll.h
|
||||
dnl Check for poll.h
|
||||
AC_CHECK_HEADERS([poll.h])
|
||||
|
@ -169,6 +152,10 @@ AC_CHECK_HEADERS([sys/vfs.h])
|
|||
dnl Check for sys/statvfs.h
|
||||
AC_CHECK_HEADERS([sys/statvfs.h])
|
||||
|
||||
# check for fuse.h
|
||||
dnl Check for fuse.h
|
||||
AC_CHECK_HEADERS([fuse.h])
|
||||
|
||||
# check for sys/socket.h
|
||||
dnl Check for sys/socket.h
|
||||
AC_CHECK_HEADERS([sys/socket.h])
|
||||
|
@ -205,6 +192,19 @@ AC_CHECK_MEMBER([struct sockaddr_storage.ss_family],
|
|||
#include <sys/socket.h>
|
||||
])
|
||||
|
||||
# check for tevent + talloc
|
||||
AC_CACHE_CHECK([for talloc and tevent support],libnfs_cv_HAVE_TALLOC_TEVENT,[
|
||||
AC_TRY_COMPILE([
|
||||
#include <talloc.h>
|
||||
#include <tevent.h>],
|
||||
[struct tevent_context *ctx = tevent_context_init(NULL);
|
||||
int major = talloc_version_major();],
|
||||
libiscsi_cv_HAVE_TALLOC_TEVENT=yes,libiscsi_cv_HAVE_TALLOC_TEVENT=no)])
|
||||
if test x"$libiscsi_cv_HAVE_TALLOC_TEVENT" = x"yes"; then
|
||||
AC_DEFINE(HAVE_TALLOC_TEVENT,1,[Whether we have talloc nad tevent support])
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_TALLOC_TEVENT], [test $libiscsi_cv_HAVE_TALLOC_TEVENT = yes])
|
||||
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec])
|
||||
|
||||
# check where makedev is defined
|
||||
|
@ -217,6 +217,7 @@ AC_CONFIG_FILES([Makefile]
|
|||
[lib/Makefile]
|
||||
[mount/Makefile]
|
||||
[nfs/Makefile]
|
||||
[nfs4/Makefile]
|
||||
[nlm/Makefile]
|
||||
[nsm/Makefile]
|
||||
[portmap/Makefile]
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-io portmap-client
|
||||
noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-io nfs-ln nfs4-cat portmap-client portmap-server
|
||||
|
||||
if HAVE_TALLOC_TEVENT
|
||||
noinst_PROGRAMS += nfs4-cat-talloc
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(abs_top_srcdir)/include \
|
||||
|
@ -6,6 +10,7 @@ AM_CPPFLAGS = \
|
|||
-I$(abs_top_srcdir)/include/win32 \
|
||||
-I$(abs_top_srcdir)/mount \
|
||||
-I$(abs_top_srcdir)/nfs \
|
||||
-I$(abs_top_srcdir)/nfs4 \
|
||||
-I$(abs_top_srcdir)/portmap \
|
||||
-I$(abs_top_srcdir)/rquota \
|
||||
"-D_U_=__attribute__((unused))"
|
||||
|
@ -17,4 +22,8 @@ nfsclient_sync_LDADD = $(COMMON_LIBS)
|
|||
nfsclient_bcast_LDADD = $(COMMON_LIBS)
|
||||
nfsclient_listservers_LDADD = $(COMMON_LIBS)
|
||||
nfs_io_LDADD = $(COMMON_LIBS)
|
||||
nfs_ln_LDADD = $(COMMON_LIBS)
|
||||
nfs4_cat_LDADD = $(COMMON_LIBS) -levent
|
||||
nfs4_cat_talloc_LDADD = $(COMMON_LIBS) -ltevent -ltalloc
|
||||
portmap_client_LDADD = $(COMMON_LIBS)
|
||||
portmap_server_LDADD = $(COMMON_LIBS) -levent
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2017
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
#include "aros_compat.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32_compat.h"
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
WSADATA wsaData;
|
||||
#define PRId64 "ll"
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#ifndef AROS
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "libnfs.h"
|
||||
#include "libnfs-raw.h"
|
||||
#include "libnfs-raw-mount.h"
|
||||
|
||||
void print_usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: nfs-ln <url> <old-path> <new-path>\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 1;
|
||||
struct nfs_context *nfs = NULL;
|
||||
struct nfsfh *nfsfh = NULL;
|
||||
struct nfs_url *url = NULL;
|
||||
|
||||
#ifdef WIN32
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
|
||||
printf("Failed to start Winsock2\n");
|
||||
exit(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
aros_init_socket();
|
||||
#endif
|
||||
|
||||
if (argc != 4) {
|
||||
print_usage();
|
||||
goto finished;
|
||||
}
|
||||
|
||||
nfs = nfs_init_context();
|
||||
if (nfs == NULL) {
|
||||
printf("failed to init context\n");
|
||||
goto finished;
|
||||
}
|
||||
|
||||
url = nfs_parse_url_full(nfs, argv[1]);
|
||||
if (url == NULL) {
|
||||
fprintf(stderr, "%s\n", nfs_get_error(nfs));
|
||||
goto finished;
|
||||
}
|
||||
|
||||
if (nfs_mount(nfs, url->server, url->path) != 0) {
|
||||
fprintf(stderr, "Failed to mount nfs share : %s\n",
|
||||
nfs_get_error(nfs));
|
||||
goto finished;
|
||||
}
|
||||
|
||||
ret = nfs_link(nfs, argv[2], argv[3]);
|
||||
if (ret) {
|
||||
fprintf(stderr, "nfs_link() failed with %s\n",
|
||||
nfs_get_error(nfs));
|
||||
goto finished;
|
||||
}
|
||||
|
||||
finished:
|
||||
if (ret > 0) {
|
||||
print_usage();
|
||||
}
|
||||
nfs_destroy_url(url);
|
||||
if (nfs != NULL) {
|
||||
if (nfsfh) {
|
||||
nfs_close(nfs, nfsfh);
|
||||
}
|
||||
nfs_destroy_context(nfs);
|
||||
}
|
||||
return !!ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,968 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
|
||||
/* THIS IS NOT A PROPER NFS4 CLIENT!
|
||||
* This software is only meant to illustrate how to plug libnfs into
|
||||
* an eventsystem like libevent and then use the raw rpc api
|
||||
* connect to an nfsv4 server and read a file.
|
||||
* If any kind of error occurs it will immediately terminate by calling
|
||||
* exit() without even attempting to cleanup.
|
||||
* If the access to the server is successful it should however run valgrind
|
||||
* clean.
|
||||
*
|
||||
* NFSv4 access is done through the raw async interface and is cumbersome
|
||||
* to use for NFSv4 due to the richness of the protocol.
|
||||
* A future aim will be to build better helper functions to make ease
|
||||
* of use better.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2015
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
#include "aros_compat.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32_compat.h"
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
WSADATA wsaData;
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include "libnfs.h"
|
||||
#include "libnfs-raw.h"
|
||||
#include "libnfs-raw-nfs4.h"
|
||||
|
||||
#include <tevent.h>
|
||||
#include <talloc.h>
|
||||
|
||||
struct tevent_context *ev;
|
||||
|
||||
struct client {
|
||||
struct nfs_context *nfs;
|
||||
struct rpc_context *rpc;
|
||||
char *server;
|
||||
char *path;
|
||||
|
||||
struct tevent_fd *fde;
|
||||
int callback_fd;
|
||||
|
||||
/* For SETCLIENTID */
|
||||
verifier4 verifier;
|
||||
char *id;
|
||||
clientid4 clientid;
|
||||
verifier4 setclientid_confirm;
|
||||
|
||||
/* For OPEN */
|
||||
char *owner;
|
||||
int op_len;
|
||||
|
||||
/* filehandle and state for the open file */
|
||||
nfs_fh4 fh;
|
||||
uint32_t seqid;
|
||||
stateid4 stateid;
|
||||
|
||||
/* offset when reading */
|
||||
uint64_t offset;
|
||||
|
||||
int is_finished;
|
||||
};
|
||||
|
||||
static void set_nonblocking(int fd)
|
||||
{
|
||||
int v = 0;
|
||||
#if defined(WIN32)
|
||||
long nonblocking=1;
|
||||
v = ioctl(fd, FIONBIO, &nonblocking);
|
||||
#else
|
||||
v = fcntl(fd, F_GETFL, 0);
|
||||
fcntl(fd, F_SETFL, v | O_NONBLOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int client_destructor(struct client *c)
|
||||
{
|
||||
if (c->nfs) {
|
||||
nfs_destroy_context(c->nfs);
|
||||
}
|
||||
if (c->callback_fd != -1) {
|
||||
close(c->callback_fd);
|
||||
}
|
||||
};
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: nfs4-cat-talloc <file>\n");
|
||||
fprintf(stderr, " <file> is an nfs url.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void update_events(struct rpc_context *rpc,
|
||||
struct tevent_fd *fde)
|
||||
{
|
||||
int events = rpc_which_events(rpc);
|
||||
int flags = 0;
|
||||
|
||||
if (events & POLLIN) {
|
||||
flags |= TEVENT_FD_READ;
|
||||
}
|
||||
|
||||
if (events & POLLOUT) {
|
||||
flags |= TEVENT_FD_WRITE;
|
||||
}
|
||||
|
||||
tevent_fd_set_flags(fde, flags);
|
||||
}
|
||||
|
||||
struct server {
|
||||
struct rpc_context *rpc;
|
||||
struct tevent_fd *fde;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Helper functions to send client RPC requests.
|
||||
*/
|
||||
static void send_setclientid(struct rpc_context *rpc,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
SETCLIENTID4args *sc4args;
|
||||
nfs_argop4 op[1];
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
struct sockaddr_in *in;
|
||||
struct sockaddr_in6 *in6;
|
||||
char *netid;
|
||||
char str[240], addr[256];
|
||||
unsigned short port;
|
||||
|
||||
if (getsockname(client->callback_fd, (struct sockaddr *)&ss, &len) < 0) {
|
||||
fprintf(stderr, "getsockaddr failed\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
switch (ss.ss_family) {
|
||||
case AF_INET:
|
||||
netid = "tcp";
|
||||
in = (struct sockaddr_in *)&ss;
|
||||
inet_ntop(AF_INET, &in->sin_addr, str, sizeof(str));
|
||||
port = ntohs(in->sin_port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
netid = "tcp6";
|
||||
in6 = (struct sockaddr_in6 *)&ss;
|
||||
inet_ntop(AF_INET6, &in6->sin6_addr, str, sizeof(str));
|
||||
port = ntohs(in6->sin6_port);
|
||||
break;
|
||||
}
|
||||
sprintf(addr, "%s.%d.%d", str, port >> 8, port & 0xff);
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
|
||||
op[0].argop = OP_SETCLIENTID;
|
||||
sc4args = &op[0].nfs_argop4_u.opsetclientid;
|
||||
memcpy(sc4args->client.verifier, client->verifier, sizeof(verifier4));
|
||||
sc4args->client.id.id_len = strlen(client->id);
|
||||
sc4args->client.id.id_val = client->id;
|
||||
sc4args->callback.cb_program = NFS4_CALLBACK;
|
||||
sc4args->callback.cb_location.r_netid = netid;
|
||||
sc4args->callback.cb_location.r_addr = addr;
|
||||
sc4args->callback_ident = 0x00000001;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 SETCLIENTID request\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_setclientid_confirm(struct rpc_context *rpc,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
SETCLIENTID_CONFIRM4args *scc4args;
|
||||
nfs_argop4 op[1];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_SETCLIENTID_CONFIRM;
|
||||
scc4args = &op[0].nfs_argop4_u.opsetclientid_confirm;
|
||||
scc4args->clientid = client->clientid;
|
||||
memcpy(scc4args->setclientid_confirm, client->setclientid_confirm,
|
||||
NFS4_VERIFIER_SIZE);
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 SETCLIENTID_CONFIRM request\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_getrootfh(struct rpc_context *rpc,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 op[2];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTROOTFH;
|
||||
op[1].argop = OP_GETFH;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 GETROOTFH request\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_open(struct rpc_context *rpc, nfs_fh4 dir, char *path,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
ACCESS4args *a4args;
|
||||
LOOKUP4args *l4args;
|
||||
OPEN4args *o4args;
|
||||
nfs_argop4 *op;
|
||||
int i = 0, idx = 0;
|
||||
char *tmp;
|
||||
|
||||
/*
|
||||
* Count how many directories we have in the path.
|
||||
*/
|
||||
tmp = path;
|
||||
while (tmp = strchr(tmp, '/')) {
|
||||
i++;
|
||||
tmp++;
|
||||
}
|
||||
|
||||
op = talloc_zero_array(client, nfs_argop4, 4 + i);
|
||||
|
||||
op[idx].argop = OP_PUTFH;
|
||||
op[idx].nfs_argop4_u.opputfh.object = dir;
|
||||
idx++;
|
||||
|
||||
while (i-- > 0) {
|
||||
tmp = strchr(path, '/');
|
||||
*tmp++ = '\0';
|
||||
|
||||
op[idx].argop = OP_LOOKUP;
|
||||
l4args = &op[idx].nfs_argop4_u.oplookup;
|
||||
l4args->objname.utf8string_len = strlen(path);
|
||||
l4args->objname.utf8string_val = path;
|
||||
idx++;
|
||||
|
||||
path = tmp;
|
||||
}
|
||||
|
||||
op[idx].argop = OP_OPEN;
|
||||
o4args = &op[idx].nfs_argop4_u.opopen;
|
||||
o4args->seqid = client->seqid;
|
||||
o4args->share_access = OPEN4_SHARE_ACCESS_READ;
|
||||
o4args->share_deny = OPEN4_SHARE_DENY_NONE;
|
||||
o4args->owner.clientid = client->clientid;
|
||||
o4args->owner.owner.owner_len = strlen(client->owner);
|
||||
o4args->owner.owner.owner_val = client->owner;
|
||||
o4args->openhow.opentype = OPEN4_NOCREATE;
|
||||
o4args->claim.claim = CLAIM_NULL;
|
||||
o4args->claim.open_claim4_u.file.utf8string_len = strlen(path);
|
||||
o4args->claim.open_claim4_u.file.utf8string_val = path;
|
||||
idx++;
|
||||
|
||||
op[idx].argop = OP_GETFH;
|
||||
idx++;
|
||||
|
||||
op[idx].argop = OP_ACCESS;
|
||||
a4args = &op[idx].nfs_argop4_u.opaccess;
|
||||
a4args->access = ACCESS4_READ;
|
||||
|
||||
client->seqid++;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = idx;
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 OPEN request\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
talloc_free(op);
|
||||
}
|
||||
|
||||
static void send_open_confirm(struct rpc_context *rpc, nfs_fh4 object, rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
OPEN_CONFIRM4args *oc4args;
|
||||
PUTFH4args *pfh4args;
|
||||
nfs_argop4 op[2];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTFH;
|
||||
pfh4args = &op[0].nfs_argop4_u.opputfh;
|
||||
pfh4args->object = object;
|
||||
|
||||
op[1].argop = OP_OPEN_CONFIRM;
|
||||
oc4args = &op[1].nfs_argop4_u.opopen_confirm;
|
||||
oc4args->open_stateid.seqid = client->seqid;
|
||||
memcpy(oc4args->open_stateid.other,
|
||||
client->stateid.other, 12);
|
||||
oc4args->seqid = client->seqid;
|
||||
|
||||
client->seqid++;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_read(struct rpc_context *rpc, nfs_fh4 object,
|
||||
uint64_t offset, uint32_t count,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
PUTFH4args *pfh4args;
|
||||
READ4args *r4args;
|
||||
nfs_argop4 op[3];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTFH;
|
||||
pfh4args = &op[0].nfs_argop4_u.opputfh;
|
||||
pfh4args->object = object;
|
||||
|
||||
op[1].argop = OP_READ;
|
||||
r4args = &op[1].nfs_argop4_u.opread;
|
||||
r4args->stateid.seqid = client->seqid;
|
||||
memcpy(r4args->stateid.other, client->stateid.other, 12);
|
||||
r4args->offset = offset;
|
||||
r4args->count = count;
|
||||
|
||||
op[2].argop = OP_GETATTR;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 READ request\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_close(struct rpc_context *rpc, nfs_fh4 object,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
CLOSE4args *c4args;
|
||||
PUTFH4args *pfh4args;
|
||||
nfs_argop4 op[2];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTFH;
|
||||
pfh4args = &op[0].nfs_argop4_u.opputfh;
|
||||
pfh4args->object = object;
|
||||
|
||||
op[1].argop = OP_CLOSE;
|
||||
c4args = &op[1].nfs_argop4_u.opclose;
|
||||
c4args->seqid = client->seqid;
|
||||
c4args->open_stateid.seqid = client->seqid;
|
||||
memcpy(c4args->open_stateid.other, client->stateid.other, 12);
|
||||
|
||||
client->seqid++;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callbacks for completed requests.
|
||||
*/
|
||||
void close_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
|
||||
/*
|
||||
* FINISHED
|
||||
*/
|
||||
/*
|
||||
* Note that we can not start tearing down and destroying the contexts
|
||||
* right here as we are still in a callback from ... rpc_service().
|
||||
* Instead flag that we should abort and start doing the teardown
|
||||
* in client_io once we return from libnfs.
|
||||
*/
|
||||
client->is_finished = 1;
|
||||
}
|
||||
|
||||
void read_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
struct READ4res *r4res;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to read file on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to read file on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
r4res = &res->resarray.resarray_val[1].nfs_resop4_u.opread;
|
||||
write(1,
|
||||
r4res->READ4res_u.resok4.data.data_val,
|
||||
r4res->READ4res_u.resok4.data.data_len);
|
||||
|
||||
/*
|
||||
* Are we at end-of-file? If so we can close the file and exit.
|
||||
*/
|
||||
if (r4res->READ4res_u.resok4.eof) {
|
||||
send_close(rpc, client->fh, close_cb, client);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We still have more data to read.
|
||||
*/
|
||||
client->offset += r4res->READ4res_u.resok4.data.data_len;
|
||||
|
||||
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
|
||||
}
|
||||
|
||||
void open_confirm_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to confirm open file on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to confirm open file on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
|
||||
}
|
||||
|
||||
void open_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
GETFH4res *gfh4res;
|
||||
OPEN4res *o4res;
|
||||
int idx;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to open file on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to open file on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/* Find the index for the OPEN opcode */
|
||||
for (idx = 1; idx < res->resarray.resarray_len - 1; idx++) {
|
||||
if ((res->resarray.resarray_val[idx].resop == OP_OPEN) &&
|
||||
(res->resarray.resarray_val[idx + 1].resop == OP_GETFH)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx >= res->resarray.resarray_len - 1) {
|
||||
fprintf(stderr, "No OP_OPEN in server response\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/* Store the open handle in the client structure */
|
||||
gfh4res = &res->resarray.resarray_val[idx+1].nfs_resop4_u.opgetfh;
|
||||
client->fh.nfs_fh4_len = gfh4res->GETFH4res_u.resok4.object.nfs_fh4_len;
|
||||
client->fh.nfs_fh4_val = talloc_size(client, client->fh.nfs_fh4_len);
|
||||
if (client->fh.nfs_fh4_val == NULL) {
|
||||
fprintf(stderr, "Failed to allocate data for nfs_fh4\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
memcpy(client->fh.nfs_fh4_val,
|
||||
gfh4res->GETFH4res_u.resok4.object.nfs_fh4_val,
|
||||
client->fh.nfs_fh4_len);
|
||||
|
||||
/* Store stateid for the open handle in the client structure */
|
||||
o4res = &res->resarray.resarray_val[idx].nfs_resop4_u.opopen;
|
||||
client->stateid.seqid = o4res->OPEN4res_u.resok4.stateid.seqid;
|
||||
memcpy(client->stateid.other,
|
||||
o4res->OPEN4res_u.resok4.stateid.other, 12);
|
||||
|
||||
/* Check if server wants us to confirm the open */
|
||||
if (o4res->OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM) {
|
||||
send_open_confirm(rpc, client->fh, open_confirm_cb, client);
|
||||
return;
|
||||
}
|
||||
|
||||
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
|
||||
}
|
||||
|
||||
void getrootfh_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
GETFH4res *gfh4res;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to get root filehandle of server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to get root filehandle of server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
gfh4res = &res->resarray.resarray_val[1].nfs_resop4_u.opgetfh;
|
||||
send_open(rpc, gfh4res->GETFH4res_u.resok4.object,
|
||||
client->path, open_cb, client);
|
||||
}
|
||||
|
||||
void setclientid_confirm_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
char *path;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to set client id of server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to set client id of server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
send_getrootfh(rpc, getrootfh_cb, client);
|
||||
}
|
||||
|
||||
void setclientid_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
SETCLIENTID4res *sc4res;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to set client id on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to set client id on server %s\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
sc4res = &res->resarray.resarray_val[0].nfs_resop4_u.opsetclientid;
|
||||
client->clientid = sc4res->SETCLIENTID4res_u.resok4.clientid;
|
||||
memcpy(client->setclientid_confirm,
|
||||
sc4res->SETCLIENTID4res_u.resok4.setclientid_confirm,
|
||||
NFS4_VERIFIER_SIZE);
|
||||
|
||||
send_setclientid_confirm(rpc, setclientid_confirm_cb, client);
|
||||
}
|
||||
|
||||
/*
|
||||
* NULL procedure for the callback protocol.
|
||||
*/
|
||||
static int cb_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CB_COMPOUND procedure for the callback protocol.
|
||||
* This is where the server will inform us about lease breaks and similar.
|
||||
*/
|
||||
static int cb_compound_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
CB_COMPOUND4args *args = call->body.cbody.args;
|
||||
|
||||
fprintf(stderr, "cb_compund_cb. Do something here.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct service_proc pt[] = {
|
||||
{CB_NULL, cb_null_proc,
|
||||
(zdrproc_t)zdr_void, 0},
|
||||
{CB_COMPOUND, cb_compound_proc,
|
||||
(zdrproc_t)zdr_CB_COMPOUND4args, sizeof(CB_COMPOUND4args)},
|
||||
};
|
||||
|
||||
static void server_io(struct tevent_context *ev, struct tevent_fd *fde,
|
||||
uint16_t events, void *private_data)
|
||||
{
|
||||
struct server *server = private_data;
|
||||
int revents = 0;
|
||||
|
||||
if (events & TEVENT_FD_READ) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if (events & TEVENT_FD_WRITE) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
|
||||
if (rpc_service(server->rpc, revents) < 0) {
|
||||
talloc_free(server);
|
||||
return;
|
||||
}
|
||||
|
||||
update_events(server->rpc, server->fde);
|
||||
}
|
||||
|
||||
static int server_destructor(struct server *s)
|
||||
{
|
||||
if (s->rpc) {
|
||||
rpc_destroy_context(s->rpc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback is invoked when others (the nfsv4 server) initiates a
|
||||
* NFSv4 CALLBACK sessions to us.
|
||||
* We accept() the connection and create a local rpc server context
|
||||
* for the callback protocol.
|
||||
*/
|
||||
static void client_accept(struct tevent_context *ev, struct tevent_fd *fde,
|
||||
uint16_t events, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
struct server *server;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
int fd;
|
||||
|
||||
server = talloc_zero(client, struct server);
|
||||
talloc_set_destructor(server, server_destructor);
|
||||
|
||||
if ((fd = accept(client->callback_fd, (struct sockaddr *)&ss, &len)) < 0) {
|
||||
fprintf(stderr, "accept failed\n");
|
||||
talloc_free(server);
|
||||
return;
|
||||
}
|
||||
set_nonblocking(fd);
|
||||
|
||||
server->rpc = rpc_init_server_context(fd);
|
||||
if (server->rpc == NULL) {
|
||||
fprintf(stderr, "Failed to create server rpc context\n");
|
||||
talloc_free(server);
|
||||
return;
|
||||
}
|
||||
|
||||
rpc_register_service(server->rpc, NFS4_CALLBACK, NFS_CB,
|
||||
pt, sizeof(pt) / sizeof(pt[0]));
|
||||
|
||||
server->fde = tevent_add_fd(ev, server, fd, TEVENT_FD_READ,
|
||||
server_io, server);
|
||||
tevent_fd_set_auto_close(server->fde);
|
||||
update_events(server->rpc, server->fde);
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback is invoked when our async connect() to the server has
|
||||
* completed. At this point we know which IP address was used locally for
|
||||
* the connection and can bind our nfsv4 callback server instance to it.
|
||||
*/
|
||||
void connect_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
struct sockaddr_in *in;
|
||||
struct sockaddr_in6 *in6;
|
||||
struct tevent_fd *fde;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "connection to NFSv4 server %s failed\n",
|
||||
client->server);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* NFSv4 CALLBACK
|
||||
* Now that we have a client connection we can register a callback
|
||||
* server port on the same IP address as was used to the outgoing
|
||||
* client connection. That way we know that the address used by the
|
||||
* server is routable, and uses the same version of ip, that the client
|
||||
* supports and can route to.
|
||||
*/
|
||||
if (getsockname(rpc_get_fd(rpc), (struct sockaddr *)&ss, &len) < 0) {
|
||||
fprintf(stderr, "getsockaddr failed\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
switch (ss.ss_family) {
|
||||
case AF_INET:
|
||||
in = (struct sockaddr_in *)&ss;
|
||||
in->sin_port=0;
|
||||
break;
|
||||
case AF_INET6:
|
||||
in6 = (struct sockaddr_in6 *)&ss;
|
||||
in6->sin6_port=0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Can not handle AF_FAMILY:%d", ss.ss_family);
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
client->callback_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (client->callback_fd == -1) {
|
||||
fprintf(stderr, "Failed to create callback socket\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
set_nonblocking(client->callback_fd);
|
||||
|
||||
if (bind(client->callback_fd, (struct sockaddr *)&ss, sizeof(ss)) < 0) {
|
||||
fprintf(stderr, "Failed to bind callback socket\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (listen(client->callback_fd, 16) < 0) {
|
||||
fprintf(stderr, "failed to listen to callback socket\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
fde = tevent_add_fd(ev, client, client->callback_fd, TEVENT_FD_READ,
|
||||
client_accept, private_data);
|
||||
tevent_fd_set_auto_close(fde);
|
||||
|
||||
update_events(client->rpc, client->fde);
|
||||
|
||||
/*
|
||||
* Now that we are finished setting up the callback server port
|
||||
* we can proceed and negotiate the nfsv4 client id.
|
||||
*/
|
||||
send_setclientid(rpc, setclientid_cb, client);
|
||||
}
|
||||
|
||||
|
||||
static void client_io(struct tevent_context *ev, struct tevent_fd *fde,
|
||||
uint16_t events, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
int revents = 0;
|
||||
|
||||
if (events & TEVENT_FD_READ) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if (events & TEVENT_FD_WRITE) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
|
||||
if (rpc_service(client->rpc, revents) < 0) {
|
||||
fprintf(stderr, "rpc_service failed\n");
|
||||
talloc_free(client);
|
||||
exit(10);
|
||||
}
|
||||
update_events(client->rpc, client->fde);
|
||||
if (client->is_finished) {
|
||||
talloc_free(client);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TALLOC_CTX *ctx = talloc_new(NULL);
|
||||
struct client *client;
|
||||
struct nfs_url *url;
|
||||
int i, fd;
|
||||
|
||||
#ifdef WIN32
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
|
||||
fprintf(stderr, "Failed to start Winsock2\n");
|
||||
exit(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
aros_init_socket();
|
||||
#endif
|
||||
|
||||
srandom(time(NULL) ^ getpid());
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
ev = tevent_context_init(ctx);
|
||||
|
||||
client = talloc_zero(ctx, struct client);
|
||||
talloc_set_destructor(client, client_destructor);
|
||||
client->callback_fd = -1;
|
||||
|
||||
client->nfs = nfs_init_context();
|
||||
if (client->nfs == NULL) {
|
||||
fprintf(stderr, "failed to init nfs context\n");
|
||||
talloc_free(ctx);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
url = nfs_parse_url_dir(client->nfs, argv[1]);
|
||||
if (url == NULL) {
|
||||
fprintf(stderr, "failed to parse url\n");
|
||||
talloc_free(ctx);
|
||||
exit(10);
|
||||
}
|
||||
client->server = talloc_strdup(client, url->server);
|
||||
client->path = talloc_strdup(client, &url->path[1]); // skip leading '/'
|
||||
nfs_destroy_url(url);
|
||||
|
||||
for (i = 0; i < NFS4_VERIFIER_SIZE; i++) {
|
||||
client->verifier[i] = random() & 0xff;
|
||||
}
|
||||
client->id = talloc_asprintf(client, "Libnfs %s tcp pid:%d",
|
||||
argv[1], getpid());
|
||||
client->owner = talloc_asprintf(client, "open id:libnfs pid:%d",
|
||||
getpid());
|
||||
/*
|
||||
* From here on we will mainly use the rpc context directly
|
||||
* and not the nfs context so lets store the rpc context here
|
||||
* for easy access.
|
||||
*/
|
||||
client->rpc = nfs_get_rpc_context(client->nfs);
|
||||
|
||||
if (rpc_connect_program_async(client->rpc, client->server,
|
||||
NFS4_PROGRAM, NFS_V4,
|
||||
connect_cb, client) != 0) {
|
||||
fprintf(stderr, "Failed to start connection: %s\n",
|
||||
rpc_get_error(client->rpc));
|
||||
talloc_free(ctx);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the events we need for the outgoing client RPC channel.
|
||||
*/
|
||||
fd = rpc_get_fd(client->rpc);
|
||||
client->fde = tevent_add_fd(ev, client, fd, TEVENT_FD_READ,
|
||||
client_io, (void *)client);
|
||||
update_events(client->rpc, client->fde);
|
||||
|
||||
tevent_loop_wait(ev);
|
||||
|
||||
talloc_free(ctx);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,943 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
|
||||
/* THIS IS NOT A PROPER NFS4 CLIENT!
|
||||
* This software is only meant to illustrate how to plug libnfs into
|
||||
* an eventsystem like libevent and then use the raw rpc api
|
||||
* connect to an nfsv4 server and read a file.
|
||||
* If any kind of error occurs it will immediately terminate by calling
|
||||
* exit() without even attempting to cleanup.
|
||||
* If the access to the server is successful it should however run valgrind
|
||||
* clean.
|
||||
*
|
||||
* NFSv4 access is done through the raw async interface and is cumbersome
|
||||
* to use for NFSv4 due to the richness of the protocol.
|
||||
* A future aim will be to build better helper functions to make ease
|
||||
* of use better.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2015
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
#include "aros_compat.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32_compat.h"
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
WSADATA wsaData;
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include "libnfs.h"
|
||||
#include "libnfs-raw.h"
|
||||
#include "libnfs-raw-nfs4.h"
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
struct event_base *base;
|
||||
|
||||
struct client {
|
||||
struct rpc_context *rpc;
|
||||
struct event *read_event;
|
||||
struct event *write_event;
|
||||
struct event *listen_event;
|
||||
|
||||
char *server;
|
||||
char *path;
|
||||
int op_len;
|
||||
int is_finished;
|
||||
|
||||
verifier4 verifier;
|
||||
char *id;
|
||||
char *owner;
|
||||
clientid4 clientid;
|
||||
verifier4 setclientid_confirm;
|
||||
|
||||
/* filehandle and state for the open file */
|
||||
nfs_fh4 fh;
|
||||
uint32_t seqid;
|
||||
stateid4 stateid;
|
||||
|
||||
/* offset when reading */
|
||||
uint64_t offset;
|
||||
|
||||
int callback_fd;
|
||||
};
|
||||
|
||||
struct server {
|
||||
struct server *next;
|
||||
struct rpc_context *rpc;
|
||||
struct event *read_event;
|
||||
struct event *write_event;
|
||||
};
|
||||
struct server *server_list;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: nfs4-cat <file>\n");
|
||||
fprintf(stderr, " <file> is an nfs url.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void update_events(struct rpc_context *rpc, struct event *read_event,
|
||||
struct event *write_event)
|
||||
{
|
||||
int events = rpc_which_events(rpc);
|
||||
|
||||
if (read_event) {
|
||||
if (events & POLLIN) {
|
||||
event_add(read_event, NULL);
|
||||
} else {
|
||||
event_del(read_event);
|
||||
}
|
||||
}
|
||||
if (write_event) {
|
||||
if (events & POLLOUT) {
|
||||
event_add(write_event, NULL);
|
||||
} else {
|
||||
event_del(write_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void free_server(struct server *server)
|
||||
{
|
||||
if (server->rpc) {
|
||||
rpc_disconnect(server->rpc, NULL);
|
||||
rpc_destroy_context(server->rpc);
|
||||
server->rpc = NULL;
|
||||
}
|
||||
if (server->read_event) {
|
||||
event_free(server->read_event);
|
||||
server->read_event = NULL;
|
||||
}
|
||||
if (server->write_event) {
|
||||
event_free(server->write_event);
|
||||
server->write_event = NULL;
|
||||
}
|
||||
|
||||
free(server);
|
||||
}
|
||||
|
||||
static void server_io(evutil_socket_t fd, short events, void *private_data)
|
||||
{
|
||||
struct server *server = private_data;
|
||||
int revents = 0;
|
||||
|
||||
if (events & EV_READ) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if (events & EV_WRITE) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
|
||||
if (rpc_service(server->rpc, revents) < 0) {
|
||||
fprintf(stderr, "rpc_service() failed for server\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
update_events(server->rpc, server->read_event, server->write_event);
|
||||
}
|
||||
|
||||
static void client_io(evutil_socket_t fd, short events, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
struct server *server;
|
||||
int revents = 0;
|
||||
|
||||
if (events & EV_READ) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if (events & EV_WRITE) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
|
||||
if (rpc_service(client->rpc, revents) < 0) {
|
||||
fprintf(stderr, "rpc_service failed\n");
|
||||
exit(10);
|
||||
}
|
||||
update_events(client->rpc, client->read_event, client->write_event);
|
||||
|
||||
if (client->is_finished) {
|
||||
/*
|
||||
* Stop listening for new connections.
|
||||
*/
|
||||
event_free(client->listen_event);
|
||||
client->listen_event = NULL;
|
||||
|
||||
/*
|
||||
* Stop listening for events on the client context.
|
||||
*/
|
||||
event_free(client->read_event);
|
||||
client->read_event = NULL;
|
||||
event_free(client->write_event);
|
||||
client->write_event = NULL;
|
||||
|
||||
/*
|
||||
* Stop listening to server connections.
|
||||
*/
|
||||
for (server = server_list; server; server = server->next) {
|
||||
if (server->read_event) {
|
||||
event_free(server->read_event);
|
||||
server->read_event = NULL;
|
||||
}
|
||||
if (server->write_event) {
|
||||
event_free(server->write_event);
|
||||
server->write_event = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions to send client RPC requests.
|
||||
*/
|
||||
static void send_setclientid_confirm(struct rpc_context *rpc,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 op[1];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_SETCLIENTID_CONFIRM;
|
||||
op[0].nfs_argop4_u.opsetclientid_confirm.clientid = client->clientid;
|
||||
memcpy(op[0].nfs_argop4_u.opsetclientid_confirm.setclientid_confirm, client->setclientid_confirm, NFS4_VERIFIER_SIZE);
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 SETCLIENTID_CONFIRM request\n");
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_setclientid(struct rpc_context *rpc,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 op[1];
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
struct sockaddr_in *in;
|
||||
struct sockaddr_in6 *in6;
|
||||
char *netid;
|
||||
char str[240], addr[256];
|
||||
unsigned short port;
|
||||
|
||||
if (getsockname(client->callback_fd, (struct sockaddr *)&ss, &len) < 0) {
|
||||
fprintf(stderr, "getsockaddr failed\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
switch (ss.ss_family) {
|
||||
case AF_INET:
|
||||
netid = "tcp";
|
||||
in = (struct sockaddr_in *)&ss;
|
||||
inet_ntop(AF_INET, &in->sin_addr, str, sizeof(str));
|
||||
port = ntohs(in->sin_port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
netid = "tcp6";
|
||||
in6 = (struct sockaddr_in6 *)&ss;
|
||||
inet_ntop(AF_INET6, &in6->sin6_addr, str, sizeof(str));
|
||||
port = ntohs(in6->sin6_port);
|
||||
break;
|
||||
}
|
||||
sprintf(addr, "%s.%d.%d", str, port >> 8, port & 0xff);
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_SETCLIENTID;
|
||||
memcpy(op[0].nfs_argop4_u.opsetclientid.client.verifier, client->verifier, sizeof(verifier4));
|
||||
op[0].nfs_argop4_u.opsetclientid.client.id.id_len = strlen(client->id);
|
||||
op[0].nfs_argop4_u.opsetclientid.client.id.id_val = client->id;
|
||||
|
||||
op[0].nfs_argop4_u.opsetclientid.callback.cb_program = NFS4_CALLBACK;
|
||||
|
||||
op[0].nfs_argop4_u.opsetclientid.callback.cb_location.r_netid = netid;
|
||||
op[0].nfs_argop4_u.opsetclientid.callback.cb_location.r_addr = addr;
|
||||
|
||||
op[0].nfs_argop4_u.opsetclientid.callback_ident = 0x00000001;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 SETCLIENTID request\n");
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_getrootfh(struct rpc_context *rpc,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 op[2];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTROOTFH;
|
||||
op[1].argop = OP_GETFH;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 GETROOTFH request\n");
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_open(struct rpc_context *rpc, nfs_fh4 dir, char *path,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 *op;
|
||||
int i = 0, idx = 0;
|
||||
char *tmp;
|
||||
|
||||
printf("OPEN called\n");
|
||||
/*
|
||||
* Count how many directories we have in the path.
|
||||
*/
|
||||
tmp = path;
|
||||
while (tmp = strchr(tmp, '/')) {
|
||||
i++;
|
||||
tmp++;
|
||||
}
|
||||
|
||||
op = malloc(sizeof(nfs_argop4) * (4 + i));
|
||||
memset(op, 0, sizeof(nfs_argop4) * (4 + i));
|
||||
|
||||
op[idx].argop = OP_PUTFH;
|
||||
op[idx].nfs_argop4_u.opputfh.object = dir;
|
||||
idx++;
|
||||
|
||||
while (i-- > 0) {
|
||||
tmp = strchr(path, '/');
|
||||
*tmp++ = '\0';
|
||||
|
||||
op[idx].argop = OP_LOOKUP;
|
||||
op[idx].nfs_argop4_u.oplookup.objname.utf8string_len = strlen(path);
|
||||
op[idx].nfs_argop4_u.oplookup.objname.utf8string_val = path;
|
||||
idx++;
|
||||
|
||||
path = tmp;
|
||||
}
|
||||
|
||||
op[idx].argop = OP_OPEN;
|
||||
op[idx].nfs_argop4_u.opopen.seqid = client->seqid;
|
||||
op[idx].nfs_argop4_u.opopen.share_access = OPEN4_SHARE_ACCESS_READ;
|
||||
op[idx].nfs_argop4_u.opopen.share_deny = OPEN4_SHARE_DENY_NONE;
|
||||
op[idx].nfs_argop4_u.opopen.owner.clientid = client->clientid;
|
||||
op[idx].nfs_argop4_u.opopen.owner.owner.owner_len = strlen(client->owner);
|
||||
op[idx].nfs_argop4_u.opopen.owner.owner.owner_val = client->owner;
|
||||
op[idx].nfs_argop4_u.opopen.openhow.opentype = OPEN4_NOCREATE;
|
||||
op[idx].nfs_argop4_u.opopen.claim.claim = CLAIM_NULL;
|
||||
op[idx].nfs_argop4_u.opopen.claim.open_claim4_u.file.utf8string_len = strlen(path);
|
||||
op[idx].nfs_argop4_u.opopen.claim.open_claim4_u.file.utf8string_val = path;
|
||||
idx++;
|
||||
|
||||
op[idx].argop = OP_GETFH;
|
||||
idx++;
|
||||
|
||||
op[idx].argop = OP_ACCESS;
|
||||
op[idx].nfs_argop4_u.opaccess.access = ACCESS4_READ;
|
||||
|
||||
client->seqid++;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = idx;
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 OPEN request\n");
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_open_confirm(struct rpc_context *rpc, nfs_fh4 object, rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 op[2];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTFH;
|
||||
op[0].nfs_argop4_u.opputfh.object = object;
|
||||
op[1].argop = OP_OPEN_CONFIRM;
|
||||
op[1].nfs_argop4_u.opopen_confirm.open_stateid.seqid = client->seqid;
|
||||
memcpy(op[1].nfs_argop4_u.opopen_confirm.open_stateid.other, client->stateid.other, 12);
|
||||
op[1].nfs_argop4_u.opopen_confirm.seqid = client->seqid;
|
||||
|
||||
client->seqid++;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_read(struct rpc_context *rpc, nfs_fh4 object,
|
||||
uint64_t offset, uint32_t count,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 op[3];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTFH;
|
||||
op[0].nfs_argop4_u.opputfh.object = object;
|
||||
op[1].argop = OP_READ;
|
||||
op[1].nfs_argop4_u.opread.stateid.seqid = client->seqid;
|
||||
memcpy(op[1].nfs_argop4_u.opread.stateid.other, client->stateid.other, 12);
|
||||
op[1].nfs_argop4_u.opread.offset = offset;
|
||||
op[1].nfs_argop4_u.opread.count = count;
|
||||
op[2].argop = OP_GETATTR;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 READ request\n");
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_close(struct rpc_context *rpc, nfs_fh4 object,
|
||||
rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4args args;
|
||||
nfs_argop4 op[2];
|
||||
|
||||
memset(op, 0, sizeof(op));
|
||||
op[0].argop = OP_PUTFH;
|
||||
op[0].nfs_argop4_u.opputfh.object = object;
|
||||
op[1].argop = OP_CLOSE;
|
||||
op[1].nfs_argop4_u.opclose.seqid = client->seqid;
|
||||
op[1].nfs_argop4_u.opclose.open_stateid.seqid = client->seqid;
|
||||
memcpy(op[1].nfs_argop4_u.opclose.open_stateid.other, client->stateid.other, 12);
|
||||
|
||||
client->seqid++;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||
args.argarray.argarray_val = op;
|
||||
|
||||
if (rpc_nfs4_compound_async(rpc, cb, &args, private_data) != 0) {
|
||||
fprintf(stderr, "Failed to send nfs4 CLOSE request\n");
|
||||
exit(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callbacks for completed requests.
|
||||
*/
|
||||
void close_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
|
||||
/*
|
||||
* FINISHED
|
||||
*/
|
||||
/*
|
||||
* Note that we can not start tearing down and destroying the contexts
|
||||
* right here as we are still in a callback from ... rpc_service().
|
||||
* Instead flag that we should abort and start doing the teardown
|
||||
* in client_io once we return from libnfs.
|
||||
*/
|
||||
client->is_finished = 1;
|
||||
}
|
||||
|
||||
void read_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to read file on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to read file on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
write(1, res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.data.data_val, res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.data.data_len);
|
||||
|
||||
/*
|
||||
* Are we at end-of-file? If so we can close the file and exit.
|
||||
*/
|
||||
if (res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.eof) {
|
||||
send_close(rpc, client->fh, close_cb, client);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We still have more data to read.
|
||||
*/
|
||||
client->offset += res->resarray.resarray_val[1].nfs_resop4_u.opread.READ4res_u.resok4.data.data_len;
|
||||
|
||||
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
|
||||
}
|
||||
|
||||
void open_confirm_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to confirm open file on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to confirm open file on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
|
||||
}
|
||||
|
||||
void open_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
int idx;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to open file on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to open file on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/* Find the index for the OPEN opcode */
|
||||
for (idx = 1; idx < res->resarray.resarray_len - 1; idx++) {
|
||||
if ((res->resarray.resarray_val[idx].resop == OP_OPEN) &&
|
||||
(res->resarray.resarray_val[idx + 1].resop == OP_GETFH)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx >= res->resarray.resarray_len - 1) {
|
||||
fprintf(stderr, "No OP_OPEN in server response\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/* Store the open handle in the client structure */
|
||||
client->fh.nfs_fh4_len = res->resarray.resarray_val[idx+1].nfs_resop4_u.opgetfh.GETFH4res_u.resok4.object.nfs_fh4_len;
|
||||
client->fh.nfs_fh4_val = malloc(client->fh.nfs_fh4_len);
|
||||
if (client->fh.nfs_fh4_val == NULL) {
|
||||
fprintf(stderr, "Failed to allocate data for nfs_fh4\n");
|
||||
exit(10);
|
||||
}
|
||||
memcpy(client->fh.nfs_fh4_val, res->resarray.resarray_val[idx+1].nfs_resop4_u.opgetfh.GETFH4res_u.resok4.object.nfs_fh4_val, client->fh.nfs_fh4_len);
|
||||
|
||||
/* Store stateid for the open handle in the client structure */
|
||||
client->stateid.seqid = res->resarray.resarray_val[idx].nfs_resop4_u.opopen.OPEN4res_u.resok4.stateid.seqid;
|
||||
memcpy(client->stateid.other, res->resarray.resarray_val[idx].nfs_resop4_u.opopen.OPEN4res_u.resok4.stateid.other, 12);
|
||||
|
||||
/* Check if server wants us to confirm the open */
|
||||
if (res->resarray.resarray_val[idx].nfs_resop4_u.opopen.OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM) {
|
||||
send_open_confirm(rpc, client->fh, open_confirm_cb, client);
|
||||
return;
|
||||
}
|
||||
|
||||
send_read(rpc, client->fh, client->offset, 4096, read_cb, client);
|
||||
}
|
||||
|
||||
void getrootfh_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to get root filehandle of server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to get root filehandle of server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
send_open(rpc, res->resarray.resarray_val[1].nfs_resop4_u.opgetfh.GETFH4res_u.resok4.object, client->path, open_cb, client);
|
||||
}
|
||||
|
||||
|
||||
void setclientid_confirm_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
char *path;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to set client id of server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to set client id of server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
send_getrootfh(rpc, getrootfh_cb, client);
|
||||
}
|
||||
|
||||
void setclientid_cb(struct rpc_context *rpc, int status, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
COMPOUND4res *res = data;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Failed to set client id on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (res->status != NFS4_OK) {
|
||||
fprintf(stderr, "Failed to set client id on server %s\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
client->clientid = res->resarray.resarray_val[0].nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.resok4.clientid;
|
||||
memcpy(client->setclientid_confirm, res->resarray.resarray_val[0].nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.resok4.setclientid_confirm, NFS4_VERIFIER_SIZE);
|
||||
|
||||
send_setclientid_confirm(rpc, setclientid_confirm_cb, client);
|
||||
}
|
||||
|
||||
/*
|
||||
* NULL procedure for the callback protocol.
|
||||
*/
|
||||
static int cb_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CB_COMPOUND procedure for the callback protocol.
|
||||
* This is where the server will inform us about lease breaks and similar.
|
||||
*/
|
||||
static int cb_compound_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
CB_COMPOUND4args *args = call->body.cbody.args;
|
||||
|
||||
fprintf(stderr, "cb_compund_cb. Do something here.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct service_proc pt[] = {
|
||||
{CB_NULL, cb_null_proc,
|
||||
(zdrproc_t)zdr_void, 0},
|
||||
{CB_COMPOUND, cb_compound_proc,
|
||||
(zdrproc_t)zdr_CB_COMPOUND4args, sizeof(CB_COMPOUND4args)},
|
||||
};
|
||||
|
||||
/*
|
||||
* This callback is invoked when others (the nfsv4 server) initiates a
|
||||
* NFSv4 CALLBACK sessions to us.
|
||||
* We accept() the connection and create a local rpc server context
|
||||
* for the callback protocol.
|
||||
*/
|
||||
static void client_accept(evutil_socket_t s, short events, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
struct server *server;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
int fd;
|
||||
|
||||
server = malloc(sizeof(struct server));
|
||||
if (server == NULL) {
|
||||
fprintf(stderr, "failed to malloc server structure\n");
|
||||
exit(10);
|
||||
}
|
||||
memset(server, 0, sizeof(*server));
|
||||
server->next = server_list;
|
||||
server_list = server;
|
||||
|
||||
if ((fd = accept(s, (struct sockaddr *)&ss, &len)) < 0) {
|
||||
free_server(server);
|
||||
fprintf(stderr, "accept failed\n");
|
||||
exit(10);
|
||||
}
|
||||
evutil_make_socket_nonblocking(fd);
|
||||
|
||||
server->rpc = rpc_init_server_context(fd);
|
||||
if (server->rpc == NULL) {
|
||||
free_server(server);
|
||||
fprintf(stderr, "Failed to create server rpc context\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
rpc_register_service(server->rpc, NFS4_CALLBACK, NFS_CB,
|
||||
pt, sizeof(pt) / sizeof(pt[0]));
|
||||
|
||||
server->read_event = event_new(base, fd, EV_READ|EV_PERSIST,
|
||||
server_io, server);
|
||||
server->write_event = event_new(base, fd, EV_WRITE|EV_PERSIST,
|
||||
server_io, server);
|
||||
update_events(server->rpc, server->read_event, server->write_event);
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback is invoked when our async connect() to the server has
|
||||
* completed. At this point we know which IP address was used locally for
|
||||
* the connection and can bind our nfsv4 callback server instance to it.
|
||||
*/
|
||||
void connect_cb(struct rpc_context *rpc, int status, void *data _U_,
|
||||
void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
struct sockaddr_in *in;
|
||||
struct sockaddr_in6 *in6;
|
||||
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "connection to NFSv4 server %s failed\n",
|
||||
client->server);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* NFSv4 CALLBACK
|
||||
* Now that we have a client connection we can register a callback
|
||||
* server port on the same IP address as was used to the outgoing
|
||||
* client connection. That way we know that the address used by the
|
||||
* server is routable, and uses the same version of ip, that the client
|
||||
* supports and can route to.
|
||||
*/
|
||||
if (getsockname(rpc_get_fd(rpc), (struct sockaddr *)&ss, &len) < 0) {
|
||||
fprintf(stderr, "getsockaddr failed\n");
|
||||
exit(10);
|
||||
}
|
||||
switch (ss.ss_family) {
|
||||
case AF_INET:
|
||||
in = (struct sockaddr_in *)&ss;
|
||||
in->sin_port=0;
|
||||
break;
|
||||
case AF_INET6:
|
||||
in6 = (struct sockaddr_in6 *)&ss;
|
||||
in6->sin6_port=0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Can not handle AF_FAMILY:%d", ss.ss_family);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
client->callback_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (client->callback_fd == -1) {
|
||||
fprintf(stderr, "Failed to create callback socket\n");
|
||||
exit(10);
|
||||
}
|
||||
evutil_make_socket_nonblocking(client->callback_fd);
|
||||
|
||||
if (bind(client->callback_fd, (struct sockaddr *)&ss, sizeof(ss)) < 0) {
|
||||
fprintf(stderr, "Failed to bind callback socket\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (listen(client->callback_fd, 16) < 0) {
|
||||
fprintf(stderr, "failed to listen to callback socket\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
client->listen_event = event_new(base,
|
||||
client->callback_fd,
|
||||
EV_READ|EV_PERSIST,
|
||||
client_accept, private_data);
|
||||
event_add(client->listen_event, NULL);
|
||||
|
||||
|
||||
/*
|
||||
* Now that we are finished setting up the callback server port
|
||||
* we can proceed and negotiate the nfsv4 client id.
|
||||
*/
|
||||
send_setclientid(rpc, setclientid_cb, client);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct nfs_context *nfs;
|
||||
struct nfs_url *url;
|
||||
struct client client;
|
||||
int i, fd;
|
||||
|
||||
#ifdef WIN32
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
|
||||
fprintf(stderr, "Failed to start Winsock2\n");
|
||||
exit(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
aros_init_socket();
|
||||
#endif
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
base = event_base_new();
|
||||
if (base == NULL) {
|
||||
fprintf(stderr, "Failed create event context\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
nfs = nfs_init_context();
|
||||
if (nfs == NULL) {
|
||||
fprintf(stderr, "failed to init context\n");
|
||||
exit(10);
|
||||
}
|
||||
url = nfs_parse_url_dir(nfs, argv[1]);
|
||||
if (url == NULL) {
|
||||
fprintf(stderr, "failed to parse url\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
memset(&client, 0, sizeof(client));
|
||||
client.rpc = nfs_get_rpc_context(nfs);
|
||||
client.is_finished = 0;
|
||||
client.server = url->server;
|
||||
client.path = &url->path[1]; // skip leading '/'
|
||||
srandom(time(NULL));
|
||||
for (i = 0; i < NFS4_VERIFIER_SIZE; i++) {
|
||||
client.verifier[i] = random() & 0xff;
|
||||
}
|
||||
asprintf(&client.id, "Libnfs %s tcp pid:%d", argv[1], getpid());
|
||||
asprintf(&client.owner, "open id:libnfs pid:%d", getpid());
|
||||
client.callback_fd = -1;
|
||||
|
||||
if (rpc_connect_program_async(client.rpc, url->server,
|
||||
NFS4_PROGRAM, NFS_V4,
|
||||
connect_cb, &client) != 0) {
|
||||
fprintf(stderr, "Failed to start connection\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the events we need for the outgoing client RPC channel.
|
||||
*/
|
||||
fd = rpc_get_fd(client.rpc);
|
||||
client.read_event = event_new(base, fd, EV_READ|EV_PERSIST,
|
||||
client_io, &client);
|
||||
client.write_event = event_new(base, fd, EV_WRITE|EV_PERSIST,
|
||||
client_io, &client);
|
||||
update_events(client.rpc, client.read_event, client.write_event);
|
||||
|
||||
/*
|
||||
* Main event loop.
|
||||
*/
|
||||
event_base_dispatch(base);
|
||||
|
||||
/*
|
||||
* Finished cleanly, lets deallocate all resrouces we were using.
|
||||
*/
|
||||
/*
|
||||
* Close the listening socket.
|
||||
*/
|
||||
close(client.callback_fd);
|
||||
|
||||
/*
|
||||
* Destroy the client context.
|
||||
*/
|
||||
free(client.id);
|
||||
free(client.owner);
|
||||
free(client.fh.nfs_fh4_val);
|
||||
|
||||
/*
|
||||
* Destroy all server contexts
|
||||
*/
|
||||
while (server_list) {
|
||||
struct server *server = server_list;
|
||||
|
||||
server_list = server->next;
|
||||
free_server(server);
|
||||
}
|
||||
|
||||
nfs_destroy_url(url);
|
||||
/*
|
||||
* This will implicitly close the rpc context and also destroy it.
|
||||
*/
|
||||
nfs_destroy_context(nfs);
|
||||
|
||||
event_base_free(base);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -128,6 +128,46 @@ void pmap3_getaddr_cb(struct rpc_context *rpc, int status, void *data, void *pri
|
|||
client->is_finished = 1;
|
||||
}
|
||||
|
||||
void pmap2_set_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
uint32_t res = *(uint32_t *)data;
|
||||
|
||||
if (status == RPC_STATUS_ERROR) {
|
||||
printf("PORTMAP2/SET call failed with \"%s\"\n", (char *)data);
|
||||
exit(10);
|
||||
}
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
printf("PORTMAP2/SET call failed, status:%d\n", status);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
printf("PORTMAP2/SET:\n");
|
||||
printf(" Res:%d\n", res);
|
||||
|
||||
client->is_finished = 1;
|
||||
}
|
||||
|
||||
void pmap2_unset_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
uint32_t res = *(uint32_t *)data;
|
||||
|
||||
if (status == RPC_STATUS_ERROR) {
|
||||
printf("PORTMAP2/UNSET call failed with \"%s\"\n", (char *)data);
|
||||
exit(10);
|
||||
}
|
||||
if (status != RPC_STATUS_SUCCESS) {
|
||||
printf("PORTMAP2/UNSET call failed, status:%d\n", status);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
printf("PORTMAP2/UNSET:\n");
|
||||
printf(" Res:%d\n", res);
|
||||
|
||||
client->is_finished = 1;
|
||||
}
|
||||
|
||||
void pmap3_set_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
|
||||
{
|
||||
struct client *client = private_data;
|
||||
|
@ -329,6 +369,8 @@ int main(int argc _U_, char *argv[] _U_)
|
|||
int null2 = 0;
|
||||
int dump2 = 0;
|
||||
int null3 = 0;
|
||||
int set2 = 0;
|
||||
int unset2 = 0;
|
||||
int set3 = 0;
|
||||
int unset3 = 0;
|
||||
int getaddr3 = 0;
|
||||
|
@ -337,6 +379,8 @@ int main(int argc _U_, char *argv[] _U_)
|
|||
int u2t3 = 0;
|
||||
int command_found = 0;
|
||||
|
||||
int set2prog, set2vers, set2prot, set2port;
|
||||
int unset2prog, unset2vers, unset2prot, unset2port;
|
||||
int set3prog, set3vers;
|
||||
char *set3netid, *set3addr, *set3owner;
|
||||
int unset3prog, unset3vers;
|
||||
|
@ -365,6 +409,20 @@ int main(int argc _U_, char *argv[] _U_)
|
|||
} else if (!strcmp(argv[i], "null2")) {
|
||||
null2 = 1;
|
||||
command_found++;
|
||||
} else if (!strcmp(argv[i], "set2")) {
|
||||
set2 = 1;
|
||||
set2prog = atoi(argv[++i]);
|
||||
set2vers = atoi(argv[++i]);
|
||||
set2prot = atoi(argv[++i]);
|
||||
set2port = atoi(argv[++i]);
|
||||
command_found++;
|
||||
} else if (!strcmp(argv[i], "unset2")) {
|
||||
unset2 = 1;
|
||||
unset2prog = atoi(argv[++i]);
|
||||
unset2vers = atoi(argv[++i]);
|
||||
unset2prot = atoi(argv[++i]);
|
||||
unset2port = atoi(argv[++i]);
|
||||
command_found++;
|
||||
} else if (!strcmp(argv[i], "dump3")) {
|
||||
dump3 = 1;
|
||||
command_found++;
|
||||
|
@ -465,6 +523,20 @@ int main(int argc _U_, char *argv[] _U_)
|
|||
}
|
||||
wait_until_finished(rpc, &client);
|
||||
}
|
||||
if (set2) {
|
||||
if (rpc_pmap2_set_async(rpc, set2prog, set2vers, set2prot, set2port, pmap2_set_cb, &client) != 0) {
|
||||
printf("Failed to send SET2 request\n");
|
||||
exit(10);
|
||||
}
|
||||
wait_until_finished(rpc, &client);
|
||||
}
|
||||
if (unset2) {
|
||||
if (rpc_pmap2_unset_async(rpc, unset2prog, unset2vers, unset2prot, unset2port, pmap2_unset_cb, &client) != 0) {
|
||||
printf("Failed to send UNSET2 request\n");
|
||||
exit(10);
|
||||
}
|
||||
wait_until_finished(rpc, &client);
|
||||
}
|
||||
if (set3) {
|
||||
struct pmap3_mapping map;
|
||||
|
||||
|
|
|
@ -0,0 +1,703 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2015
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This is a very incomplete portmapper that only implements
|
||||
* a subset of version 2 and threee of the protocol.
|
||||
* A proper portmapper needs to implement these two versions fully
|
||||
* as well as version 4.
|
||||
*
|
||||
* See this as an example of how to build a simple RPC service
|
||||
* that supports both UDP and TCP using libnfs.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
#include "aros_compat.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32_compat.h"
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
WSADATA wsaData;
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include "libnfs.h"
|
||||
#include "libnfs-raw.h"
|
||||
#include "libnfs-raw-portmap.h"
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
struct event_base *base;
|
||||
|
||||
struct server {
|
||||
struct rpc_context *rpc;
|
||||
struct event *read_event;
|
||||
struct event *write_event;
|
||||
};
|
||||
|
||||
/* Socket where we listen for incomming rpc connections */
|
||||
struct event *listen_event;
|
||||
int listen_socket = -1;
|
||||
|
||||
/* Socket used for UDP server */
|
||||
struct server udp_server;
|
||||
int udp_socket = -1;
|
||||
|
||||
struct mapping {
|
||||
struct mapping *next;
|
||||
u_int prog;
|
||||
u_int vers;
|
||||
int port;
|
||||
char *netid;
|
||||
char *addr;
|
||||
char *owner;
|
||||
};
|
||||
struct mapping *map;
|
||||
|
||||
|
||||
void free_map_item(struct mapping *item)
|
||||
{
|
||||
free(item->netid);
|
||||
free(item->addr);
|
||||
free(item->owner);
|
||||
free(item);
|
||||
}
|
||||
|
||||
static void free_server(struct server *server)
|
||||
{
|
||||
if (server->rpc) {
|
||||
rpc_disconnect(server->rpc, NULL);
|
||||
rpc_destroy_context(server->rpc);
|
||||
}
|
||||
if (server->read_event) {
|
||||
event_free(server->read_event);
|
||||
}
|
||||
if (server->write_event) {
|
||||
event_free(server->write_event);
|
||||
}
|
||||
|
||||
free(server);
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on the state of libnfs and its context, update libevent
|
||||
* accordingly regarding which events we are interested in.
|
||||
*/
|
||||
static void update_events(struct rpc_context *rpc, struct event *read_event,
|
||||
struct event *write_event)
|
||||
{
|
||||
int events = rpc_which_events(rpc);
|
||||
|
||||
if (read_event) {
|
||||
if (events & POLLIN) {
|
||||
event_add(read_event, NULL);
|
||||
} else {
|
||||
event_del(read_event);
|
||||
}
|
||||
}
|
||||
if (write_event) {
|
||||
if (events & POLLOUT) {
|
||||
event_add(write_event, NULL);
|
||||
} else {
|
||||
event_del(write_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a registration for program,version,netid.
|
||||
*/
|
||||
int pmap_register(int prog, int vers, char *netid, char *addr,
|
||||
char *owner)
|
||||
{
|
||||
struct mapping *item;
|
||||
char *str;
|
||||
int count = 0;
|
||||
|
||||
item = malloc(sizeof(struct mapping));
|
||||
item->prog = prog;
|
||||
item->vers = vers;
|
||||
item->netid = netid;
|
||||
item->addr = addr;
|
||||
item->owner = owner;
|
||||
|
||||
/* The port are the last two dotted decimal fields in the address */
|
||||
for (str = item->addr + strlen(item->addr) - 1; str >= item->addr; str--) {
|
||||
if (*str != '.') {
|
||||
if (*str < '0' || *str > '9') {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count == 2) {
|
||||
int high, low;
|
||||
|
||||
sscanf(str, ".%d.%d", &high, &low);
|
||||
item->port = high * 256 + low;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item->next = map;
|
||||
map = item;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and return a registration matching program,version,netid.
|
||||
*/
|
||||
struct mapping *map_lookup(int prog, int vers, char *netid)
|
||||
{
|
||||
struct mapping *tmp;
|
||||
|
||||
for (tmp = map; tmp; tmp = tmp->next) {
|
||||
if (tmp->prog != prog) {
|
||||
continue;
|
||||
}
|
||||
if (tmp->vers != vers) {
|
||||
continue;
|
||||
}
|
||||
if (strcmp(tmp->netid, netid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a registration from our map or registrations.
|
||||
*/
|
||||
void map_remove(int prog, int vers, char *netid)
|
||||
{
|
||||
struct mapping *prev = NULL;
|
||||
struct mapping *tmp;
|
||||
|
||||
for (tmp = map; tmp; prev = tmp, tmp = tmp->next) {
|
||||
if (tmp->prog != prog) {
|
||||
continue;
|
||||
}
|
||||
if (tmp->vers != vers) {
|
||||
continue;
|
||||
}
|
||||
if (strcmp(tmp->netid, netid)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (tmp == NULL) {
|
||||
return;
|
||||
}
|
||||
if (prev) {
|
||||
prev->next = tmp->next;
|
||||
} else {
|
||||
map = tmp->next;
|
||||
}
|
||||
|
||||
free_map_item(tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NULL procedure. All protocols/versions must provide a NULL procedure
|
||||
* as index 0.
|
||||
* It is used by clients, and rpcinfo, to "ping" a service and verify that
|
||||
* the service is available and that it does support the indicated version.
|
||||
*/
|
||||
static int pmap2_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* v2 GETPORT.
|
||||
* This is the lookup function for portmapper version 2.
|
||||
* A client provides program, version and protocol (tcp or udp)
|
||||
* and portmapper returns which port that service is available on,
|
||||
* (or 0 if no such program is registered.)
|
||||
*/
|
||||
static int pmap2_getport_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
PMAP2GETPORTargs *args = call->body.cbody.args;
|
||||
struct mapping *tmp;
|
||||
char *netid;
|
||||
uint32_t port = 0;
|
||||
|
||||
if (args->prot == IPPROTO_TCP) {
|
||||
netid = "tcp";
|
||||
} else {
|
||||
netid = "udp";
|
||||
}
|
||||
|
||||
tmp = map_lookup(args->prog, args->vers, netid);
|
||||
if (tmp) {
|
||||
port = tmp->port;
|
||||
}
|
||||
|
||||
rpc_send_reply(rpc, call, &port, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* v2 DUMP.
|
||||
* This RPC returns a list of all endpoints that are registered with
|
||||
* portmapper.
|
||||
*/
|
||||
static int pmap2_dump_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
PMAP2DUMPres reply;
|
||||
struct mapping *tmp;
|
||||
|
||||
reply.list = NULL;
|
||||
for (tmp = map; tmp; tmp = tmp->next) {
|
||||
struct pmap2_mapping_list *tmp_list;
|
||||
int proto;
|
||||
|
||||
/* pmap2 only support ipv4 */
|
||||
if (!strcmp(tmp->netid, "tcp")) {
|
||||
proto = IPPROTO_TCP;
|
||||
} else if (!strcmp(tmp->netid, "udp")) {
|
||||
proto = IPPROTO_UDP;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp_list = malloc(sizeof(struct pmap2_mapping_list));
|
||||
tmp_list->map.prog = tmp->prog;
|
||||
tmp_list->map.vers = tmp->vers;
|
||||
tmp_list->map.prot = proto;
|
||||
tmp_list->map.port = tmp->port;
|
||||
|
||||
tmp_list->next = reply.list;
|
||||
|
||||
reply.list = tmp_list;
|
||||
}
|
||||
|
||||
rpc_send_reply(rpc, call, &reply,
|
||||
(zdrproc_t)zdr_PMAP2DUMPres, sizeof(PMAP2DUMPres));
|
||||
|
||||
while (reply.list) {
|
||||
struct pmap2_mapping_list *tmp_list = reply.list->next;
|
||||
free(reply.list);
|
||||
reply.list = tmp_list;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* v2 SET
|
||||
* This procedure is used to register and endpoint with portmapper.
|
||||
*/
|
||||
static int pmap2_set_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
PMAP2GETPORTargs *args = call->body.cbody.args;
|
||||
char *prot;
|
||||
char *addr;
|
||||
uint32_t response = 1;
|
||||
|
||||
if (args->prot == IPPROTO_TCP) {
|
||||
prot = "tcp";
|
||||
} else {
|
||||
prot = "udp";
|
||||
}
|
||||
|
||||
/* Don't update if we already have a mapping */
|
||||
if (map_lookup(args->prog, args->vers, prot)) {
|
||||
response = 0;
|
||||
rpc_send_reply(rpc, call, &response, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
asprintf(&addr, "0.0.0.0.%d.%d", args->port >> 8, args->port & 0xff);
|
||||
pmap_register(args->prog, args->vers, strdup(prot), addr,
|
||||
strdup("<unknown>"));
|
||||
|
||||
rpc_send_reply(rpc, call, &response, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* v2 UNSET
|
||||
* This procedure is used to remove a registration from portmappers
|
||||
* list of endpoints.
|
||||
*/
|
||||
static int pmap2_unset_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
PMAP2GETPORTargs *args = call->body.cbody.args;
|
||||
char *prot;
|
||||
char *addr;
|
||||
uint32_t response = 1;
|
||||
|
||||
if (args->prot == IPPROTO_TCP) {
|
||||
prot = "tcp";
|
||||
} else {
|
||||
prot = "udp";
|
||||
}
|
||||
|
||||
map_remove(args->prog, args->vers, prot);
|
||||
|
||||
rpc_send_reply(rpc, call, &response, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Service table for portmapper v2.
|
||||
*
|
||||
* Service management is table driven in libnfsand this is the table
|
||||
* that defines which procedures we implement for portmapper v2.
|
||||
* If clients try to connect to the not-yet-implemented procedures here
|
||||
* libnfs will automatically respond with an RPC layer error that flags
|
||||
* PROCEDURE UNAVAILABLE.
|
||||
*
|
||||
* This table contains the procedure number, the callback function to implement
|
||||
* this procedure, the unmarshalling function that libnfs should use to unppack
|
||||
* the client payload as well as its size.
|
||||
*
|
||||
* Version 2 does not support ipv6 so this version of portmapper is
|
||||
* not too commonly used any more.
|
||||
*/
|
||||
struct service_proc pmap2_pt[] = {
|
||||
{PMAP2_NULL, pmap2_null_proc,
|
||||
(zdrproc_t)zdr_void, 0},
|
||||
{PMAP2_SET, pmap2_set_proc,
|
||||
(zdrproc_t)zdr_PMAP2SETargs, sizeof(PMAP2SETargs)},
|
||||
{PMAP2_UNSET, pmap2_unset_proc,
|
||||
(zdrproc_t)zdr_PMAP2UNSETargs, sizeof(PMAP2UNSETargs)},
|
||||
{PMAP2_GETPORT, pmap2_getport_proc,
|
||||
(zdrproc_t)zdr_PMAP2GETPORTargs, sizeof(PMAP2GETPORTargs)},
|
||||
{PMAP2_DUMP, pmap2_dump_proc,
|
||||
(zdrproc_t)zdr_void, 0},
|
||||
//{PMAP2_CALLIT, pmap2_...},
|
||||
};
|
||||
|
||||
/*
|
||||
* The NULL procedure. All protocols/versions must provide a NULL procedure
|
||||
* as index 0.
|
||||
* It is used by clients, and rpcinfo, to "ping" a service and verify that
|
||||
* the service is available and that it does support the indicated version.
|
||||
*/
|
||||
static int pmap3_null_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* v3 DUMP.
|
||||
* This RPC returns a list of all endpoints that are registered with
|
||||
* portmapper.
|
||||
*/
|
||||
static int pmap3_dump_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
{
|
||||
PMAP3DUMPres reply;
|
||||
struct mapping *tmp;
|
||||
|
||||
reply.list = NULL;
|
||||
for (tmp = map; tmp; tmp = tmp->next) {
|
||||
struct pmap3_mapping_list *tmp_list;
|
||||
|
||||
tmp_list = malloc(sizeof(struct pmap3_mapping_list));
|
||||
tmp_list->map.prog = tmp->prog;
|
||||
tmp_list->map.vers = tmp->vers;
|
||||
tmp_list->map.netid = tmp->netid;
|
||||
tmp_list->map.addr = tmp->addr;
|
||||
tmp_list->map.owner = tmp->owner;
|
||||
|
||||
tmp_list->next = reply.list;
|
||||
|
||||
reply.list = tmp_list;
|
||||
}
|
||||
|
||||
rpc_send_reply(rpc, call, &reply,
|
||||
(zdrproc_t)zdr_PMAP3DUMPres, sizeof(PMAP3DUMPres));
|
||||
|
||||
while (reply.list) {
|
||||
struct pmap3_mapping_list *tmp_list = reply.list->next;
|
||||
free(reply.list);
|
||||
reply.list = tmp_list;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Service table for portmapper v3.
|
||||
*
|
||||
* Service management is table driven in libnfsand this is the table
|
||||
* that defines which procedures we implement for portmapper v3.
|
||||
* If clients try to connect to the not-yet-implemented procedures here
|
||||
* libnfs will automatically respond with an RPC layer error that flags
|
||||
* PROCEDURE UNAVAILABLE.
|
||||
*
|
||||
* This table contains the procedure number, the callback function to implement
|
||||
* this procedure, the unmarshalling function that libnfs should use to unppack
|
||||
* the client payload as well as its size.
|
||||
*/
|
||||
struct service_proc pmap3_pt[] = {
|
||||
{PMAP3_NULL, pmap3_null_proc,
|
||||
(zdrproc_t)zdr_void, 0},
|
||||
//{PMAP3_SET, pmap3_...},
|
||||
//{PMAP3_UNSET, pmap3_...},
|
||||
//{PMAP3_GETADDR, pmap3_...},
|
||||
{PMAP3_DUMP, pmap3_dump_proc,
|
||||
(zdrproc_t)zdr_void, 0},
|
||||
//{PMAP3_CALLIT, pmap3_...},
|
||||
//{PMAP3_GETTIME, pmap3_...},
|
||||
//{PMAP3_UADDR2TADDR, pmap3_...},
|
||||
//{PMAP3_TADDR2UADDR, pmap3_...},
|
||||
};
|
||||
|
||||
/*
|
||||
* This callback is invoked from the event system when an event we are waiting
|
||||
* for has become active.
|
||||
*/
|
||||
static void server_io(evutil_socket_t fd, short events, void *private_data)
|
||||
{
|
||||
struct server *server = private_data;
|
||||
int revents = 0;
|
||||
|
||||
/*
|
||||
* Translate the libevent read/write flags to the corresponding
|
||||
* flags that libnfs uses.
|
||||
*/
|
||||
if (events & EV_READ) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if (events & EV_WRITE) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let libnfs process the event.
|
||||
*/
|
||||
if (rpc_service(server->rpc, revents) < 0) {
|
||||
free_server(server);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update which events we are interested in. It might have changed
|
||||
* for example if we no longer have any data pending to send
|
||||
* we no longer need to wait for the socket to become writeable.
|
||||
*/
|
||||
update_events(server->rpc, server->read_event, server->write_event);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This callback is invoked when we have a client connecting to our TCP
|
||||
* port.
|
||||
*/
|
||||
static void do_accept(evutil_socket_t s, short events, void *private_data)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
struct server *server;
|
||||
int fd;
|
||||
|
||||
server = malloc(sizeof(struct server));
|
||||
if (server == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(server, 0, sizeof(*server));
|
||||
|
||||
if ((fd = accept(s, (struct sockaddr *)&ss, &len)) < 0) {
|
||||
free_server(server);
|
||||
return;
|
||||
}
|
||||
evutil_make_socket_nonblocking(fd);
|
||||
|
||||
server->rpc = rpc_init_server_context(fd);
|
||||
if (server->rpc == NULL) {
|
||||
close(fd);
|
||||
free_server(server);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register both v2 and v3 of the protocol to the new
|
||||
* server context.
|
||||
*/
|
||||
rpc_register_service(server->rpc, PMAP_PROGRAM, PMAP_V2,
|
||||
pmap2_pt, sizeof(pmap2_pt) / sizeof(pmap2_pt[0]));
|
||||
rpc_register_service(server->rpc, PMAP_PROGRAM, PMAP_V3,
|
||||
pmap3_pt, sizeof(pmap3_pt) / sizeof(pmap3_pt[0]));
|
||||
|
||||
/*
|
||||
* Create events for read and write for this new server instance.
|
||||
*/
|
||||
server->read_event = event_new(base, fd, EV_READ|EV_PERSIST,
|
||||
server_io, server);
|
||||
server->write_event = event_new(base, fd, EV_WRITE|EV_PERSIST,
|
||||
server_io, server);
|
||||
update_events(server->rpc, server->read_event, server->write_event);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_in in;
|
||||
int one = 1;
|
||||
|
||||
#ifdef WIN32
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
|
||||
printf("Failed to start Winsock2\n");
|
||||
return 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AROS
|
||||
aros_init_socket();
|
||||
#endif
|
||||
|
||||
base = event_base_new();
|
||||
if (base == NULL) {
|
||||
printf("Failed create event context\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Portmapper listens on port 111, any address.
|
||||
* Just initialize it for now as we will need it several times below.
|
||||
*/
|
||||
in.sin_family = AF_INET;
|
||||
in.sin_port = htons(111);
|
||||
in.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||
|
||||
|
||||
/* This is the portmapper protocol itself which we obviously
|
||||
* support.
|
||||
*/
|
||||
pmap_register(100000, 2, strdup("tcp"), strdup("0.0.0.0.0.111"),
|
||||
strdup("portmapper-service"));
|
||||
pmap_register(100000, 2, strdup("udp"), strdup("0.0.0.0.0.111"),
|
||||
strdup("portmapper-service"));
|
||||
pmap_register(100000, 3, strdup("tcp"), strdup("0.0.0.0.0.111"),
|
||||
strdup("portmapper-service"));
|
||||
pmap_register(100000, 3, strdup("udp"), strdup("0.0.0.0.0.111"),
|
||||
strdup("portmapper-service"));
|
||||
|
||||
|
||||
/*
|
||||
* TCP: Set up a listening socket for incoming TCP connections.
|
||||
* Once clients connect, inside do_accept() we will create a proper
|
||||
* libnfs server context for each connection.
|
||||
*/
|
||||
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listen_socket == -1) {
|
||||
printf("Failed to create listening socket\n");
|
||||
exit(10);
|
||||
}
|
||||
evutil_make_socket_nonblocking(listen_socket);
|
||||
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
|
||||
if (bind(listen_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
|
||||
printf("Failed to bind listening socket\n");
|
||||
exit(10);
|
||||
}
|
||||
if (listen(listen_socket, 16) < 0) {
|
||||
printf("failed to listen to socket\n");
|
||||
exit(10);
|
||||
}
|
||||
listen_event = event_new(base,
|
||||
listen_socket,
|
||||
EV_READ|EV_PERSIST,
|
||||
do_accept, NULL);
|
||||
event_add(listen_event, NULL);
|
||||
|
||||
|
||||
/*
|
||||
* UDP: Create and bind to the socket we want to use for the UDP server.
|
||||
*/
|
||||
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (udp_socket == -1) {
|
||||
printf("Failed to create udp socket\n");
|
||||
exit(10);
|
||||
}
|
||||
evutil_make_socket_nonblocking(udp_socket);
|
||||
setsockopt(udp_socket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
|
||||
if (bind(udp_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
|
||||
printf("Failed to bind udp socket\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* UDP: Create a libnfs server context for this socket.
|
||||
*/
|
||||
memset(&udp_server, 0, sizeof(udp_server));
|
||||
udp_server.rpc = rpc_init_server_context(udp_socket);
|
||||
|
||||
/*
|
||||
* UDP: Register both v2 and v3 of the protocol to the
|
||||
* UDP server context.
|
||||
*/
|
||||
rpc_register_service(udp_server.rpc, PMAP_PROGRAM, PMAP_V2,
|
||||
pmap2_pt, sizeof(pmap2_pt) / sizeof(pmap2_pt[0]));
|
||||
rpc_register_service(udp_server.rpc, PMAP_PROGRAM, PMAP_V3,
|
||||
pmap3_pt, sizeof(pmap3_pt) / sizeof(pmap3_pt[0]));
|
||||
|
||||
udp_server.read_event = event_new(base,
|
||||
udp_socket,
|
||||
EV_READ|EV_PERSIST,
|
||||
server_io, &udp_server);
|
||||
event_add(udp_server.read_event, NULL);
|
||||
|
||||
|
||||
/*
|
||||
* Everything is now set up. Start the event loop.
|
||||
*/
|
||||
event_base_dispatch(base);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -6,6 +6,7 @@ dist_nfsc_HEADERS = \
|
|||
../mount/libnfs-raw-mount.h \
|
||||
../portmap/libnfs-raw-portmap.h \
|
||||
../nfs/libnfs-raw-nfs.h \
|
||||
../nfs4/libnfs-raw-nfs4.h \
|
||||
../nlm/libnfs-raw-nlm.h \
|
||||
../nsm/libnfs-raw-nsm.h \
|
||||
../rquota/libnfs-raw-rquota.h
|
||||
|
|
|
@ -93,11 +93,20 @@ struct rpc_queue {
|
|||
#define ZDR_ENCODE_OVERHEAD 1024
|
||||
#define ZDR_ENCODEBUF_MINSIZE 4096
|
||||
|
||||
struct rpc_endpoint {
|
||||
struct rpc_endpoint *next;
|
||||
int program;
|
||||
int version;
|
||||
struct service_proc *procs;
|
||||
int num_procs;
|
||||
};
|
||||
|
||||
struct rpc_context {
|
||||
uint32_t magic;
|
||||
int fd;
|
||||
int old_fd;
|
||||
int is_connected;
|
||||
int is_nonblocking;
|
||||
|
||||
char *error_string;
|
||||
|
||||
|
@ -110,19 +119,21 @@ struct rpc_context {
|
|||
struct rpc_queue outqueue;
|
||||
struct sockaddr_storage udp_src;
|
||||
struct rpc_queue waitpdu[HASHES];
|
||||
uint32_t waitpdu_len;
|
||||
|
||||
uint32_t inpos;
|
||||
uint32_t insize;
|
||||
char rm_buf[4];
|
||||
char *inbuf;
|
||||
|
||||
/* special fields for UDP, which can sometimes be BROADCASTed */
|
||||
int is_udp;
|
||||
struct sockaddr *udp_dest;
|
||||
struct sockaddr_storage udp_dest;
|
||||
int is_broadcast;
|
||||
|
||||
/* track the address we connect to so we can auto-reconnect on session failure */
|
||||
struct sockaddr_storage s;
|
||||
int auto_reconnect;
|
||||
int auto_reconnect_retries;
|
||||
|
||||
/* fragment reassembly */
|
||||
struct rpc_fragment *fragments;
|
||||
|
@ -137,6 +148,10 @@ struct rpc_context {
|
|||
int debug;
|
||||
int timeout;
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
/* Is a server context ? */
|
||||
int is_server_context;
|
||||
struct rpc_endpoint *endpoints;
|
||||
};
|
||||
|
||||
struct rpc_pdu {
|
||||
|
@ -155,6 +170,11 @@ struct rpc_pdu {
|
|||
zdrproc_t zdr_decode_fn;
|
||||
caddr_t zdr_decode_buf;
|
||||
uint32_t zdr_decode_bufsize;
|
||||
|
||||
#define PDU_DISCARD_AFTER_SENDING 0x00000001
|
||||
uint32_t flags;
|
||||
|
||||
time_t timeout;
|
||||
};
|
||||
|
||||
void rpc_reset_queue(struct rpc_queue *q);
|
||||
|
@ -204,8 +224,6 @@ void rpc_unset_autoreconnect(struct rpc_context *rpc);
|
|||
void rpc_set_interface(struct rpc_context *rpc, const char *ifname);
|
||||
|
||||
void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v);
|
||||
void rpc_set_uid(struct rpc_context *rpc, int uid);
|
||||
void rpc_set_gid(struct rpc_context *rpc, int gid);
|
||||
void rpc_set_pagecache(struct rpc_context *rpc, uint32_t v);
|
||||
void rpc_set_pagecache_ttl(struct rpc_context *rpc, uint32_t v);
|
||||
void rpc_set_readahead(struct rpc_context *rpc, uint32_t v);
|
||||
|
@ -214,9 +232,12 @@ void rpc_set_timeout(struct rpc_context *rpc, int timeout);
|
|||
int rpc_get_timeout(struct rpc_context *rpc);
|
||||
int rpc_add_fragment(struct rpc_context *rpc, char *data, uint32_t size);
|
||||
void rpc_free_all_fragments(struct rpc_context *rpc);
|
||||
int rpc_is_udp_socket(struct rpc_context *rpc);
|
||||
|
||||
const struct nfs_fh3 *nfs_get_rootfh(struct nfs_context *nfs);
|
||||
|
||||
void *zdr_malloc(ZDR *zdrs, uint32_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
|
||||
|
@ -70,6 +71,63 @@ int rpc_service(struct rpc_context *rpc, int revents);
|
|||
*/
|
||||
int rpc_queue_length(struct rpc_context *rpc);
|
||||
|
||||
/*
|
||||
* Set which UID/GID to use in the authenticator.
|
||||
* By default libnfs will use getuid()/getgid() where available
|
||||
* and 65534/65534 where not.
|
||||
*/
|
||||
void rpc_set_uid(struct rpc_context *rpc, int uid);
|
||||
void rpc_set_gid(struct rpc_context *rpc, int gid);
|
||||
|
||||
/*
|
||||
* Create a server context.
|
||||
*/
|
||||
struct rpc_context *rpc_init_server_context(int s);
|
||||
|
||||
/* This is the callback functions for server contexts.
|
||||
* These are invoked from the library when a CALL has been received and a
|
||||
* service procedure has been found that matches the rpc
|
||||
* program/version/procedure.
|
||||
*
|
||||
* The rpc arguments are stored in call->body.cbody.args;
|
||||
* Example:
|
||||
* static int pmap2_getport_proc(struct rpc_context *rpc, struct rpc_msg *call)
|
||||
* {
|
||||
* pmap2_mapping *args = call->body.cbody.args;
|
||||
* ...
|
||||
*
|
||||
* struct service_proc pmap2_pt[] = {
|
||||
* {PMAP2_GETPORT, pmap2_getport_proc,
|
||||
* (zdrproc_t)zdr_pmap2_mapping, sizeof(pmap2_mapping)},
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* The return value is:
|
||||
* 0: Procedure was completed normally.
|
||||
* !0: An abnormal error has occured. It is unrecoverable and the only
|
||||
* meaningful cause of action is to tear down the connection from
|
||||
* the client.
|
||||
*/
|
||||
typedef int (*service_fn)(struct rpc_context *rpc, struct rpc_msg *call);
|
||||
|
||||
struct service_proc {
|
||||
int proc;
|
||||
service_fn func;
|
||||
zdrproc_t decode_fn;
|
||||
int decode_buf_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Register a service callback table for program/version.
|
||||
* Can only be used with contexts created with rpc_init_server_context()
|
||||
*/
|
||||
int rpc_register_service(struct rpc_context *rpc, int program, int version,
|
||||
struct service_proc *procs, int num_procs);
|
||||
|
||||
int rpc_send_reply(struct rpc_context *rpc, struct rpc_msg *call,
|
||||
void *reply, zdrproc_t encode_fn,
|
||||
int alloc_hint);
|
||||
|
||||
/*
|
||||
* When an operation failed, this function can extract a detailed error string.
|
||||
*/
|
||||
|
@ -109,6 +167,7 @@ void rpc_set_fd(struct rpc_context *rpc, int fd);
|
|||
#define RPC_STATUS_SUCCESS 0
|
||||
#define RPC_STATUS_ERROR 1
|
||||
#define RPC_STATUS_CANCEL 2
|
||||
#define RPC_STATUS_TIMEOUT 3
|
||||
|
||||
/*
|
||||
* Async connection to the tcp port at server:port.
|
||||
|
@ -1699,6 +1758,56 @@ EXTERN int rpc_nsm1_simucrash_async(struct rpc_context *rpc, rpc_cb cb, void *pr
|
|||
struct NSM1_NOTIFYargs;
|
||||
EXTERN int rpc_nsm1_notify_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_NOTIFYargs *args, void *private_data);
|
||||
|
||||
/*
|
||||
* Call NFS4/NULL
|
||||
* Function returns
|
||||
* 0 : The call was initiated. The callback will be invoked when the call completes.
|
||||
* <0 : An error occured when trying to set up the call. The callback will not be invoked.
|
||||
*
|
||||
* When the callback is invoked, status indicates the result:
|
||||
* RPC_STATUS_SUCCESS : We got a successful response from the nfs daemon.
|
||||
* data is NULL.
|
||||
* RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
|
||||
* data is the error string.
|
||||
* RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
|
||||
* data is NULL.
|
||||
*/
|
||||
EXTERN int rpc_nfs4_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
|
||||
|
||||
/*
|
||||
* Call NFS4/COMPOUND
|
||||
* Function returns
|
||||
* 0 : The call was initiated. The callback will be invoked when the call completes.
|
||||
* <0 : An error occured when trying to set up the call. The callback will not be invoked.
|
||||
*
|
||||
* When the callback is invoked, status indicates the result:
|
||||
* RPC_STATUS_SUCCESS : We got a successful response from the nfs daemon.
|
||||
* data is COMPOUND4res
|
||||
* RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon.
|
||||
* data is the error string.
|
||||
* RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
|
||||
* data is NULL.
|
||||
*/
|
||||
struct COMPOUND4args;
|
||||
EXTERN int rpc_nfs4_compound_async(struct rpc_context *rpc, rpc_cb cb, struct COMPOUND4args *args, void *private_data);
|
||||
|
||||
/*
|
||||
* Call <generic>/NULL
|
||||
* Function returns
|
||||
* 0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
|
||||
* <0 : An error occured when trying to set up the connection. The callback will not be invoked.
|
||||
*
|
||||
* When the callback is invoked, status indicates the result:
|
||||
* RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
|
||||
* data is NULL.
|
||||
* RPC_STATUS_ERROR : An error occured when trying to contact the portmapper.
|
||||
* data is the error string.
|
||||
* RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
|
||||
* data is NULL.
|
||||
*/
|
||||
EXTERN int
|
||||
rpc_null_async(struct rpc_context *rpc, int program, int version, rpc_cb cb, void *private_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -96,7 +96,7 @@ typedef uint32_t u_int;
|
|||
typedef uint32_t enum_t;
|
||||
typedef uint32_t bool_t;
|
||||
|
||||
typedef int (*zdrproc_t) (ZDR *, void *,...);
|
||||
typedef uint32_t (*zdrproc_t) (ZDR *, void *,...);
|
||||
|
||||
#define AUTH_NONE 0
|
||||
#define AUTH_NULL 0
|
||||
|
@ -165,6 +165,7 @@ struct call_body {
|
|||
uint32_t proc;
|
||||
struct opaque_auth cred;
|
||||
struct opaque_auth verf;
|
||||
void *args;
|
||||
};
|
||||
|
||||
struct accepted_reply {
|
||||
|
@ -221,9 +222,11 @@ void libnfs_zdr_destroy(ZDR *zdrs);
|
|||
bool_t libnfs_zdr_bytes(ZDR *zdrs, char **bufp, uint32_t *size, uint32_t maxsize);
|
||||
|
||||
#define zdr_u_int libnfs_zdr_u_int
|
||||
#define zdr_uint32_t libnfs_zdr_u_int
|
||||
bool_t libnfs_zdr_u_int(ZDR *zdrs, uint32_t *u);
|
||||
|
||||
#define zdr_int libnfs_zdr_int
|
||||
#define zdr_int32_t libnfs_zdr_int
|
||||
bool_t libnfs_zdr_int(ZDR *zdrs, int32_t *i);
|
||||
|
||||
#define zdr_uint64_t libnfs_zdr_uint64_t
|
||||
|
@ -239,7 +242,7 @@ bool_t libnfs_zdr_enum(ZDR *zdrs, enum_t *e);
|
|||
bool_t libnfs_zdr_bool(ZDR *zdrs, bool_t *b);
|
||||
|
||||
#define zdr_void libnfs_zdr_void
|
||||
bool_t libnfs_zdr_void(void);
|
||||
bool_t libnfs_zdr_void(ZDR *zdrs, void *);
|
||||
|
||||
#define zdr_pointer libnfs_zdr_pointer
|
||||
bool_t libnfs_zdr_pointer(ZDR *zdrs, char **objp, uint32_t size, zdrproc_t proc);
|
||||
|
|
|
@ -22,14 +22,11 @@
|
|||
#define _LIBNFS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#if defined(__ANDROID__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#if defined(AROS)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#if defined(__ANDROID__) || defined(AROS) \
|
||||
|| ( defined(__APPLE__) && defined(__MACH__) )
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -57,7 +54,10 @@ struct nfs_url {
|
|||
#define EXTERN
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#ifdef WIN32
|
||||
#ifdef HAVE_FUSE_H
|
||||
#include <fuse.h>
|
||||
#else
|
||||
struct statvfs {
|
||||
uint32_t f_bsize;
|
||||
uint32_t f_frsize;
|
||||
|
@ -71,6 +71,7 @@ struct statvfs {
|
|||
uint32_t f_flag;
|
||||
uint32_t f_namemax;
|
||||
};
|
||||
#endif
|
||||
#if !defined(__MINGW32__)
|
||||
struct utimbuf {
|
||||
time_t actime;
|
||||
|
@ -238,12 +239,6 @@ EXTERN void nfs_set_dircache(struct nfs_context *nfs, int enabled);
|
|||
*/
|
||||
EXTERN void nfs_pagecache_invalidate(struct nfs_context *nfs, struct nfsfh *nfsfh);
|
||||
|
||||
/*
|
||||
* Sets timeout in milliseconds. A negative value means infinite timeout.
|
||||
*/
|
||||
EXTERN void nfs_set_timeout(struct nfs_context *nfs, int timeout);
|
||||
EXTERN int nfs_get_timeout(struct nfs_context *nfs);
|
||||
|
||||
/*
|
||||
* MOUNT THE EXPORT
|
||||
*/
|
||||
|
@ -455,13 +450,14 @@ EXTERN uint16_t nfs_umask(struct nfs_context *nfs, uint16_t mask);
|
|||
* Async open(<filename>)
|
||||
*
|
||||
* mode is a combination of the flags :
|
||||
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC
|
||||
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC, O_NOFOLLOW
|
||||
*
|
||||
* Function returns
|
||||
* 0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
|
||||
* <0 : An error occured when trying to set up the operation. The callback will not be invoked.
|
||||
*
|
||||
* Supported flags are
|
||||
* O_NOFOLLOW
|
||||
* O_APPEND
|
||||
* O_RDONLY
|
||||
* O_WRONLY
|
||||
|
@ -538,7 +534,7 @@ EXTERN int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_
|
|||
* >=0 : numer of bytes read.
|
||||
* -errno : An error occured.
|
||||
*/
|
||||
EXTERN int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf);
|
||||
EXTERN int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, void *buf);
|
||||
|
||||
|
||||
|
||||
|
@ -566,7 +562,7 @@ EXTERN int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t
|
|||
* >=0 : numer of bytes read.
|
||||
* -errno : An error occured.
|
||||
*/
|
||||
EXTERN int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf);
|
||||
EXTERN int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, void *buf);
|
||||
|
||||
|
||||
|
||||
|
@ -587,14 +583,14 @@ EXTERN int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count
|
|||
* -errno : An error occured.
|
||||
* data is the error string.
|
||||
*/
|
||||
EXTERN int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data);
|
||||
EXTERN int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf, nfs_cb cb, void *private_data);
|
||||
/*
|
||||
* Sync pwrite()
|
||||
* Function returns
|
||||
* >=0 : numer of bytes written.
|
||||
* -errno : An error occured.
|
||||
*/
|
||||
EXTERN int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf);
|
||||
EXTERN int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -613,14 +609,14 @@ EXTERN int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t off
|
|||
* -errno : An error occured.
|
||||
* data is the error string.
|
||||
*/
|
||||
EXTERN int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data);
|
||||
EXTERN int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf, nfs_cb cb, void *private_data);
|
||||
/*
|
||||
* Sync write()
|
||||
* Function returns
|
||||
* >=0 : numer of bytes written.
|
||||
* -errno : An error occured.
|
||||
*/
|
||||
EXTERN int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf);
|
||||
EXTERN int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -754,6 +750,27 @@ EXTERN int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
|
|||
*/
|
||||
EXTERN int nfs_mkdir(struct nfs_context *nfs, const char *path);
|
||||
|
||||
/*
|
||||
* Async mkdir2()
|
||||
*
|
||||
* Function returns
|
||||
* 0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
|
||||
* <0 : An error occured when trying to set up the operation. The callback will not be invoked.
|
||||
*
|
||||
* When the callback is invoked, status indicates the result:
|
||||
* 0 : Success.
|
||||
* -errno : An error occured.
|
||||
* data is the error string.
|
||||
*/
|
||||
EXTERN int nfs_mkdir2_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data);
|
||||
/*
|
||||
* Sync mkdir2()
|
||||
* Function returns
|
||||
* 0 : Success
|
||||
* -errno : An error occured.
|
||||
*/
|
||||
EXTERN int nfs_mkdir2(struct nfs_context *nfs, const char *path, int mode);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -812,6 +829,7 @@ EXTERN int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct
|
|||
* Async create()
|
||||
*
|
||||
* Same as nfs_creat_async but allows passing flags:
|
||||
* O_NOFOLLOW
|
||||
* O_APPEND
|
||||
* O_SYNC
|
||||
* O_EXCL
|
||||
|
@ -1523,6 +1541,28 @@ struct nfs_server_list {
|
|||
struct nfs_server_list *nfs_find_local_servers(void);
|
||||
void free_nfs_srvr_list(struct nfs_server_list *srv);
|
||||
|
||||
/*
|
||||
* sync nfs_set_timeout()
|
||||
* This function sets the timeout used for nfs rpc calls.
|
||||
*
|
||||
* Function returns nothing.
|
||||
*
|
||||
* int milliseconds : timeout to be applied in milliseconds (-1 no timeout)
|
||||
* timeouts must currently be set in whole seconds,
|
||||
* i.e. units of 1000
|
||||
*/
|
||||
EXTERN void nfs_set_timeout(struct nfs_context *nfs, int milliseconds);
|
||||
|
||||
/*
|
||||
* sync nfs_get_timeout()
|
||||
* This function gets the timeout used for nfs rpc calls.
|
||||
*
|
||||
* Function returns
|
||||
* -1 : No timeout applied
|
||||
* > 0 : Timeout in milliseconds
|
||||
*/
|
||||
EXTERN int nfs_get_timeout(struct nfs_context *nfs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@ libnfs_la_CPPFLAGS = -I$(abs_top_srcdir)/include \
|
|||
-I$(abs_top_srcdir)/include/nfsc \
|
||||
-I$(abs_top_srcdir)/mount \
|
||||
-I$(abs_top_srcdir)/nfs \
|
||||
-I$(abs_top_srcdir)/nfs4 \
|
||||
-I$(abs_top_srcdir)/nlm \
|
||||
-I$(abs_top_srcdir)/nsm \
|
||||
-I$(abs_top_srcdir)/portmap \
|
||||
|
@ -29,6 +30,7 @@ libnfs_la_LDFLAGS = -version-info $(SOCURRENT):$(SOREVISION):$(SOAGE)
|
|||
libnfs_la_LIBADD = \
|
||||
../mount/libmount.la \
|
||||
../nfs/libnfs.la \
|
||||
../nfs4/libnfs4.la \
|
||||
../nlm/libnlm.la \
|
||||
../nsm/libnsm.la \
|
||||
../portmap/libportmap.la \
|
||||
|
|
80
lib/init.c
80
lib/init.c
|
@ -91,7 +91,28 @@ struct rpc_context *rpc_init_context(void)
|
|||
return rpc;
|
||||
}
|
||||
|
||||
uint32_t static round_to_power_of_two(uint32_t x) {
|
||||
struct rpc_context *rpc_init_server_context(int s)
|
||||
{
|
||||
struct rpc_context *rpc;
|
||||
|
||||
rpc = malloc(sizeof(struct rpc_context));
|
||||
if (rpc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(rpc, 0, sizeof(struct rpc_context));
|
||||
|
||||
rpc->magic = RPC_CONTEXT_MAGIC;
|
||||
|
||||
rpc->is_server_context = 1;
|
||||
rpc->fd = s;
|
||||
rpc->is_connected = 1;
|
||||
rpc->is_udp = rpc_is_udp_socket(rpc);
|
||||
rpc_reset_queue(&rpc->outqueue);
|
||||
|
||||
return rpc;
|
||||
}
|
||||
|
||||
static uint32_t round_to_power_of_two(uint32_t x) {
|
||||
uint32_t power = 1;
|
||||
while (power < x) {
|
||||
power <<= 1;
|
||||
|
@ -237,8 +258,8 @@ void rpc_error_all_pdus(struct rpc_context *rpc, const char *error)
|
|||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
while ((pdu = rpc->outqueue.head) != NULL) {
|
||||
pdu->cb(rpc, RPC_STATUS_ERROR, (void *)error, pdu->private_data);
|
||||
rpc->outqueue.head = pdu->next;
|
||||
pdu->cb(rpc, RPC_STATUS_ERROR, (void *)error, pdu->private_data);
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
}
|
||||
rpc->outqueue.tail = NULL;
|
||||
|
@ -247,13 +268,14 @@ void rpc_error_all_pdus(struct rpc_context *rpc, const char *error)
|
|||
struct rpc_queue *q = &rpc->waitpdu[i];
|
||||
|
||||
while((pdu = q->head) != NULL) {
|
||||
q->head = pdu->next;
|
||||
pdu->cb(rpc, RPC_STATUS_ERROR, (void *)error,
|
||||
pdu->private_data);
|
||||
q->head = pdu->next;
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
}
|
||||
q->tail = NULL;
|
||||
}
|
||||
rpc->waitpdu_len = 0;
|
||||
}
|
||||
|
||||
static void rpc_free_fragment(struct rpc_fragment *fragment)
|
||||
|
@ -306,9 +328,17 @@ void rpc_destroy_context(struct rpc_context *rpc)
|
|||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
/* If we are a server context, free all registered endpoints. */
|
||||
while (rpc->endpoints != NULL) {
|
||||
struct rpc_endpoint *next = rpc->endpoints->next;
|
||||
|
||||
free(rpc->endpoints);
|
||||
rpc->endpoints = next;
|
||||
}
|
||||
|
||||
while((pdu = rpc->outqueue.head) != NULL) {
|
||||
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
|
||||
LIBNFS_LIST_REMOVE(&rpc->outqueue.head, pdu);
|
||||
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
}
|
||||
|
||||
|
@ -316,16 +346,18 @@ void rpc_destroy_context(struct rpc_context *rpc)
|
|||
struct rpc_queue *q = &rpc->waitpdu[i];
|
||||
|
||||
while((pdu = q->head) != NULL) {
|
||||
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
|
||||
LIBNFS_LIST_REMOVE(&q->head, pdu);
|
||||
pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
}
|
||||
}
|
||||
|
||||
rpc_free_all_fragments(rpc);
|
||||
|
||||
auth_destroy(rpc->auth);
|
||||
rpc->auth =NULL;
|
||||
if (rpc->auth) {
|
||||
auth_destroy(rpc->auth);
|
||||
rpc->auth =NULL;
|
||||
}
|
||||
|
||||
if (rpc->fd != -1) {
|
||||
close(rpc->fd);
|
||||
|
@ -336,11 +368,6 @@ void rpc_destroy_context(struct rpc_context *rpc)
|
|||
rpc->error_string = NULL;
|
||||
}
|
||||
|
||||
if (rpc->udp_dest != NULL) {
|
||||
free(rpc->udp_dest);
|
||||
rpc->udp_dest = NULL;
|
||||
}
|
||||
|
||||
free(rpc->inbuf);
|
||||
rpc->inbuf = NULL;
|
||||
|
||||
|
@ -361,3 +388,32 @@ int rpc_get_timeout(struct rpc_context *rpc)
|
|||
|
||||
return rpc->timeout;
|
||||
}
|
||||
|
||||
int rpc_register_service(struct rpc_context *rpc, int program, int version,
|
||||
struct service_proc *procs, int num_procs)
|
||||
{
|
||||
struct rpc_endpoint *endpoint;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (!rpc->is_server_context) {
|
||||
rpc_set_error(rpc, "Not a server context.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
endpoint = malloc(sizeof(*endpoint));
|
||||
if (endpoint == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory: Failed to allocate endpoint "
|
||||
"structure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
endpoint->program = program;
|
||||
endpoint->version = version;
|
||||
endpoint->procs = procs;
|
||||
endpoint->num_procs = num_procs;
|
||||
endpoint->next = rpc->endpoints;
|
||||
rpc->endpoints = endpoint;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -395,7 +395,7 @@ static void pread_cb(int status, struct nfs_context *nfs, void *data, void *priv
|
|||
memcpy(buffer, (char *)data, status);
|
||||
}
|
||||
|
||||
int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buffer)
|
||||
int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, void *buffer)
|
||||
{
|
||||
struct sync_cb_data cb_data;
|
||||
|
||||
|
@ -416,7 +416,7 @@ int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uin
|
|||
/*
|
||||
* read()
|
||||
*/
|
||||
int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buffer)
|
||||
int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, void *buffer)
|
||||
{
|
||||
struct sync_cb_data cb_data;
|
||||
|
||||
|
@ -526,7 +526,7 @@ static void pwrite_cb(int status, struct nfs_context *nfs, void *data, void *pri
|
|||
nfs_set_error(nfs, "%s call failed with \"%s\"", cb_data->call, (char *)data);
|
||||
}
|
||||
|
||||
int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf)
|
||||
int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf)
|
||||
{
|
||||
struct sync_cb_data cb_data;
|
||||
|
||||
|
@ -546,7 +546,7 @@ int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, ui
|
|||
/*
|
||||
* write()
|
||||
*/
|
||||
int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf)
|
||||
int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf)
|
||||
{
|
||||
struct sync_cb_data cb_data;
|
||||
|
||||
|
@ -697,6 +697,21 @@ int nfs_mkdir(struct nfs_context *nfs, const char *path)
|
|||
return cb_data.status;
|
||||
}
|
||||
|
||||
int nfs_mkdir2(struct nfs_context *nfs, const char *path, int mode)
|
||||
{
|
||||
struct sync_cb_data cb_data;
|
||||
|
||||
cb_data.is_finished = 0;
|
||||
|
||||
if (nfs_mkdir2_async(nfs, path, mode, mkdir_cb, &cb_data) != 0) {
|
||||
nfs_set_error(nfs, "nfs_mkdir2_async failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait_for_nfs_reply(nfs, &cb_data);
|
||||
|
||||
return cb_data.status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1420,7 +1435,8 @@ int nfs_link(struct nfs_context *nfs, const char *oldpath, const char *newpath)
|
|||
cb_data.is_finished = 0;
|
||||
|
||||
if (nfs_link_async(nfs, oldpath, newpath, link_cb, &cb_data) != 0) {
|
||||
nfs_set_error(nfs, "nfs_link_async failed");
|
||||
nfs_set_error(nfs, "nfs_link_async failed: %s",
|
||||
nfs_get_error(nfs));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ nfs_lseek
|
|||
nfs_lseek_async
|
||||
nfs_mkdir
|
||||
nfs_mkdir_async
|
||||
nfs_mkdir2
|
||||
nfs_mkdir2_async
|
||||
nfs_mknod
|
||||
nfs_mknod_async
|
||||
nfs_mount
|
||||
|
@ -104,6 +106,7 @@ rpc_disconnect
|
|||
rpc_get_error
|
||||
rpc_get_fd
|
||||
rpc_init_context
|
||||
rpc_init_server_context
|
||||
rpc_pmap2_null_async
|
||||
rpc_pmap2_getport_async
|
||||
rpc_pmap2_set_async
|
||||
|
@ -200,6 +203,8 @@ rpc_nfs3_readlink_async
|
|||
rpc_nfs3_symlink_async
|
||||
rpc_nfs3_rename_async
|
||||
rpc_nfs3_link_async
|
||||
rpc_nfs4_compound_async
|
||||
rpc_nfs4_null_async
|
||||
rpc_nlm4_null_async
|
||||
rpc_nlm4_test_async
|
||||
rpc_nlm4_lock_async
|
||||
|
@ -212,9 +217,14 @@ rpc_nsm1_unmon_async
|
|||
rpc_nsm1_unmonall_async
|
||||
rpc_nsm1_simucrash_async
|
||||
rpc_nsm1_notify_async
|
||||
rpc_null_async
|
||||
rpc_register_service
|
||||
rpc_rquota1_null_async
|
||||
rpc_rquota1_getquota_async
|
||||
rpc_rquota1_getactivequota_async
|
||||
rpc_send_reply
|
||||
rpc_service
|
||||
rpc_set_fd
|
||||
rpc_set_gid
|
||||
rpc_set_uid
|
||||
rpc_which_events
|
||||
|
|
|
@ -78,7 +78,7 @@ void libnfs_zdrmem_create(ZDR *zdrs, const caddr_t addr, uint32_t size, enum zdr
|
|||
zdrs->mem = NULL;
|
||||
}
|
||||
|
||||
static void *zdr_malloc(ZDR *zdrs, uint32_t size)
|
||||
void *zdr_malloc(ZDR *zdrs, uint32_t size)
|
||||
{
|
||||
struct zdr_mem *mem;
|
||||
int mem_size;
|
||||
|
@ -205,7 +205,7 @@ bool_t libnfs_zdr_bool(ZDR *zdrs, bool_t *b)
|
|||
return libnfs_zdr_u_int(zdrs, (uint32_t *)b);
|
||||
}
|
||||
|
||||
bool_t libnfs_zdr_void(void)
|
||||
bool_t libnfs_zdr_void(ZDR *zdrs, void *v)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -312,10 +312,6 @@ bool_t libnfs_zdr_array(ZDR *zdrs, char **arrp, uint32_t *size, uint32_t maxsize
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (zdrs->pos + (int)(*size * elsize) > zdrs->size) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (zdrs->x_op == ZDR_DECODE) {
|
||||
*arrp = zdr_malloc(zdrs, *size * elsize);
|
||||
if (*arrp == NULL) {
|
||||
|
|
|
@ -27,9 +27,12 @@
|
|||
|
||||
#ifdef WIN32
|
||||
#include "win32_compat.h"
|
||||
#define PRIu64 "llu"
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#define PRIu64 "llu"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIME_H
|
||||
|
@ -68,7 +71,7 @@
|
|||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
|
@ -216,7 +219,7 @@ void nfs_pagecache_invalidate(struct nfs_context *nfs, struct nfsfh *nfsfh) {
|
|||
}
|
||||
}
|
||||
|
||||
static void nfs_pagecache_put(struct nfs_pagecache *pagecache, uint64_t offset, char *buf, size_t len) {
|
||||
static void nfs_pagecache_put(struct nfs_pagecache *pagecache, uint64_t offset, const char *buf, size_t len) {
|
||||
time_t ts = pagecache->ttl ? time(NULL) : 1;
|
||||
if (!pagecache->num_entries) return;
|
||||
while (len > 0) {
|
||||
|
@ -286,7 +289,7 @@ struct nfs_cb_data {
|
|||
uint64_t offset, max_offset, org_offset;
|
||||
char *buffer;
|
||||
int not_my_buffer;
|
||||
char *usrbuf;
|
||||
const char *usrbuf;
|
||||
int update_pos;
|
||||
};
|
||||
|
||||
|
@ -534,6 +537,7 @@ void nfs_destroy_context(struct nfs_context *nfs)
|
|||
LIBNFS_LIST_REMOVE(&nfs->nested_mounts, mnt);
|
||||
free(mnt->path);
|
||||
free(mnt->fh.data.data_val);
|
||||
free(mnt);
|
||||
}
|
||||
|
||||
rpc_destroy_context(nfs->rpc);
|
||||
|
@ -628,27 +632,12 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
|
|||
return;
|
||||
}
|
||||
|
||||
switch (data->program) {
|
||||
case MOUNT_PROGRAM:
|
||||
if (rpc_mount3_null_async(rpc, rpc_connect_program_5_cb,
|
||||
data) != 0) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
case NFS_PROGRAM:
|
||||
if (rpc_nfs3_null_async(rpc, rpc_connect_program_5_cb,
|
||||
data) != 0) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
data->cb(rpc, status, NULL, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
if (rpc_null_async(rpc, data->program, data->version,
|
||||
rpc_connect_program_5_cb, data) != 0) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
|
||||
|
@ -969,19 +958,11 @@ static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_d
|
|||
nfs->writemax = res->FSINFO3res_u.resok.wtmax;
|
||||
|
||||
if (nfs->readmax > NFS_MAX_XFER_SIZE) {
|
||||
rpc_set_error(rpc, "server max rsize of %" PRIu64 " is greater than libnfs supported %d bytes",
|
||||
nfs->readmax, NFS_MAX_XFER_SIZE);
|
||||
data->cb(-EINVAL, nfs, command_data, data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return;
|
||||
nfs->readmax = NFS_MAX_XFER_SIZE;
|
||||
}
|
||||
|
||||
if (nfs->writemax > NFS_MAX_XFER_SIZE) {
|
||||
rpc_set_error(rpc, "server max wsize of %" PRIu64 " is greater than libnfs supported %d bytes",
|
||||
nfs->writemax, NFS_MAX_XFER_SIZE);
|
||||
data->cb(-EINVAL, nfs, command_data, data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return;
|
||||
nfs->writemax = NFS_MAX_XFER_SIZE;
|
||||
}
|
||||
|
||||
memset(&args, 0, sizeof(GETATTR3args));
|
||||
|
@ -1086,6 +1067,17 @@ finished:
|
|||
|
||||
rpc_disconnect(rpc, "normal disconnect");
|
||||
|
||||
if (status == RPC_STATUS_ERROR) {
|
||||
data->cb(-EFAULT, nfs, command_data, data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return;
|
||||
}
|
||||
if (status == RPC_STATUS_CANCEL) {
|
||||
data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpc_connect_program_async(nfs->rpc, nfs->server, NFS_PROGRAM, NFS_V3, nfs_mount_9_cb, data) != 0) {
|
||||
data->cb(-ENOMEM, nfs, command_data, data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
|
@ -1461,28 +1453,35 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr,
|
|||
path = data->path;
|
||||
slash = strchr(path, '/');
|
||||
|
||||
if (attr && attr->type == NF3LNK && (!data->no_follow || *path != '\0')) {
|
||||
READLINK3args rl_args;
|
||||
|
||||
if (data->link_count++ >= MAX_LINK_COUNT) {
|
||||
data->cb(-ELOOP, nfs, "Too many levels of symbolic links", data->private_data);
|
||||
if (attr && attr->type == NF3LNK) {
|
||||
if (data->continue_int & O_NOFOLLOW) {
|
||||
data->cb(-ELOOP, nfs, "Symbolic link encountered", data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return -1;
|
||||
}
|
||||
if (!data->no_follow || *path != '\0') {
|
||||
READLINK3args rl_args;
|
||||
|
||||
rl_args.symlink = *fh;
|
||||
if (data->link_count++ >= MAX_LINK_COUNT) {
|
||||
data->cb(-ELOOP, nfs, "Too many levels of symbolic links", data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rpc_nfs3_readlink_async(nfs->rpc, nfs_lookup_path_2_cb, &rl_args, data) != 0) {
|
||||
rpc_set_error(nfs->rpc, "RPC error: Failed to send READLINK call for %s", data->path);
|
||||
data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return -1;
|
||||
rl_args.symlink = *fh;
|
||||
|
||||
if (rpc_nfs3_readlink_async(nfs->rpc, nfs_lookup_path_2_cb, &rl_args, data) != 0) {
|
||||
rpc_set_error(nfs->rpc, "RPC error: Failed to send READLINK call for %s", data->path);
|
||||
data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (slash != NULL) {
|
||||
*slash = '/';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (slash != NULL) {
|
||||
*slash = '/';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (slash != NULL) {
|
||||
|
@ -2514,7 +2513,7 @@ int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count,
|
|||
* Async pwrite()
|
||||
*/
|
||||
static void nfs_fill_WRITE3args (WRITE3args *args, struct nfsfh *fh, uint64_t offset, uint64_t count,
|
||||
void *buf)
|
||||
const void *buf)
|
||||
{
|
||||
memset(args, 0, sizeof(WRITE3args));
|
||||
args->file = fh->fh;
|
||||
|
@ -2522,7 +2521,7 @@ static void nfs_fill_WRITE3args (WRITE3args *args, struct nfsfh *fh, uint64_t of
|
|||
args->count = (count3)count;
|
||||
args->stable = fh->is_sync ? FILE_SYNC : UNSTABLE;
|
||||
args->data.data_len = (count3)count;
|
||||
args->data.data_val = buf;
|
||||
args->data.data_val = (char *)buf;
|
||||
}
|
||||
|
||||
static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
|
||||
|
@ -2616,7 +2615,7 @@ static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_da
|
|||
}
|
||||
|
||||
|
||||
static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, size_t count, char *buf, nfs_cb cb, void *private_data, int update_pos)
|
||||
static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, size_t count, const char *buf, nfs_cb cb, void *private_data, int update_pos)
|
||||
{
|
||||
struct nfs_cb_data *data;
|
||||
|
||||
|
@ -2688,7 +2687,7 @@ static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsf
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data)
|
||||
int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, const void *buf, nfs_cb cb, void *private_data)
|
||||
{
|
||||
return nfs_pwrite_async_internal(nfs, nfsfh, offset, (size_t)count, buf, cb, private_data, 0);
|
||||
}
|
||||
|
@ -2731,7 +2730,7 @@ static void nfs_write_append_cb(struct rpc_context *rpc, int status, void *comma
|
|||
free_nfs_cb_data(data);
|
||||
}
|
||||
|
||||
int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data)
|
||||
int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, const void *buf, nfs_cb cb, void *private_data)
|
||||
{
|
||||
if (nfsfh->is_append) {
|
||||
struct GETATTR3args args;
|
||||
|
@ -2770,12 +2769,30 @@ int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count
|
|||
* close
|
||||
*/
|
||||
|
||||
static void nfs_close_cb(int err, struct nfs_context *nfs, void *ret_data, void *private_data) {
|
||||
struct nfs_cb_data *data = private_data;
|
||||
free_nfsfh(data->nfsfh);
|
||||
data->cb(err, nfs, ret_data, data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
}
|
||||
|
||||
int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
|
||||
{
|
||||
free_nfsfh(nfsfh);
|
||||
cb(0, nfs, NULL, private_data);
|
||||
return 0;
|
||||
};
|
||||
struct nfs_cb_data *data;
|
||||
|
||||
data = malloc(sizeof(struct nfs_cb_data));
|
||||
if (data == NULL) {
|
||||
rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
|
||||
return -1;
|
||||
}
|
||||
memset(data, 0, sizeof(struct nfs_cb_data));
|
||||
|
||||
data->nfsfh = nfsfh;
|
||||
data->cb = cb;
|
||||
data->private_data = private_data;
|
||||
|
||||
return nfs_fsync_async(nfs, nfsfh, nfs_close_cb, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -3052,6 +3069,7 @@ static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data
|
|||
static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
|
||||
{
|
||||
char *str = data->continue_data;
|
||||
int mode = data->continue_int;
|
||||
MKDIR3args args;
|
||||
|
||||
str = &str[strlen(str) + 1];
|
||||
|
@ -3060,7 +3078,7 @@ static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_
|
|||
args.where.dir = data->fh;
|
||||
args.where.name = str;
|
||||
args.attributes.mode.set_it = 1;
|
||||
args.attributes.mode.set_mode3_u.mode = 0755;
|
||||
args.attributes.mode.set_mode3_u.mode = mode;
|
||||
|
||||
if (rpc_nfs3_mkdir_async(nfs->rpc, nfs_mkdir_cb, &args, data) != 0) {
|
||||
rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path);
|
||||
|
@ -3071,7 +3089,7 @@ static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
|
||||
int nfs_mkdir2_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
|
||||
{
|
||||
char *new_path;
|
||||
char *ptr;
|
||||
|
@ -3091,7 +3109,7 @@ int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
|
|||
*ptr = 0;
|
||||
|
||||
/* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
|
||||
if (nfs_lookuppath_async(nfs, new_path, 0, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
|
||||
if (nfs_lookuppath_async(nfs, new_path, 0, cb, private_data, nfs_mkdir_continue_internal, new_path, free, mode) != 0) {
|
||||
rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component");
|
||||
return -1;
|
||||
}
|
||||
|
@ -3099,6 +3117,10 @@ int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
|
||||
{
|
||||
return nfs_mkdir2_async(nfs, path, 0755, cb, private_data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -3270,7 +3292,7 @@ static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_d
|
|||
if (res->status != NFS3_OK) {
|
||||
rpc_set_error(nfs->rpc, "NFS: CREATE of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
|
||||
data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
|
||||
|
||||
free_nfs_cb_data(data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5393,7 +5415,7 @@ static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data,
|
|||
return;
|
||||
}
|
||||
|
||||
nfs_dircache_drop(nfs, &data->fh);
|
||||
nfs_dircache_drop(nfs, &link_data->newdir);
|
||||
data->cb(0, nfs, NULL, data->private_data);
|
||||
free_nfs_cb_data(data);
|
||||
}
|
||||
|
@ -5690,3 +5712,21 @@ int nfs_get_timeout(struct nfs_context *nfs)
|
|||
{
|
||||
return rpc_get_timeout(nfs->rpc);
|
||||
}
|
||||
|
||||
int rpc_null_async(struct rpc_context *rpc, int program, int version, rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
|
||||
pdu = rpc_allocate_pdu(rpc, program, version, 0, cb, private_data, (zdrproc_t)zdr_void, 0);
|
||||
if (pdu == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NULL call");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NULL call");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
208
lib/pdu.c
208
lib/pdu.c
|
@ -86,6 +86,51 @@ unsigned int rpc_hash_xid(uint32_t xid)
|
|||
|
||||
#define PAD_TO_8_BYTES(x) ((x + 0x07) & ~0x07)
|
||||
|
||||
static struct rpc_pdu *rpc_allocate_reply_pdu(struct rpc_context *rpc,
|
||||
struct rpc_msg *res,
|
||||
size_t alloc_hint)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
pdu = malloc(sizeof(struct rpc_pdu));
|
||||
if (pdu == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory: Failed to allocate pdu structure");
|
||||
return NULL;
|
||||
}
|
||||
memset(pdu, 0, sizeof(struct rpc_pdu));
|
||||
pdu->flags = PDU_DISCARD_AFTER_SENDING;
|
||||
pdu->xid = 0;
|
||||
pdu->cb = NULL;
|
||||
pdu->private_data = NULL;
|
||||
pdu->zdr_decode_fn = NULL;
|
||||
pdu->zdr_decode_bufsize = 0;
|
||||
|
||||
pdu->outdata.data = malloc(ZDR_ENCODEBUF_MINSIZE + alloc_hint);
|
||||
if (pdu->outdata.data == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory: Failed to allocate encode buffer");
|
||||
free(pdu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zdrmem_create(&pdu->zdr, pdu->outdata.data, ZDR_ENCODEBUF_MINSIZE + alloc_hint, ZDR_ENCODE);
|
||||
if (rpc->is_udp == 0) {
|
||||
zdr_setpos(&pdu->zdr, 4); /* skip past the record marker */
|
||||
}
|
||||
|
||||
if (zdr_replymsg(rpc, &pdu->zdr, res) == 0) {
|
||||
rpc_set_error(rpc, "zdr_replymsg failed with %s",
|
||||
rpc_get_error(rpc));
|
||||
zdr_destroy(&pdu->zdr);
|
||||
free(pdu->outdata.data);
|
||||
free(pdu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize, size_t alloc_hint)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
|
@ -115,6 +160,7 @@ struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int vers
|
|||
pdu->outdata.data = malloc(ZDR_ENCODEBUF_MINSIZE + alloc_hint);
|
||||
if (pdu->outdata.data == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory: Failed to allocate encode buffer");
|
||||
free(pdu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -137,6 +183,7 @@ struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int vers
|
|||
rpc_set_error(rpc, "zdr_callmsg failed with %s",
|
||||
rpc_get_error(rpc));
|
||||
zdr_destroy(&pdu->zdr);
|
||||
free(pdu->outdata.data);
|
||||
free(pdu);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -153,14 +200,10 @@ void rpc_free_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
|
|||
{
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (pdu->outdata.data != NULL) {
|
||||
free(pdu->outdata.data);
|
||||
pdu->outdata.data = NULL;
|
||||
}
|
||||
free(pdu->outdata.data);
|
||||
|
||||
if (pdu->zdr_decode_buf != NULL) {
|
||||
zdr_free(pdu->zdr_decode_fn, pdu->zdr_decode_buf);
|
||||
pdu->zdr_decode_buf = NULL;
|
||||
}
|
||||
|
||||
zdr_destroy(&pdu->zdr);
|
||||
|
@ -179,6 +222,12 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
|
|||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (rpc->timeout > 0) {
|
||||
pdu->timeout = time(NULL) + rpc->timeout / 1000;
|
||||
} else {
|
||||
pdu->timeout = 0;
|
||||
}
|
||||
|
||||
size = zdr_getpos(&pdu->zdr);
|
||||
|
||||
/* for udp we dont queue, we just send it straight away */
|
||||
|
@ -186,7 +235,9 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
|
|||
unsigned int hash;
|
||||
|
||||
// XXX add a rpc->udp_dest_sock_size and get rid of sys/socket.h and netinet/in.h
|
||||
if (sendto(rpc->fd, pdu->zdr.buf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) {
|
||||
if (sendto(rpc->fd, pdu->zdr.buf, size, MSG_DONTWAIT,
|
||||
(struct sockaddr *)&rpc->udp_dest,
|
||||
sizeof(rpc->udp_dest)) < 0) {
|
||||
rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno));
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
|
@ -194,6 +245,7 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
|
|||
|
||||
hash = rpc_hash_xid(pdu->xid);
|
||||
rpc_enqueue(&rpc->waitpdu[hash], pdu);
|
||||
rpc->waitpdu_len++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -230,7 +282,6 @@ static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, ZDR *
|
|||
}
|
||||
msg.body.rbody.reply.areply.reply_data.results.where = pdu->zdr_decode_buf;
|
||||
msg.body.rbody.reply.areply.reply_data.results.proc = pdu->zdr_decode_fn;
|
||||
|
||||
if (zdr_replymsg(rpc, zdr, &msg) == 0) {
|
||||
rpc_set_error(rpc, "zdr_replymsg failed in rpc_process_reply: "
|
||||
"%s", rpc_get_error(rpc));
|
||||
|
@ -272,6 +323,137 @@ static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, ZDR *
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rpc_send_error_reply(struct rpc_context *rpc,
|
||||
struct rpc_msg *call,
|
||||
enum accept_stat err,
|
||||
int min_vers, int max_vers)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
struct rpc_msg res;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
memset(&res, 0, sizeof(struct rpc_msg));
|
||||
res.xid = call->xid;
|
||||
res.direction = REPLY;
|
||||
res.body.rbody.stat = MSG_ACCEPTED;
|
||||
res.body.rbody.reply.areply.reply_data.mismatch_info.low = min_vers;
|
||||
res.body.rbody.reply.areply.reply_data.mismatch_info.high = max_vers;
|
||||
res.body.rbody.reply.areply.verf = _null_auth;
|
||||
res.body.rbody.reply.areply.stat = err;
|
||||
|
||||
if (rpc->is_udp) {
|
||||
/* send the reply back to the client */
|
||||
memcpy(&rpc->udp_dest, &rpc->udp_src, sizeof(rpc->udp_dest));
|
||||
}
|
||||
|
||||
pdu = rpc_allocate_reply_pdu(rpc, &res, 0);
|
||||
if (pdu == NULL) {
|
||||
rpc_set_error(rpc, "Failed to send error_reply: %s",
|
||||
rpc_get_error(rpc));
|
||||
return -1;
|
||||
}
|
||||
rpc_queue_pdu(rpc, pdu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpc_send_reply(struct rpc_context *rpc,
|
||||
struct rpc_msg *call,
|
||||
void *reply,
|
||||
zdrproc_t encode_fn,
|
||||
int alloc_hint)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
struct rpc_msg res;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
memset(&res, 0, sizeof(struct rpc_msg));
|
||||
res.xid = call->xid;
|
||||
res.direction = REPLY;
|
||||
res.body.rbody.stat = MSG_ACCEPTED;
|
||||
res.body.rbody.reply.areply.verf = _null_auth;
|
||||
res.body.rbody.reply.areply.stat = SUCCESS;
|
||||
|
||||
res.body.rbody.reply.areply.reply_data.results.where = reply;
|
||||
res.body.rbody.reply.areply.reply_data.results.proc = encode_fn;
|
||||
|
||||
if (rpc->is_udp) {
|
||||
/* send the reply back to the client */
|
||||
memcpy(&rpc->udp_dest, &rpc->udp_src, sizeof(rpc->udp_dest));
|
||||
}
|
||||
|
||||
pdu = rpc_allocate_reply_pdu(rpc, &res, alloc_hint);
|
||||
if (pdu == NULL) {
|
||||
rpc_set_error(rpc, "Failed to send error_reply: %s",
|
||||
rpc_get_error(rpc));
|
||||
return -1;
|
||||
}
|
||||
rpc_queue_pdu(rpc, pdu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpc_process_call(struct rpc_context *rpc, ZDR *zdr)
|
||||
{
|
||||
struct rpc_msg call;
|
||||
struct rpc_endpoint *endpoint;
|
||||
int i, min_version = 0, max_version = 0, found_program = 0;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
memset(&call, 0, sizeof(struct rpc_msg));
|
||||
if (zdr_callmsg(rpc, zdr, &call) == 0) {
|
||||
rpc_set_error(rpc, "Failed to decode CALL message. %s",
|
||||
rpc_get_error(rpc));
|
||||
return rpc_send_error_reply(rpc, &call, GARBAGE_ARGS, 0, 0);
|
||||
}
|
||||
for (endpoint = rpc->endpoints; endpoint; endpoint = endpoint->next) {
|
||||
if (call.body.cbody.prog == endpoint->program) {
|
||||
if (!found_program) {
|
||||
min_version = max_version = endpoint->version;
|
||||
}
|
||||
if (endpoint->version < min_version) {
|
||||
min_version = endpoint->version;
|
||||
}
|
||||
if (endpoint->version > max_version) {
|
||||
max_version = endpoint->version;
|
||||
}
|
||||
found_program = 1;
|
||||
if (call.body.cbody.vers == endpoint->version) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (endpoint == NULL) {
|
||||
rpc_set_error(rpc, "No endpoint found for CALL "
|
||||
"program:0x%08x version:%d\n",
|
||||
call.body.cbody.prog, call.body.cbody.vers);
|
||||
if (!found_program) {
|
||||
return rpc_send_error_reply(rpc, &call, PROG_UNAVAIL,
|
||||
0, 0);
|
||||
}
|
||||
return rpc_send_error_reply(rpc, &call, PROG_MISMATCH,
|
||||
min_version, max_version);
|
||||
}
|
||||
for (i = 0; i < endpoint->num_procs; i++) {
|
||||
if (endpoint->procs[i].proc == call.body.cbody.proc) {
|
||||
if (endpoint->procs[i].decode_buf_size) {
|
||||
call.body.cbody.args = zdr_malloc(zdr, endpoint->procs[i].decode_buf_size);
|
||||
}
|
||||
if (!endpoint->procs[i].decode_fn(zdr, call.body.cbody.args)) {
|
||||
rpc_set_error(rpc, "Failed to unmarshall "
|
||||
"call payload");
|
||||
return rpc_send_error_reply(rpc, &call, GARBAGE_ARGS, 0 ,0);
|
||||
}
|
||||
return endpoint->procs[i].func(rpc, &call);
|
||||
}
|
||||
}
|
||||
|
||||
return rpc_send_error_reply(rpc, &call, PROC_UNAVAIL, 0 ,0);
|
||||
}
|
||||
|
||||
int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
|
||||
{
|
||||
struct rpc_pdu *pdu, *prev_pdu;
|
||||
|
@ -330,6 +512,17 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
|
|||
rpc_free_all_fragments(rpc);
|
||||
}
|
||||
|
||||
if (rpc->is_server_context) {
|
||||
int ret;
|
||||
|
||||
ret = rpc_process_call(rpc, &zdr);
|
||||
zdr_destroy(&zdr);
|
||||
if (reasbuf != NULL) {
|
||||
free(reasbuf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
pos = zdr_getpos(&zdr);
|
||||
if (zdr_int(&zdr, (int *)&xid) == 0) {
|
||||
rpc_set_error(rpc, "zdr_int reading xid failed");
|
||||
|
@ -361,6 +554,7 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
|
|||
q->tail = prev_pdu;
|
||||
if (prev_pdu != NULL)
|
||||
prev_pdu->next = pdu->next;
|
||||
rpc->waitpdu_len--;
|
||||
}
|
||||
if (rpc_process_reply(rpc, pdu, &zdr) != 0) {
|
||||
rpc_set_error(rpc, "rpc_procdess_reply failed");
|
||||
|
|
313
lib/socket.c
313
lib/socket.c
|
@ -85,19 +85,35 @@
|
|||
#include "win32_errnowrapper.h"
|
||||
#endif
|
||||
|
||||
static int rpc_reconnect_requeue(struct rpc_context *rpc);
|
||||
static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s);
|
||||
#define NR_RECONNECT_RETRIES 10
|
||||
|
||||
static void set_nonblocking(int fd)
|
||||
static int rpc_reconnect_requeue(struct rpc_context *rpc);
|
||||
|
||||
static int create_socket(int domain, int type, int protocol)
|
||||
{
|
||||
#ifdef SOCK_CLOEXEC
|
||||
/* Linux-specific extension (since 2.6.27): set the
|
||||
close-on-exec flag on all sockets to avoid leaking file
|
||||
descriptors to child processes */
|
||||
int fd = socket(domain, type|SOCK_CLOEXEC, protocol);
|
||||
if (fd >= 0 || errno != EINVAL)
|
||||
return fd;
|
||||
#endif
|
||||
|
||||
return socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
static int set_nonblocking(int fd)
|
||||
{
|
||||
int v = 0;
|
||||
#if defined(WIN32)
|
||||
long nonblocking=1;
|
||||
u_long nonblocking=1;
|
||||
v = ioctl(fd, FIONBIO, &nonblocking);
|
||||
#else
|
||||
v = fcntl(fd, F_GETFL, 0);
|
||||
fcntl(fd, F_SETFL, v | O_NONBLOCK);
|
||||
v = fcntl(fd, F_SETFL, v | O_NONBLOCK);
|
||||
#endif //FIXME
|
||||
return v;
|
||||
}
|
||||
|
||||
static void set_nolinger(int fd)
|
||||
|
@ -210,8 +226,14 @@ static int rpc_write_to_socket(struct rpc_context *rpc)
|
|||
if (pdu->next == NULL)
|
||||
rpc->outqueue.tail = NULL;
|
||||
|
||||
if (pdu->flags & PDU_DISCARD_AFTER_SENDING) {
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hash = rpc_hash_xid(pdu->xid);
|
||||
rpc_enqueue(&rpc->waitpdu[hash], pdu);
|
||||
rpc->waitpdu_len++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -222,11 +244,11 @@ static int rpc_read_from_socket(struct rpc_context *rpc)
|
|||
{
|
||||
uint32_t pdu_size;
|
||||
ssize_t count;
|
||||
char *buf;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (rpc->is_udp) {
|
||||
char *buf;
|
||||
socklen_t socklen = sizeof(rpc->udp_src);
|
||||
|
||||
buf = malloc(MAX_UDP_SIZE);
|
||||
|
@ -252,61 +274,63 @@ static int rpc_read_from_socket(struct rpc_context *rpc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
again:
|
||||
/* read record marker, 4 bytes at the beginning of every pdu first */
|
||||
pdu_size = rpc->inpos < 4 ? 4 : rpc_get_pdu_size(rpc->inbuf);
|
||||
do {
|
||||
/* read record marker, 4 bytes at the beginning of every pdu first */
|
||||
if (rpc->inpos < 4) {
|
||||
buf = (void *)rpc->rm_buf;
|
||||
pdu_size = 4;
|
||||
} else {
|
||||
pdu_size = rpc_get_pdu_size((void *)&rpc->rm_buf);
|
||||
if (rpc->inbuf == NULL) {
|
||||
if (pdu_size > NFS_MAX_XFER_SIZE + 4096) {
|
||||
rpc_set_error(rpc, "Incoming PDU exceeds limit of %d bytes.", NFS_MAX_XFER_SIZE + 4096);
|
||||
return -1;
|
||||
}
|
||||
rpc->inbuf = malloc(pdu_size);
|
||||
if (rpc->inbuf == NULL) {
|
||||
rpc_set_error(rpc, "Failed to allocate buffer of %d bytes for pdu, errno:%d. Closing socket.", pdu_size, errno);
|
||||
return -1;
|
||||
}
|
||||
memcpy(rpc->inbuf, &rpc->rm_buf, 4);
|
||||
}
|
||||
buf = rpc->inbuf;
|
||||
}
|
||||
|
||||
if (pdu_size > NFS_MAX_XFER_SIZE + 4096) {
|
||||
rpc_set_error(rpc, "Incoming PDU exceeds limit of %d bytes.", NFS_MAX_XFER_SIZE + 4096);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rpc->insize < pdu_size) {
|
||||
rpc->inbuf = realloc(rpc->inbuf, pdu_size);
|
||||
if (rpc->inbuf == NULL) {
|
||||
rpc_set_error(rpc, "Failed to allocate buffer of %d bytes for pdu, errno:%d. Closing socket.", pdu_size, errno);
|
||||
count = recv(rpc->fd, buf + rpc->inpos, pdu_size - rpc->inpos, MSG_DONTWAIT);
|
||||
if (count < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
break;
|
||||
}
|
||||
rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno);
|
||||
return -1;
|
||||
}
|
||||
rpc->insize = pdu_size;
|
||||
}
|
||||
|
||||
count = recv(rpc->fd, rpc->inbuf + rpc->inpos, rpc->insize - rpc->inpos, MSG_DONTWAIT);
|
||||
if (count < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
return 0;
|
||||
}
|
||||
rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno);
|
||||
return -1;
|
||||
}
|
||||
if (count == 0) {
|
||||
/* remote side has closed the socket. Reconnect. */
|
||||
return -1;
|
||||
}
|
||||
rpc->inpos += count;
|
||||
|
||||
if (rpc->inpos == 4) {
|
||||
/* we have just read the header there is likely more data available */
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (rpc->inpos == rpc->insize) {
|
||||
char *buf = rpc->inbuf;
|
||||
|
||||
rpc->inbuf = NULL;
|
||||
rpc->insize = 0;
|
||||
rpc->inpos = 0;
|
||||
|
||||
if (rpc_process_pdu(rpc, buf, pdu_size) != 0) {
|
||||
rpc_set_error(rpc, "Invalid/garbage pdu received from server. Closing socket");
|
||||
if (count == 0) {
|
||||
/* remote side has closed the socket. Reconnect. */
|
||||
return -1;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
rpc->inpos += count;
|
||||
|
||||
if (rpc->inpos == 4) {
|
||||
/* we have just read the header there is likely more data available */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rpc->inpos == pdu_size) {
|
||||
rpc->inbuf = NULL;
|
||||
rpc->inpos = 0;
|
||||
|
||||
if (rpc_process_pdu(rpc, buf, pdu_size) != 0) {
|
||||
rpc_set_error(rpc, "Invalid/garbage pdu received from server. Closing socket");
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
} while (rpc->is_nonblocking && rpc->waitpdu_len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
maybe_call_connect_cb(struct rpc_context *rpc, int status)
|
||||
{
|
||||
|
@ -320,10 +344,59 @@ maybe_call_connect_cb(struct rpc_context *rpc, int status)
|
|||
tmp_cb(rpc, status, rpc->error_string, rpc->connect_data);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_timeout_scan(struct rpc_context *rpc)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
struct rpc_pdu *next_pdu;
|
||||
time_t t = time(NULL);
|
||||
unsigned int i;
|
||||
|
||||
for (pdu = rpc->outqueue.head; pdu; pdu = next_pdu) {
|
||||
next_pdu = pdu->next;
|
||||
|
||||
if (pdu->timeout == 0) {
|
||||
/* no timeout for this pdu */
|
||||
continue;
|
||||
}
|
||||
if (t < pdu->timeout) {
|
||||
/* not expired yet */
|
||||
continue;
|
||||
}
|
||||
LIBNFS_LIST_REMOVE(&rpc->outqueue.head, pdu);
|
||||
rpc_set_error(rpc, "command timed out");
|
||||
pdu->cb(rpc, RPC_STATUS_TIMEOUT,
|
||||
NULL, pdu->private_data);
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
}
|
||||
for (i = 0; i < HASHES; i++) {
|
||||
struct rpc_queue *q = &rpc->waitpdu[i];
|
||||
|
||||
for (pdu = q->head; pdu; pdu = next_pdu) {
|
||||
next_pdu = pdu->next;
|
||||
|
||||
if (pdu->timeout == 0) {
|
||||
/* no timeout for this pdu */
|
||||
continue;
|
||||
}
|
||||
if (t < pdu->timeout) {
|
||||
/* not expired yet */
|
||||
continue;
|
||||
}
|
||||
LIBNFS_LIST_REMOVE(&q->head, pdu);
|
||||
rpc_set_error(rpc, "command timed out");
|
||||
pdu->cb(rpc, RPC_STATUS_TIMEOUT,
|
||||
NULL, pdu->private_data);
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rpc_service(struct rpc_context *rpc, int revents)
|
||||
{
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
if (revents & (POLLERR|POLLHUP)) {
|
||||
|
||||
if (revents & (POLLERR | POLLHUP)) {
|
||||
if (revents & POLLERR) {
|
||||
#ifdef WIN32
|
||||
char err = 0;
|
||||
|
@ -356,7 +429,7 @@ int rpc_service(struct rpc_context *rpc, int revents)
|
|||
|
||||
}
|
||||
|
||||
if (rpc->is_connected == 0 && rpc->fd != -1 && revents&POLLOUT) {
|
||||
if (rpc->is_connected == 0 && rpc->fd != -1 && (revents & POLLOUT)) {
|
||||
int err = 0;
|
||||
socklen_t err_size = sizeof(err);
|
||||
|
||||
|
@ -380,16 +453,25 @@ int rpc_service(struct rpc_context *rpc, int revents)
|
|||
|
||||
if (revents & POLLIN) {
|
||||
if (rpc_read_from_socket(rpc) != 0) {
|
||||
return rpc_reconnect_requeue(rpc);
|
||||
if (rpc->is_server_context) {
|
||||
return -1;
|
||||
} else {
|
||||
return rpc_reconnect_requeue(rpc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (revents & POLLOUT && rpc_has_queue(&rpc->outqueue)) {
|
||||
if (rpc_write_to_socket(rpc) != 0) {
|
||||
return rpc_reconnect_requeue(rpc);
|
||||
if (rpc->is_server_context) {
|
||||
return -1;
|
||||
} else {
|
||||
return rpc_reconnect_requeue(rpc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc_timeout_scan(rpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -397,6 +479,11 @@ void rpc_set_autoreconnect(struct rpc_context *rpc)
|
|||
{
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
/* we can not connect and not reconnect on a server context. */
|
||||
if (rpc->is_server_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
rpc->auto_reconnect = 1;
|
||||
}
|
||||
|
||||
|
@ -404,6 +491,10 @@ void rpc_unset_autoreconnect(struct rpc_context *rpc)
|
|||
{
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (rpc->is_server_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
rpc->auto_reconnect = 0;
|
||||
}
|
||||
|
||||
|
@ -418,16 +509,17 @@ void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v)
|
|||
#define TCP_SYNCNT 7
|
||||
#endif
|
||||
|
||||
static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s)
|
||||
static int rpc_connect_sockaddr_async(struct rpc_context *rpc)
|
||||
{
|
||||
int socksize;
|
||||
struct sockaddr_storage *s = &rpc->s;
|
||||
socklen_t socksize;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
switch (s->ss_family) {
|
||||
case AF_INET:
|
||||
socksize = sizeof(struct sockaddr_in);
|
||||
rpc->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
rpc->fd = create_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (set_bind_device(rpc->fd, rpc->ifname) != 0) {
|
||||
rpc_set_error (rpc, "Failed to bind to interface");
|
||||
return -1;
|
||||
|
@ -441,7 +533,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
|
|||
break;
|
||||
case AF_INET6:
|
||||
socksize = sizeof(struct sockaddr_in6);
|
||||
rpc->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
||||
rpc->fd = create_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (set_bind_device(rpc->fd, rpc->ifname) != 0) {
|
||||
rpc_set_error (rpc, "Failed to bind to interface");
|
||||
return -1;
|
||||
|
@ -536,7 +628,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
|
|||
} while (rc != 0 && portOfs != startOfs);
|
||||
}
|
||||
|
||||
set_nonblocking(rpc->fd);
|
||||
rpc->is_nonblocking = !set_nonblocking(rpc->fd);
|
||||
set_nolinger(rpc->fd);
|
||||
|
||||
if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) {
|
||||
|
@ -547,24 +639,11 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
|
|||
return 0;
|
||||
}
|
||||
|
||||
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
|
||||
static int rpc_set_sockaddr(struct rpc_context *rpc, const char *server,
|
||||
int port)
|
||||
{
|
||||
struct addrinfo *ai = NULL;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (rpc->fd != -1) {
|
||||
rpc_set_error(rpc, "Trying to connect while already connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rpc->is_udp != 0) {
|
||||
rpc_set_error(rpc, "Trying to connect on UDP socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rpc->auto_reconnect = 0;
|
||||
|
||||
if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
|
||||
rpc_set_error(rpc, "Invalid address:%s. "
|
||||
"Can not resolv into IPv4/v6 structure.", server);
|
||||
|
@ -589,13 +668,40 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
|
||||
{
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (rpc->is_server_context) {
|
||||
rpc_set_error(rpc, "Can not connect on a server context");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rpc->fd != -1) {
|
||||
rpc_set_error(rpc, "Trying to connect while already connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rpc->is_udp != 0) {
|
||||
rpc_set_error(rpc, "Trying to connect on UDP socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rpc->auto_reconnect = 0;
|
||||
|
||||
if (rpc_set_sockaddr(rpc, server, port) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rpc->connect_cb = cb;
|
||||
rpc->connect_data = private_data;
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
|
||||
if (rpc_connect_sockaddr_async(rpc) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -619,7 +725,9 @@ int rpc_disconnect(struct rpc_context *rpc, const char *error)
|
|||
|
||||
rpc->is_connected = 0;
|
||||
|
||||
rpc_error_all_pdus(rpc, error);
|
||||
if (!rpc->is_server_context) {
|
||||
rpc_error_all_pdus(rpc, error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -647,6 +755,9 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc)
|
|||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (rpc->is_connected)
|
||||
rpc->auto_reconnect_retries = NR_RECONNECT_RETRIES;
|
||||
|
||||
if (rpc->fd != -1) {
|
||||
rpc->old_fd = rpc->fd;
|
||||
}
|
||||
|
@ -670,11 +781,13 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc)
|
|||
}
|
||||
rpc_reset_queue(q);
|
||||
}
|
||||
rpc->waitpdu_len = 0;
|
||||
|
||||
if (rpc->auto_reconnect != 0) {
|
||||
if (rpc->auto_reconnect != 0 && rpc->auto_reconnect_retries > 0) {
|
||||
rpc->auto_reconnect_retries--;
|
||||
rpc->connect_cb = reconnect_cb;
|
||||
RPC_LOG(rpc, 1, "reconnect initiated");
|
||||
if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
|
||||
if (rpc_connect_sockaddr_async(rpc) != 0) {
|
||||
rpc_error_all_pdus(rpc, "RPC ERROR: Failed to reconnect async");
|
||||
return -1;
|
||||
}
|
||||
|
@ -708,7 +821,7 @@ int rpc_bind_udp(struct rpc_context *rpc, char *addr, int port)
|
|||
|
||||
switch(ai->ai_family) {
|
||||
case AF_INET:
|
||||
rpc->fd = socket(ai->ai_family, SOCK_DGRAM, 0);
|
||||
rpc->fd = create_socket(ai->ai_family, SOCK_DGRAM, 0);
|
||||
if (rpc->fd == -1) {
|
||||
rpc_set_error(rpc, "Failed to create UDP socket: %s", strerror(errno));
|
||||
freeaddrinfo(ai);
|
||||
|
@ -751,17 +864,7 @@ int rpc_set_udp_destination(struct rpc_context *rpc, char *addr, int port, int i
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (rpc->udp_dest) {
|
||||
free(rpc->udp_dest);
|
||||
rpc->udp_dest = NULL;
|
||||
}
|
||||
rpc->udp_dest = malloc(ai->ai_addrlen);
|
||||
if (rpc->udp_dest == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to allocate sockaddr structure");
|
||||
freeaddrinfo(ai);
|
||||
return -1;
|
||||
}
|
||||
memcpy(rpc->udp_dest, ai->ai_addr, ai->ai_addrlen);
|
||||
memcpy(&rpc->udp_dest, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
|
||||
rpc->is_broadcast = is_broadcast;
|
||||
|
@ -779,9 +882,8 @@ struct sockaddr *rpc_get_recv_sockaddr(struct rpc_context *rpc)
|
|||
|
||||
int rpc_queue_length(struct rpc_context *rpc)
|
||||
{
|
||||
int i=0;
|
||||
int i = 0;
|
||||
struct rpc_pdu *pdu;
|
||||
unsigned int n;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
|
@ -789,12 +891,8 @@ int rpc_queue_length(struct rpc_context *rpc)
|
|||
i++;
|
||||
}
|
||||
|
||||
for (n = 0; n < HASHES; n++) {
|
||||
struct rpc_queue *q = &rpc->waitpdu[n];
|
||||
i += rpc->waitpdu_len;
|
||||
|
||||
for(pdu = q->head; pdu; pdu = pdu->next)
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -804,3 +902,16 @@ void rpc_set_fd(struct rpc_context *rpc, int fd)
|
|||
|
||||
rpc->fd = fd;
|
||||
}
|
||||
|
||||
int rpc_is_udp_socket(struct rpc_context *rpc)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char type = 0;
|
||||
#else
|
||||
int type = 0;
|
||||
#endif
|
||||
socklen_t len = sizeof(type);
|
||||
|
||||
getsockopt(rpc->fd, SOL_SOCKET, SO_TYPE, &type, &len);
|
||||
return type == SOCK_DGRAM;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ int rpc_mount3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for mount/null call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -69,7 +68,6 @@ int rpc_mount3_mnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for mount/mnt call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -93,7 +91,6 @@ int rpc_mount3_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue mount/dump pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -123,7 +120,6 @@ int rpc_mount3_umnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue mount/umnt pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -147,7 +143,6 @@ int rpc_mount3_umntall_async(struct rpc_context *rpc, rpc_cb cb, void *private_d
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue mount/umntall pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -171,7 +166,6 @@ int rpc_mount3_export_async(struct rpc_context *rpc, rpc_cb cb, void *private_da
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue mount/export pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -235,7 +229,6 @@ int rpc_mount1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for MOUNT1/NULL call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -260,7 +253,6 @@ int rpc_mount1_mnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for MOUNT1/MNT call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -279,7 +271,6 @@ int rpc_mount1_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue MOUNT1/DUMP pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -304,7 +295,6 @@ int rpc_mount1_umnt_async(struct rpc_context *rpc, rpc_cb cb, char *export, void
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue MOUNT1/UMNT pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -323,7 +313,6 @@ int rpc_mount1_umntall_async(struct rpc_context *rpc, rpc_cb cb, void *private_d
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue MOUNT1/UMNTALL pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -342,7 +331,6 @@ int rpc_mount1_export_async(struct rpc_context *rpc, rpc_cb cb, void *private_da
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue MOUNT1/EXPORT pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
40
nfs/nfs.c
40
nfs/nfs.c
|
@ -88,7 +88,7 @@ int nfsstat3_to_errno(int error)
|
|||
case NFS3ERR_NAMETOOLONG: return -ENAMETOOLONG; break;
|
||||
case NFS3ERR_NOTEMPTY: return -ENOTEMPTY; break;
|
||||
case NFS3ERR_DQUOT: return -ERANGE; break;
|
||||
case NFS3ERR_STALE: return -EIO; break;
|
||||
case NFS3ERR_STALE: return -ESTALE; break;
|
||||
case NFS3ERR_REMOTE: return -EIO; break;
|
||||
case NFS3ERR_BADHANDLE: return -EIO; break;
|
||||
case NFS3ERR_NOT_SYNC: return -EIO; break;
|
||||
|
@ -118,7 +118,6 @@ int rpc_nfs3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/NULL call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -148,7 +147,6 @@ int rpc_nfs3_getattr_async(struct rpc_context *rpc, rpc_cb cb, struct GETATTR3ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/GETATTR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -184,7 +182,6 @@ int rpc_nfs3_pathconf_async(struct rpc_context *rpc, rpc_cb cb, struct PATHCONF3
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/PATHCONF call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -220,7 +217,6 @@ int rpc_nfs3_lookup_async(struct rpc_context *rpc, rpc_cb cb, struct LOOKUP3args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/LOOKUP call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -257,7 +253,6 @@ int rpc_nfs3_access_async(struct rpc_context *rpc, rpc_cb cb, struct ACCESS3args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/ACCESS call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -294,7 +289,6 @@ int rpc_nfs3_read_async(struct rpc_context *rpc, rpc_cb cb, struct READ3args *ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READ call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -332,7 +326,6 @@ int rpc_nfs3_write_async(struct rpc_context *rpc, rpc_cb cb, struct WRITE3args *
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/WRITE call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -373,7 +366,6 @@ int rpc_nfs3_commit_async(struct rpc_context *rpc, rpc_cb cb, struct COMMIT3args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/COMMIT call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -411,7 +403,6 @@ int rpc_nfs3_setattr_async(struct rpc_context *rpc, rpc_cb cb, SETATTR3args *arg
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/SETATTR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -441,7 +432,6 @@ int rpc_nfs3_mkdir_async(struct rpc_context *rpc, rpc_cb cb, MKDIR3args *args, v
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/MKDIR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -471,7 +461,6 @@ int rpc_nfs3_rmdir_async(struct rpc_context *rpc, rpc_cb cb, struct RMDIR3args *
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/RMDIR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -508,7 +497,6 @@ int rpc_nfs3_create_async(struct rpc_context *rpc, rpc_cb cb, CREATE3args *args,
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/CREATE call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -538,7 +526,6 @@ int rpc_nfs3_mknod_async(struct rpc_context *rpc, rpc_cb cb, struct MKNOD3args *
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/MKNOD call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -604,7 +591,6 @@ int rpc_nfs3_remove_async(struct rpc_context *rpc, rpc_cb cb, struct REMOVE3args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/REMOVE call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -641,7 +627,6 @@ int rpc_nfs3_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct READDIR3ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READDIR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -680,7 +665,6 @@ int rpc_nfs3_readdirplus_async(struct rpc_context *rpc, rpc_cb cb, struct READDI
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READDIRPLUS call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -720,7 +704,6 @@ int rpc_nfs3_fsstat_async(struct rpc_context *rpc, rpc_cb cb, struct FSSTAT3args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/FSSTAT call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -756,7 +739,6 @@ int rpc_nfs3_fsinfo_async(struct rpc_context *rpc, rpc_cb cb, struct FSINFO3args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/FSINFO call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -792,7 +774,6 @@ int rpc_nfs3_readlink_async(struct rpc_context *rpc, rpc_cb cb, READLINK3args *a
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READLINK call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -822,7 +803,6 @@ int rpc_nfs3_symlink_async(struct rpc_context *rpc, rpc_cb cb, SYMLINK3args *arg
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/SYMLINK call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -852,7 +832,6 @@ int rpc_nfs3_rename_async(struct rpc_context *rpc, rpc_cb cb, struct RENAME3args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/RENAME call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -892,7 +871,6 @@ int rpc_nfs3_link_async(struct rpc_context *rpc, rpc_cb cb, struct LINK3args *ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/LINK call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -928,7 +906,6 @@ int rpc_nfs2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/NULL call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -953,7 +930,6 @@ int rpc_nfs2_getattr_async(struct rpc_context *rpc, rpc_cb cb, struct GETATTR2ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/GETATTR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -978,7 +954,6 @@ int rpc_nfs2_setattr_async(struct rpc_context *rpc, rpc_cb cb, SETATTR2args *arg
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/SETATTR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1003,7 +978,6 @@ int rpc_nfs2_lookup_async(struct rpc_context *rpc, rpc_cb cb, struct LOOKUP2args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/LOOKUP call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1028,7 +1002,6 @@ int rpc_nfs2_readlink_async(struct rpc_context *rpc, rpc_cb cb, READLINK2args *a
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/READLINK call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1053,7 +1026,6 @@ int rpc_nfs2_read_async(struct rpc_context *rpc, rpc_cb cb, struct READ2args *ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/READ call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1078,7 +1050,6 @@ int rpc_nfs2_write_async(struct rpc_context *rpc, rpc_cb cb, struct WRITE2args *
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/WRITE call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1103,7 +1074,6 @@ int rpc_nfs2_create_async(struct rpc_context *rpc, rpc_cb cb, CREATE2args *args,
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/CREATE call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1128,7 +1098,6 @@ int rpc_nfs2_remove_async(struct rpc_context *rpc, rpc_cb cb, struct REMOVE2args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/REMOVE call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1153,7 +1122,6 @@ int rpc_nfs2_rename_async(struct rpc_context *rpc, rpc_cb cb, struct RENAME2args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/RENAME call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1178,7 +1146,6 @@ int rpc_nfs2_link_async(struct rpc_context *rpc, rpc_cb cb, LINK2args *args, voi
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/LINK call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1203,7 +1170,6 @@ int rpc_nfs2_symlink_async(struct rpc_context *rpc, rpc_cb cb, SYMLINK2args *arg
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/SYMLINK call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1228,7 +1194,6 @@ int rpc_nfs2_mkdir_async(struct rpc_context *rpc, rpc_cb cb, MKDIR2args *args, v
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/MKDIR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1253,7 +1218,6 @@ int rpc_nfs2_rmdir_async(struct rpc_context *rpc, rpc_cb cb, struct RMDIR2args *
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/RMDIR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1278,7 +1242,6 @@ int rpc_nfs2_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct READDIR2ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/READDIR call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -1303,7 +1266,6 @@ int rpc_nfs2_statfs_async(struct rpc_context *rpc, rpc_cb cb, struct STATFS2args
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/STATFS call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@ int rpc_nfsacl_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/null call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -68,7 +67,6 @@ int rpc_nfsacl_getacl_async(struct rpc_context *rpc, rpc_cb cb, struct GETACL3ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/getacl call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -93,7 +91,6 @@ int rpc_nfsacl_setacl_async(struct rpc_context *rpc, rpc_cb cb, struct SETACL3ar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/setacl call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
noinst_LTLIBRARIES = libnfs4.la
|
||||
|
||||
nfs4_SOURCES_GENERATED =
|
||||
nfs4_HEADERS_GENERATED =
|
||||
nfs4_GENERATED = $(nfs4_SOURCES_GENERATED) $(nfs4_HEADERS_GENERATED)
|
||||
|
||||
CLEANFILES = $(nfs_GENERATED) nfs4-stamp
|
||||
|
||||
libnfs4_la_CPPFLAGS = -I$(abs_top_srcdir)/include \
|
||||
-I$(abs_top_srcdir)/include/nfsc \
|
||||
-I$(abs_top_srcdir)/win32
|
||||
libnfs4_la_SOURCES = \
|
||||
$(nfs4_SOURCES_GENERATED) \
|
||||
nfs4.c libnfs-raw-nfs4.c libnfs-raw-nfs4.h
|
||||
|
||||
$(nfs4_GENERATED) : nfs4-stamp
|
||||
nfs4-stamp : nfs4.x
|
||||
rm -f $(nfs_GENERATED)
|
||||
touch nfs4-stamp
|
||||
|
||||
compile_rpc:
|
||||
cat nfs4.x | head -29 >libnfs-raw-nfs4.h
|
||||
rpcgen -h nfs4.x | sed -e "s/#include <rpc\/rpc.h>/#include <nfsc\/libnfs-zdr.h>/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/#define _NFS_H_RPCGEN/#define _NFS_H_RPCGEN\n#include <nfsc\/libnfs-zdr.h>/g" -e "s/#define NFS3_COOKIEVERFSIZE 8/#define NFS3_COOKIEVERFSIZE 8\n\n/g" -e "s/ CLIENT / void /g" -e "s/SVCXPRT /void /g" -e "s/bool_t/uint32_t/g" >> libnfs-raw-nfs4.h
|
||||
cat nfs4.x | head -29 >libnfs-raw-nfs4.c
|
||||
rpcgen -c nfs4.x | sed -e "s/#include \".*nfs4.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nfs4.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;//" -e "s/bool_t/uint32_t/g" -e "s/int i;//" >> libnfs-raw-nfs4.c
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,219 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
Copyright (C) 2016 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32_compat.h"
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif/*WIN32*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "libnfs-zdr.h"
|
||||
#include "libnfs.h"
|
||||
#include "libnfs-raw.h"
|
||||
#include "libnfs-private.h"
|
||||
#include "libnfs-raw-nfs4.h"
|
||||
|
||||
char *nfsstat4_to_str(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case NFS4_OK: return "NFS4_OK"; break;
|
||||
case NFS4ERR_PERM: return "NFS4ERR_PERM"; break;
|
||||
case NFS4ERR_NOENT: return "NFS4ERR_NOENT"; break;
|
||||
case NFS4ERR_IO: return "NFS4ERR_IO"; break;
|
||||
case NFS4ERR_NXIO: return "NFS4ERR_NXIO"; break;
|
||||
case NFS4ERR_ACCESS: return "NFS4ERR_ACCESS"; break;
|
||||
case NFS4ERR_EXIST: return "NFS4ERR_EXIST"; break;
|
||||
case NFS4ERR_XDEV: return "NFS4ERR_XDEV"; break;
|
||||
case NFS4ERR_NOTDIR: return "NFS4ERR_NOTDIR"; break;
|
||||
case NFS4ERR_ISDIR: return "NFS4ERR_ISDIR"; break;
|
||||
case NFS4ERR_INVAL: return "NFS4ERR_INVAL"; break;
|
||||
case NFS4ERR_FBIG: return "NFS4ERR_FBIG"; break;
|
||||
case NFS4ERR_NOSPC: return "NFS4ERR_NOSPC"; break;
|
||||
case NFS4ERR_ROFS: return"NFS4ERR_ROFS"; break;
|
||||
case NFS4ERR_MLINK: return "NFS4ERR_MLINK"; break;
|
||||
case NFS4ERR_NAMETOOLONG: return "NFS4ERR_NAMETOOLONG"; break;
|
||||
case NFS4ERR_NOTEMPTY: return "NFS4ERR_NOTEMPTY"; break;
|
||||
case NFS4ERR_DQUOT: return "NFS4ERR_DQUOT"; break;
|
||||
case NFS4ERR_STALE: return "NFS4ERR_STALE"; break;
|
||||
case NFS4ERR_BADHANDLE: return "NFS4ERR_BADHANDLE"; break;
|
||||
case NFS4ERR_BAD_COOKIE: return "NFS4ERR_BAD_COOKIE"; break;
|
||||
case NFS4ERR_NOTSUPP: return "NFS4ERR_NOTSUPP"; break;
|
||||
case NFS4ERR_TOOSMALL: return "NFS4ERR_TOOSMALL"; break;
|
||||
case NFS4ERR_SERVERFAULT: return "NFS4ERR_SERVERFAULT"; break;
|
||||
case NFS4ERR_BADTYPE: return "NFS4ERR_BADTYPE"; break;
|
||||
case NFS4ERR_DELAY: return "NFS4ERR_DELAY"; break;
|
||||
case NFS4ERR_SAME: return "NFS4ERR_SAME"; break;
|
||||
case NFS4ERR_DENIED: return "NFS4ERR_DENIED"; break;
|
||||
case NFS4ERR_EXPIRED: return "NFS4ERR_EXPIRED"; break;
|
||||
case NFS4ERR_LOCKED: return "NFS4ERR_LOCKED"; break;
|
||||
case NFS4ERR_GRACE: return "NFS4ERR_GRACE"; break;
|
||||
case NFS4ERR_FHEXPIRED: return "NFS4ERR_FHEXPIRED"; break;
|
||||
case NFS4ERR_SHARE_DENIED: return "NFS4ERR_SHARE_DENIED"; break;
|
||||
case NFS4ERR_WRONGSEC: return "NFS4ERR_WRONGSEC"; break;
|
||||
case NFS4ERR_CLID_INUSE: return "NFS4ERR_CLID_INUSE"; break;
|
||||
case NFS4ERR_RESOURCE: return "NFS4ERR_RESOURCE"; break;
|
||||
case NFS4ERR_MOVED: return "NFS4ERR_MOVED"; break;
|
||||
case NFS4ERR_NOFILEHANDLE: return "NFS4ERR_NOFILEHANDLE"; break;
|
||||
case NFS4ERR_MINOR_VERS_MISMATCH: return "NFS4ERR_MINOR_VERS_MISMATCH"; break;
|
||||
case NFS4ERR_STALE_CLIENTID: return "NFS4ERR_STALE_CLIENTID"; break;
|
||||
case NFS4ERR_STALE_STATEID: return "NFS4ERR_STALE_STATEID"; break;
|
||||
case NFS4ERR_OLD_STATEID: return "NFS4ERR_OLD_STATEID"; break;
|
||||
case NFS4ERR_BAD_STATEID: return "NFS4ERR_BAD_STATEID"; break;
|
||||
case NFS4ERR_BAD_SEQID: return "NFS4ERR_BAD_SEQID"; break;
|
||||
case NFS4ERR_NOT_SAME: return "NFS4ERR_NOT_SAME"; break;
|
||||
case NFS4ERR_LOCK_RANGE: return "NFS4ERR_LOCK_RANGE"; break;
|
||||
case NFS4ERR_SYMLINK: return "NFS4ERR_SYMLINK"; break;
|
||||
case NFS4ERR_RESTOREFH: return "NFS4ERR_RESTOREFH"; break;
|
||||
case NFS4ERR_LEASE_MOVED: return "NFS4ERR_LEASE_MOVED"; break;
|
||||
case NFS4ERR_ATTRNOTSUPP: return "NFS4ERR_ATTRNOTSUPP"; break;
|
||||
case NFS4ERR_NO_GRACE: return "NFS4ERR_NO_GRACE"; break;
|
||||
case NFS4ERR_RECLAIM_BAD: return "NFS4ERR_RECLAIM_BAD"; break;
|
||||
case NFS4ERR_RECLAIM_CONFLICT: return "NFS4ERR_RECLAIM_CONFLICT"; break;
|
||||
case NFS4ERR_BADZDR: return "NFS4ERR_BADZDR"; break;
|
||||
case NFS4ERR_LOCKS_HELD: return "NFS4ERR_LOCKS_HELD"; break;
|
||||
case NFS4ERR_OPENMODE: return "NFS4ERR_OPENMODE"; break;
|
||||
case NFS4ERR_BADOWNER: return "NFS4ERR_BADOWNER"; break;
|
||||
case NFS4ERR_BADCHAR: return "NFS4ERR_BADCHAR"; break;
|
||||
case NFS4ERR_BADNAME: return "NFS4ERR_BADNAME"; break;
|
||||
case NFS4ERR_BAD_RANGE: return "NFS4ERR_BAD_RANGE"; break;
|
||||
case NFS4ERR_LOCK_NOTSUPP: return "NFS4ERR_LOCK_NOTSUPP"; break;
|
||||
case NFS4ERR_OP_ILLEGAL: return "NFS4ERR_OP_ILLEGAL"; break;
|
||||
case NFS4ERR_DEADLOCK: return "NFS4ERR_DEADLOCK"; break;
|
||||
case NFS4ERR_FILE_OPEN: return "NFS4ERR_FILE_OPEN"; break;
|
||||
case NFS4ERR_ADMIN_REVOKED: return "NFS4ERR_ADMIN_REVOKED"; break;
|
||||
case NFS4ERR_CB_PATH_DOWN: return "NFS4ERR_CB_PATH_DOWN"; break;
|
||||
};
|
||||
return "unknown nfsv4 error";
|
||||
}
|
||||
|
||||
int nfsstat4_to_errno(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case NFS4_OK: return 0;
|
||||
case NFS4ERR_PERM: return -EPERM;
|
||||
case NFS4ERR_NOENT: return -ENOENT ;
|
||||
case NFS4ERR_IO: return -EIO;
|
||||
case NFS4ERR_NXIO: return -ENXIO;
|
||||
case NFS4ERR_ACCESS: return -EACCES ;
|
||||
case NFS4ERR_EXIST: return -EEXIST;
|
||||
case NFS4ERR_XDEV: return -EXDEV;
|
||||
case NFS4ERR_NOTDIR: return -ENOTDIR ;
|
||||
case NFS4ERR_ISDIR: return -EISDIR ;
|
||||
case NFS4ERR_INVAL: return -EINVAL;
|
||||
case NFS4ERR_FBIG: return -EFBIG;
|
||||
case NFS4ERR_NOSPC: return -ENOSPC;
|
||||
case NFS4ERR_ROFS: return -EROFS;
|
||||
case NFS4ERR_MLINK: return -EMLINK;
|
||||
case NFS4ERR_NAMETOOLONG: return -ENAMETOOLONG;
|
||||
case NFS4ERR_NOTEMPTY: return -ENOTEMPTY;
|
||||
case NFS4ERR_DQUOT: return -ERANGE;
|
||||
case NFS4ERR_STALE: return -EIO;
|
||||
case NFS4ERR_BADHANDLE: return -EINVAL;
|
||||
case NFS4ERR_BAD_COOKIE: return -EINVAL;
|
||||
case NFS4ERR_NOTSUPP: return -EINVAL;
|
||||
case NFS4ERR_TOOSMALL: return -EIO;
|
||||
case NFS4ERR_SERVERFAULT: return -EIO;
|
||||
case NFS4ERR_BADTYPE: return -EINVAL;
|
||||
case NFS4ERR_DELAY: return -EIO;
|
||||
case NFS4ERR_SAME: return -EIO;
|
||||
case NFS4ERR_DENIED: return -EIO;
|
||||
case NFS4ERR_EXPIRED: return -EIO;
|
||||
case NFS4ERR_LOCKED: return -EIO;
|
||||
case NFS4ERR_GRACE: return -EIO;
|
||||
case NFS4ERR_FHEXPIRED: return -EIO;
|
||||
case NFS4ERR_SHARE_DENIED: return -EIO;
|
||||
case NFS4ERR_WRONGSEC: return -EIO;
|
||||
case NFS4ERR_CLID_INUSE: return -EIO;
|
||||
case NFS4ERR_RESOURCE: return -EIO;
|
||||
case NFS4ERR_MOVED: return -EIO;
|
||||
case NFS4ERR_NOFILEHANDLE: return -EIO;
|
||||
case NFS4ERR_MINOR_VERS_MISMATCH: return -EIO;
|
||||
case NFS4ERR_STALE_CLIENTID: return -EIO;
|
||||
case NFS4ERR_STALE_STATEID: return -EIO;
|
||||
case NFS4ERR_OLD_STATEID: return -EIO;
|
||||
case NFS4ERR_BAD_STATEID: return -EINVAL;
|
||||
case NFS4ERR_BAD_SEQID: return -EINVAL;
|
||||
case NFS4ERR_NOT_SAME: return -EIO;
|
||||
case NFS4ERR_LOCK_RANGE: return -EIO;
|
||||
case NFS4ERR_SYMLINK: return -EIO;
|
||||
case NFS4ERR_RESTOREFH: return -EIO;
|
||||
case NFS4ERR_ATTRNOTSUPP: return -EINVAL;
|
||||
case NFS4ERR_NO_GRACE: return -EIO;
|
||||
case NFS4ERR_RECLAIM_BAD: return -EIO;
|
||||
case NFS4ERR_RECLAIM_CONFLICT: return -EIO;
|
||||
case NFS4ERR_BADZDR: return -EINVAL;
|
||||
case NFS4ERR_LOCKS_HELD: return -EIO;
|
||||
case NFS4ERR_OPENMODE: return -EIO;
|
||||
case NFS4ERR_BADOWNER: return -EINVAL;
|
||||
case NFS4ERR_BADCHAR: return -EINVAL;
|
||||
case NFS4ERR_BADNAME: return -EINVAL;
|
||||
case NFS4ERR_BAD_RANGE: return -EINVAL;
|
||||
case NFS4ERR_LOCK_NOTSUPP: return -EINVAL;
|
||||
case NFS4ERR_OP_ILLEGAL: return -EIO;
|
||||
case NFS4ERR_DEADLOCK: return -EIO;
|
||||
case NFS4ERR_FILE_OPEN: return -EIO;
|
||||
case NFS4ERR_ADMIN_REVOKED: return -EIO;
|
||||
case NFS4ERR_CB_PATH_DOWN: return -EIO;
|
||||
};
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
int rpc_nfs4_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
|
||||
pdu = rpc_allocate_pdu(rpc, NFS4_PROGRAM, NFS_V4, NFSPROC4_NULL, cb, private_data, (zdrproc_t)zdr_void, 0);
|
||||
if (pdu == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS4/NULL call");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS4/NULL call");
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpc_nfs4_compound_async(struct rpc_context *rpc, rpc_cb cb, struct COMPOUND4args *args, void *private_data)
|
||||
{
|
||||
struct rpc_pdu *pdu;
|
||||
|
||||
pdu = rpc_allocate_pdu(rpc, NFS4_PROGRAM, NFS_V4, NFSPROC4_COMPOUND, cb, private_data, (zdrproc_t)zdr_COMPOUND4res, sizeof(COMPOUND4res));
|
||||
if (pdu == NULL) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS4/COMPOUND call");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zdr_COMPOUND4args(&pdu->zdr, args) == 0) {
|
||||
rpc_set_error(rpc, "ZDR error: Failed to encode COMPOUND4args");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS4/COMPOUND4 call");
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -39,7 +39,6 @@ int rpc_nlm4_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/null call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,6 @@ int rpc_nlm4_test_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_TESTargs
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/test call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -89,7 +87,6 @@ int rpc_nlm4_lock_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_LOCKargs
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/lock call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -114,7 +111,6 @@ int rpc_nlm4_cancel_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_CANCar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/cancel call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -139,7 +135,6 @@ int rpc_nlm4_unlock_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_UNLOCK
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/unlock call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@ int rpc_nsm1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/null call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,6 @@ int rpc_nsm1_stat_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_STATargs
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/stat call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -89,7 +87,6 @@ int rpc_nsm1_mon_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_MONargs *
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/mon call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -114,7 +111,6 @@ int rpc_nsm1_unmon_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_UNMONar
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/unmon call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -139,7 +135,6 @@ int rpc_nsm1_unmonall_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_UNMO
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/unmonall call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -158,7 +153,6 @@ int rpc_nsm1_simucrash_async(struct rpc_context *rpc, rpc_cb cb, void *private_d
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/simucrash call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -183,7 +177,6 @@ int rpc_nsm1_notify_async(struct rpc_context *rpc, rpc_cb cb, struct NSM1_NOTIFY
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nsm/notify call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,4 +22,4 @@ compile_rpc:
|
|||
cat portmap.x | head -29 >libnfs-raw-portmap.h
|
||||
rpcgen -h portmap.x | sed -e "s/#include <rpc\/rpc.h>/#include <nfsc\/libnfs-zdr.h>/" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/ CLIENT / void /g" -e "s/SVCXPRT /void /g" -e "s/bool_t/uint32_t/g" >> libnfs-raw-portmap.h
|
||||
cat portmap.x | head -29 >libnfs-raw-portmap.c
|
||||
rpcgen -c portmap.x | sed -e "s/#include \".*portmap.h\"/#include \"libnfs-zdr.h\"\n#include \"libnfs-raw-portmap.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n buf = NULL;/" -e "s/bool_t/uint32_t/g" >> libnfs-raw-portmap.c
|
||||
rpcgen -c portmap.x | sed -e "s/#include \".*portmap.h\"/#include \"libnfs-zdr.h\"\n#include \"libnfs-raw-portmap.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;//" -e "s/bool_t/uint32_t/g" -e "s/[ \t]*buf = / int32_t *buf;\n buf = /" >> libnfs-raw-portmap.c
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
Copyright (c) 2014, Ronnie Sahlberg
|
||||
All rights reserved.
|
||||
|
@ -26,7 +27,6 @@ The views and conclusions contained in the software and documentation are those
|
|||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Please do not edit this file.
|
||||
* It was generated using rpcgen.
|
||||
|
@ -38,10 +38,11 @@ either expressed or implied, of the FreeBSD Project.
|
|||
uint32_t
|
||||
zdr_pmap2_mapping (ZDR *zdrs, pmap2_mapping *objp)
|
||||
{
|
||||
register int32_t *buf;
|
||||
buf = NULL;
|
||||
|
||||
|
||||
|
||||
if (zdrs->x_op == ZDR_ENCODE) {
|
||||
int32_t *buf;
|
||||
buf = ZDR_INLINE (zdrs, 4 * BYTES_PER_ZDR_UNIT);
|
||||
if (buf == NULL) {
|
||||
if (!zdr_u_int (zdrs, &objp->prog))
|
||||
|
@ -60,6 +61,7 @@ zdr_pmap2_mapping (ZDR *zdrs, pmap2_mapping *objp)
|
|||
}
|
||||
return TRUE;
|
||||
} else if (zdrs->x_op == ZDR_DECODE) {
|
||||
int32_t *buf;
|
||||
buf = ZDR_INLINE (zdrs, 4 * BYTES_PER_ZDR_UNIT);
|
||||
if (buf == NULL) {
|
||||
if (!zdr_u_int (zdrs, &objp->prog))
|
||||
|
@ -93,10 +95,11 @@ zdr_pmap2_mapping (ZDR *zdrs, pmap2_mapping *objp)
|
|||
uint32_t
|
||||
zdr_pmap2_call_args (ZDR *zdrs, pmap2_call_args *objp)
|
||||
{
|
||||
register int32_t *buf;
|
||||
buf = NULL;
|
||||
|
||||
|
||||
|
||||
if (zdrs->x_op == ZDR_ENCODE) {
|
||||
int32_t *buf;
|
||||
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
|
||||
if (buf == NULL) {
|
||||
if (!zdr_u_int (zdrs, &objp->prog))
|
||||
|
@ -115,6 +118,7 @@ zdr_pmap2_call_args (ZDR *zdrs, pmap2_call_args *objp)
|
|||
return FALSE;
|
||||
return TRUE;
|
||||
} else if (zdrs->x_op == ZDR_DECODE) {
|
||||
int32_t *buf;
|
||||
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
|
||||
if (buf == NULL) {
|
||||
if (!zdr_u_int (zdrs, &objp->prog))
|
||||
|
@ -148,6 +152,8 @@ zdr_pmap2_call_args (ZDR *zdrs, pmap2_call_args *objp)
|
|||
uint32_t
|
||||
zdr_pmap2_call_result (ZDR *zdrs, pmap2_call_result *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_u_int (zdrs, &objp->port))
|
||||
return FALSE;
|
||||
if (!zdr_bytes (zdrs, (char **)&objp->res.res_val, (u_int *) &objp->res.res_len, ~0))
|
||||
|
@ -158,6 +164,8 @@ zdr_pmap2_call_result (ZDR *zdrs, pmap2_call_result *objp)
|
|||
uint32_t
|
||||
zdr_pmap2_mapping_list (ZDR *zdrs, pmap2_mapping_list *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap2_mapping (zdrs, &objp->map))
|
||||
return FALSE;
|
||||
if (!zdr_pointer (zdrs, (char **)&objp->next, sizeof (pmap2_mapping_list), (zdrproc_t) zdr_pmap2_mapping_list))
|
||||
|
@ -168,6 +176,8 @@ zdr_pmap2_mapping_list (ZDR *zdrs, pmap2_mapping_list *objp)
|
|||
uint32_t
|
||||
zdr_pmap2_dump_result (ZDR *zdrs, pmap2_dump_result *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pointer (zdrs, (char **)&objp->list, sizeof (pmap2_mapping_list), (zdrproc_t) zdr_pmap2_mapping_list))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
@ -176,6 +186,8 @@ zdr_pmap2_dump_result (ZDR *zdrs, pmap2_dump_result *objp)
|
|||
uint32_t
|
||||
zdr_pmap3_string_result (ZDR *zdrs, pmap3_string_result *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_string (zdrs, &objp->addr, ~0))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
@ -184,6 +196,8 @@ zdr_pmap3_string_result (ZDR *zdrs, pmap3_string_result *objp)
|
|||
uint32_t
|
||||
zdr_pmap3_mapping (ZDR *zdrs, pmap3_mapping *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_u_int (zdrs, &objp->prog))
|
||||
return FALSE;
|
||||
if (!zdr_u_int (zdrs, &objp->vers))
|
||||
|
@ -200,6 +214,8 @@ zdr_pmap3_mapping (ZDR *zdrs, pmap3_mapping *objp)
|
|||
uint32_t
|
||||
zdr_pmap3_mapping_list (ZDR *zdrs, pmap3_mapping_list *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_mapping (zdrs, &objp->map))
|
||||
return FALSE;
|
||||
if (!zdr_pointer (zdrs, (char **)&objp->next, sizeof (pmap3_mapping_list), (zdrproc_t) zdr_pmap3_mapping_list))
|
||||
|
@ -210,6 +226,8 @@ zdr_pmap3_mapping_list (ZDR *zdrs, pmap3_mapping_list *objp)
|
|||
uint32_t
|
||||
zdr_pmap3_dump_result (ZDR *zdrs, pmap3_dump_result *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pointer (zdrs, (char **)&objp->list, sizeof (pmap3_mapping_list), (zdrproc_t) zdr_pmap3_mapping_list))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
@ -218,10 +236,11 @@ zdr_pmap3_dump_result (ZDR *zdrs, pmap3_dump_result *objp)
|
|||
uint32_t
|
||||
zdr_pmap3_call_args (ZDR *zdrs, pmap3_call_args *objp)
|
||||
{
|
||||
register int32_t *buf;
|
||||
buf = NULL;
|
||||
|
||||
|
||||
|
||||
if (zdrs->x_op == ZDR_ENCODE) {
|
||||
int32_t *buf;
|
||||
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
|
||||
if (buf == NULL) {
|
||||
if (!zdr_u_int (zdrs, &objp->prog))
|
||||
|
@ -240,6 +259,7 @@ zdr_pmap3_call_args (ZDR *zdrs, pmap3_call_args *objp)
|
|||
return FALSE;
|
||||
return TRUE;
|
||||
} else if (zdrs->x_op == ZDR_DECODE) {
|
||||
int32_t *buf;
|
||||
buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
|
||||
if (buf == NULL) {
|
||||
if (!zdr_u_int (zdrs, &objp->prog))
|
||||
|
@ -273,6 +293,8 @@ zdr_pmap3_call_args (ZDR *zdrs, pmap3_call_args *objp)
|
|||
uint32_t
|
||||
zdr_pmap3_call_result (ZDR *zdrs, pmap3_call_result *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_u_int (zdrs, &objp->port))
|
||||
return FALSE;
|
||||
if (!zdr_bytes (zdrs, (char **)&objp->res.res_val, (u_int *) &objp->res.res_len, ~0))
|
||||
|
@ -283,9 +305,171 @@ zdr_pmap3_call_result (ZDR *zdrs, pmap3_call_result *objp)
|
|||
uint32_t
|
||||
zdr_pmap3_netbuf (ZDR *zdrs, pmap3_netbuf *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_u_int (zdrs, &objp->maxlen))
|
||||
return FALSE;
|
||||
if (!zdr_bytes (zdrs, (char **)&objp->buf.buf_val, (u_int *) &objp->buf.buf_len, ~0))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP2SETargs (ZDR *zdrs, PMAP2SETargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap2_mapping (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP2UNSETargs (ZDR *zdrs, PMAP2UNSETargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap2_mapping (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP2GETPORTargs (ZDR *zdrs, PMAP2GETPORTargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap2_mapping (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP2CALLITargs (ZDR *zdrs, PMAP2CALLITargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap2_call_args (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP2CALLITres (ZDR *zdrs, PMAP2CALLITres *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap2_call_result (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP2DUMPres (ZDR *zdrs, PMAP2DUMPres *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap2_dump_result (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3SETargs (ZDR *zdrs, PMAP3SETargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_mapping (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3UNSETargs (ZDR *zdrs, PMAP3UNSETargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_mapping (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3GETADDRargs (ZDR *zdrs, PMAP3GETADDRargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_mapping (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3GETADDRres (ZDR *zdrs, PMAP3GETADDRres *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_string_result (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3DUMPres (ZDR *zdrs, PMAP3DUMPres *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_dump_result (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3CALLITargs (ZDR *zdrs, PMAP3CALLITargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_call_result (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3CALLITres (ZDR *zdrs, PMAP3CALLITres *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_call_result (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3UADDR2TADDRres (ZDR *zdrs, PMAP3UADDR2TADDRres *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_netbuf (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3TADDR2UADDRargs (ZDR *zdrs, PMAP3TADDR2UADDRargs *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_netbuf (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
zdr_PMAP3TADDR2UADDRres (ZDR *zdrs, PMAP3TADDR2UADDRres *objp)
|
||||
{
|
||||
|
||||
|
||||
if (!zdr_pmap3_string_result (zdrs, objp))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
Copyright (c) 2014, Ronnie Sahlberg
|
||||
All rights reserved.
|
||||
|
@ -26,7 +27,6 @@ The views and conclusions contained in the software and documentation are those
|
|||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Please do not edit this file.
|
||||
* It was generated using rpcgen.
|
||||
|
@ -137,6 +137,38 @@ struct pmap3_netbuf {
|
|||
};
|
||||
typedef struct pmap3_netbuf pmap3_netbuf;
|
||||
|
||||
typedef pmap2_mapping PMAP2SETargs;
|
||||
|
||||
typedef pmap2_mapping PMAP2UNSETargs;
|
||||
|
||||
typedef pmap2_mapping PMAP2GETPORTargs;
|
||||
|
||||
typedef pmap2_call_args PMAP2CALLITargs;
|
||||
|
||||
typedef pmap2_call_result PMAP2CALLITres;
|
||||
|
||||
typedef pmap2_dump_result PMAP2DUMPres;
|
||||
|
||||
typedef pmap3_mapping PMAP3SETargs;
|
||||
|
||||
typedef pmap3_mapping PMAP3UNSETargs;
|
||||
|
||||
typedef pmap3_mapping PMAP3GETADDRargs;
|
||||
|
||||
typedef pmap3_string_result PMAP3GETADDRres;
|
||||
|
||||
typedef pmap3_dump_result PMAP3DUMPres;
|
||||
|
||||
typedef pmap3_call_result PMAP3CALLITargs;
|
||||
|
||||
typedef pmap3_call_result PMAP3CALLITres;
|
||||
|
||||
typedef pmap3_netbuf PMAP3UADDR2TADDRres;
|
||||
|
||||
typedef pmap3_netbuf PMAP3TADDR2UADDRargs;
|
||||
|
||||
typedef pmap3_string_result PMAP3TADDR2UADDRres;
|
||||
|
||||
#define PMAP_PROGRAM 100000
|
||||
#define PMAP_V2 2
|
||||
|
||||
|
@ -145,20 +177,20 @@ typedef struct pmap3_netbuf pmap3_netbuf;
|
|||
extern void * pmap2_null_2(void *, void *);
|
||||
extern void * pmap2_null_2_svc(void *, struct svc_req *);
|
||||
#define PMAP2_SET 1
|
||||
extern uint32_t * pmap2_set_2(pmap2_mapping *, void *);
|
||||
extern uint32_t * pmap2_set_2_svc(pmap2_mapping *, struct svc_req *);
|
||||
extern uint32_t * pmap2_set_2(PMAP2SETargs *, void *);
|
||||
extern uint32_t * pmap2_set_2_svc(PMAP2SETargs *, struct svc_req *);
|
||||
#define PMAP2_UNSET 2
|
||||
extern uint32_t * pmap2_unset_2(pmap2_mapping *, void *);
|
||||
extern uint32_t * pmap2_unset_2_svc(pmap2_mapping *, struct svc_req *);
|
||||
extern uint32_t * pmap2_unset_2(PMAP2UNSETargs *, void *);
|
||||
extern uint32_t * pmap2_unset_2_svc(PMAP2UNSETargs *, struct svc_req *);
|
||||
#define PMAP2_GETPORT 3
|
||||
extern u_int * pmap2_getport_2(pmap2_mapping *, void *);
|
||||
extern u_int * pmap2_getport_2_svc(pmap2_mapping *, struct svc_req *);
|
||||
extern uint32_t * pmap2_getport_2(PMAP2GETPORTargs *, void *);
|
||||
extern uint32_t * pmap2_getport_2_svc(PMAP2GETPORTargs *, struct svc_req *);
|
||||
#define PMAP2_DUMP 4
|
||||
extern pmap2_dump_result * pmap2_dump_2(void *, void *);
|
||||
extern pmap2_dump_result * pmap2_dump_2_svc(void *, struct svc_req *);
|
||||
extern PMAP2DUMPres * pmap2_dump_2(void *, void *);
|
||||
extern PMAP2DUMPres * pmap2_dump_2_svc(void *, struct svc_req *);
|
||||
#define PMAP2_CALLIT 5
|
||||
extern pmap2_call_result * pmap2_callit_2(pmap2_call_args *, void *);
|
||||
extern pmap2_call_result * pmap2_callit_2_svc(pmap2_call_args *, struct svc_req *);
|
||||
extern PMAP2CALLITres * pmap2_callit_2(PMAP2CALLITargs *, void *);
|
||||
extern PMAP2CALLITres * pmap2_callit_2_svc(PMAP2CALLITargs *, struct svc_req *);
|
||||
extern int pmap_program_2_freeresult (void *, zdrproc_t, caddr_t);
|
||||
|
||||
#else /* K&R C */
|
||||
|
@ -172,14 +204,14 @@ extern uint32_t * pmap2_set_2_svc();
|
|||
extern uint32_t * pmap2_unset_2();
|
||||
extern uint32_t * pmap2_unset_2_svc();
|
||||
#define PMAP2_GETPORT 3
|
||||
extern u_int * pmap2_getport_2();
|
||||
extern u_int * pmap2_getport_2_svc();
|
||||
extern uint32_t * pmap2_getport_2();
|
||||
extern uint32_t * pmap2_getport_2_svc();
|
||||
#define PMAP2_DUMP 4
|
||||
extern pmap2_dump_result * pmap2_dump_2();
|
||||
extern pmap2_dump_result * pmap2_dump_2_svc();
|
||||
extern PMAP2DUMPres * pmap2_dump_2();
|
||||
extern PMAP2DUMPres * pmap2_dump_2_svc();
|
||||
#define PMAP2_CALLIT 5
|
||||
extern pmap2_call_result * pmap2_callit_2();
|
||||
extern pmap2_call_result * pmap2_callit_2_svc();
|
||||
extern PMAP2CALLITres * pmap2_callit_2();
|
||||
extern PMAP2CALLITres * pmap2_callit_2_svc();
|
||||
extern int pmap_program_2_freeresult ();
|
||||
#endif /* K&R C */
|
||||
#define PMAP_V3 3
|
||||
|
@ -189,29 +221,29 @@ extern int pmap_program_2_freeresult ();
|
|||
extern void * pmap3_null_3(void *, void *);
|
||||
extern void * pmap3_null_3_svc(void *, struct svc_req *);
|
||||
#define PMAP3_SET 1
|
||||
extern uint32_t * pmap3_set_3(pmap3_mapping *, void *);
|
||||
extern uint32_t * pmap3_set_3_svc(pmap3_mapping *, struct svc_req *);
|
||||
extern uint32_t * pmap3_set_3(PMAP3SETargs *, void *);
|
||||
extern uint32_t * pmap3_set_3_svc(PMAP3SETargs *, struct svc_req *);
|
||||
#define PMAP3_UNSET 2
|
||||
extern uint32_t * pmap3_unset_3(pmap3_mapping *, void *);
|
||||
extern uint32_t * pmap3_unset_3_svc(pmap3_mapping *, struct svc_req *);
|
||||
extern uint32_t * pmap3_unset_3(PMAP3UNSETargs *, void *);
|
||||
extern uint32_t * pmap3_unset_3_svc(PMAP3UNSETargs *, struct svc_req *);
|
||||
#define PMAP3_GETADDR 3
|
||||
extern pmap3_string_result * pmap3_getaddr_3(pmap3_mapping *, void *);
|
||||
extern pmap3_string_result * pmap3_getaddr_3_svc(pmap3_mapping *, struct svc_req *);
|
||||
extern PMAP3GETADDRres * pmap3_getaddr_3(PMAP3GETADDRargs *, void *);
|
||||
extern PMAP3GETADDRres * pmap3_getaddr_3_svc(PMAP3GETADDRargs *, struct svc_req *);
|
||||
#define PMAP3_DUMP 4
|
||||
extern pmap3_dump_result * pmap3_dump_3(void *, void *);
|
||||
extern pmap3_dump_result * pmap3_dump_3_svc(void *, struct svc_req *);
|
||||
extern PMAP3DUMPres * pmap3_dump_3(void *, void *);
|
||||
extern PMAP3DUMPres * pmap3_dump_3_svc(void *, struct svc_req *);
|
||||
#define PMAP3_CALLIT 5
|
||||
extern pmap3_call_result * pmap3_callit_3(pmap3_call_args *, void *);
|
||||
extern pmap3_call_result * pmap3_callit_3_svc(pmap3_call_args *, struct svc_req *);
|
||||
extern PMAP3CALLITres * pmap3_callit_3(PMAP3CALLITargs *, void *);
|
||||
extern PMAP3CALLITres * pmap3_callit_3_svc(PMAP3CALLITargs *, struct svc_req *);
|
||||
#define PMAP3_GETTIME 6
|
||||
extern u_int * pmap3_gettime_3(void *, void *);
|
||||
extern u_int * pmap3_gettime_3_svc(void *, struct svc_req *);
|
||||
extern uint32_t * pmap3_gettime_3(void *, void *);
|
||||
extern uint32_t * pmap3_gettime_3_svc(void *, struct svc_req *);
|
||||
#define PMAP3_UADDR2TADDR 7
|
||||
extern pmap3_netbuf * pmap3_uaddr2taddr_3(char **, void *);
|
||||
extern pmap3_netbuf * pmap3_uaddr2taddr_3_svc(char **, struct svc_req *);
|
||||
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3(char **, void *);
|
||||
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3_svc(char **, struct svc_req *);
|
||||
#define PMAP3_TADDR2UADDR 8
|
||||
extern struct pmap3_string_result * pmap3_taddr2uaddr_3(pmap3_netbuf *, void *);
|
||||
extern struct pmap3_string_result * pmap3_taddr2uaddr_3_svc(pmap3_netbuf *, struct svc_req *);
|
||||
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3(PMAP3TADDR2UADDRargs *, void *);
|
||||
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3_svc(PMAP3TADDR2UADDRargs *, struct svc_req *);
|
||||
extern int pmap_program_3_freeresult (void *, zdrproc_t, caddr_t);
|
||||
|
||||
#else /* K&R C */
|
||||
|
@ -225,23 +257,23 @@ extern uint32_t * pmap3_set_3_svc();
|
|||
extern uint32_t * pmap3_unset_3();
|
||||
extern uint32_t * pmap3_unset_3_svc();
|
||||
#define PMAP3_GETADDR 3
|
||||
extern pmap3_string_result * pmap3_getaddr_3();
|
||||
extern pmap3_string_result * pmap3_getaddr_3_svc();
|
||||
extern PMAP3GETADDRres * pmap3_getaddr_3();
|
||||
extern PMAP3GETADDRres * pmap3_getaddr_3_svc();
|
||||
#define PMAP3_DUMP 4
|
||||
extern pmap3_dump_result * pmap3_dump_3();
|
||||
extern pmap3_dump_result * pmap3_dump_3_svc();
|
||||
extern PMAP3DUMPres * pmap3_dump_3();
|
||||
extern PMAP3DUMPres * pmap3_dump_3_svc();
|
||||
#define PMAP3_CALLIT 5
|
||||
extern pmap3_call_result * pmap3_callit_3();
|
||||
extern pmap3_call_result * pmap3_callit_3_svc();
|
||||
extern PMAP3CALLITres * pmap3_callit_3();
|
||||
extern PMAP3CALLITres * pmap3_callit_3_svc();
|
||||
#define PMAP3_GETTIME 6
|
||||
extern u_int * pmap3_gettime_3();
|
||||
extern u_int * pmap3_gettime_3_svc();
|
||||
extern uint32_t * pmap3_gettime_3();
|
||||
extern uint32_t * pmap3_gettime_3_svc();
|
||||
#define PMAP3_UADDR2TADDR 7
|
||||
extern pmap3_netbuf * pmap3_uaddr2taddr_3();
|
||||
extern pmap3_netbuf * pmap3_uaddr2taddr_3_svc();
|
||||
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3();
|
||||
extern PMAP3UADDR2TADDRres * pmap3_uaddr2taddr_3_svc();
|
||||
#define PMAP3_TADDR2UADDR 8
|
||||
extern struct pmap3_string_result * pmap3_taddr2uaddr_3();
|
||||
extern struct pmap3_string_result * pmap3_taddr2uaddr_3_svc();
|
||||
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3();
|
||||
extern PMAP3TADDR2UADDRres * pmap3_taddr2uaddr_3_svc();
|
||||
extern int pmap_program_3_freeresult ();
|
||||
#endif /* K&R C */
|
||||
|
||||
|
@ -260,6 +292,22 @@ extern uint32_t zdr_pmap3_dump_result (ZDR *, pmap3_dump_result*);
|
|||
extern uint32_t zdr_pmap3_call_args (ZDR *, pmap3_call_args*);
|
||||
extern uint32_t zdr_pmap3_call_result (ZDR *, pmap3_call_result*);
|
||||
extern uint32_t zdr_pmap3_netbuf (ZDR *, pmap3_netbuf*);
|
||||
extern uint32_t zdr_PMAP2SETargs (ZDR *, PMAP2SETargs*);
|
||||
extern uint32_t zdr_PMAP2UNSETargs (ZDR *, PMAP2UNSETargs*);
|
||||
extern uint32_t zdr_PMAP2GETPORTargs (ZDR *, PMAP2GETPORTargs*);
|
||||
extern uint32_t zdr_PMAP2CALLITargs (ZDR *, PMAP2CALLITargs*);
|
||||
extern uint32_t zdr_PMAP2CALLITres (ZDR *, PMAP2CALLITres*);
|
||||
extern uint32_t zdr_PMAP2DUMPres (ZDR *, PMAP2DUMPres*);
|
||||
extern uint32_t zdr_PMAP3SETargs (ZDR *, PMAP3SETargs*);
|
||||
extern uint32_t zdr_PMAP3UNSETargs (ZDR *, PMAP3UNSETargs*);
|
||||
extern uint32_t zdr_PMAP3GETADDRargs (ZDR *, PMAP3GETADDRargs*);
|
||||
extern uint32_t zdr_PMAP3GETADDRres (ZDR *, PMAP3GETADDRres*);
|
||||
extern uint32_t zdr_PMAP3DUMPres (ZDR *, PMAP3DUMPres*);
|
||||
extern uint32_t zdr_PMAP3CALLITargs (ZDR *, PMAP3CALLITargs*);
|
||||
extern uint32_t zdr_PMAP3CALLITres (ZDR *, PMAP3CALLITres*);
|
||||
extern uint32_t zdr_PMAP3UADDR2TADDRres (ZDR *, PMAP3UADDR2TADDRres*);
|
||||
extern uint32_t zdr_PMAP3TADDR2UADDRargs (ZDR *, PMAP3TADDR2UADDRargs*);
|
||||
extern uint32_t zdr_PMAP3TADDR2UADDRres (ZDR *, PMAP3TADDR2UADDRres*);
|
||||
|
||||
#else /* K&R C */
|
||||
extern uint32_t zdr_pmap2_mapping ();
|
||||
|
@ -274,6 +322,22 @@ extern uint32_t zdr_pmap3_dump_result ();
|
|||
extern uint32_t zdr_pmap3_call_args ();
|
||||
extern uint32_t zdr_pmap3_call_result ();
|
||||
extern uint32_t zdr_pmap3_netbuf ();
|
||||
extern uint32_t zdr_PMAP2SETargs ();
|
||||
extern uint32_t zdr_PMAP2UNSETargs ();
|
||||
extern uint32_t zdr_PMAP2GETPORTargs ();
|
||||
extern uint32_t zdr_PMAP2CALLITargs ();
|
||||
extern uint32_t zdr_PMAP2CALLITres ();
|
||||
extern uint32_t zdr_PMAP2DUMPres ();
|
||||
extern uint32_t zdr_PMAP3SETargs ();
|
||||
extern uint32_t zdr_PMAP3UNSETargs ();
|
||||
extern uint32_t zdr_PMAP3GETADDRargs ();
|
||||
extern uint32_t zdr_PMAP3GETADDRres ();
|
||||
extern uint32_t zdr_PMAP3DUMPres ();
|
||||
extern uint32_t zdr_PMAP3CALLITargs ();
|
||||
extern uint32_t zdr_PMAP3CALLITres ();
|
||||
extern uint32_t zdr_PMAP3UADDR2TADDRres ();
|
||||
extern uint32_t zdr_PMAP3TADDR2UADDRargs ();
|
||||
extern uint32_t zdr_PMAP3TADDR2UADDRres ();
|
||||
|
||||
#endif /* K&R C */
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ int rpc_pmap2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for PORTMAP2/NULL call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -70,7 +69,6 @@ int rpc_pmap2_getport_async(struct rpc_context *rpc, int program, int version, i
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP2/GETPORT pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -100,7 +98,6 @@ int rpc_pmap2_set_async(struct rpc_context *rpc, int program, int version, int p
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP2/SET pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -130,7 +127,6 @@ int rpc_pmap2_unset_async(struct rpc_context *rpc, int program, int version, int
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP2/UNSET pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -149,7 +145,6 @@ int rpc_pmap2_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP2/DUMP pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -202,7 +197,6 @@ int rpc_pmap3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for PORTMAP3/NULL call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -227,7 +221,6 @@ int rpc_pmap3_set_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP3/SET pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -252,7 +245,6 @@ int rpc_pmap3_unset_async(struct rpc_context *rpc, struct pmap3_mapping *map, rp
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP3/UNSET pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -277,7 +269,6 @@ int rpc_pmap3_getaddr_async(struct rpc_context *rpc, struct pmap3_mapping *map,
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP3/GETADDR pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -296,7 +287,6 @@ int rpc_pmap3_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP3/DUMP pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -315,7 +305,6 @@ int rpc_pmap3_gettime_async(struct rpc_context *rpc, rpc_cb cb, void *private_da
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Failed to queue PORTMAP3/GETTIME pdu");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
Copyright (c) 2014, Ronnie Sahlberg
|
||||
All rights reserved.
|
||||
|
@ -99,53 +100,71 @@ struct pmap3_netbuf {
|
|||
opaque buf<>;
|
||||
};
|
||||
|
||||
typedef pmap2_mapping PMAP2SETargs;
|
||||
typedef pmap2_mapping PMAP2UNSETargs;
|
||||
typedef pmap2_mapping PMAP2GETPORTargs;
|
||||
typedef pmap2_call_args PMAP2CALLITargs;
|
||||
typedef pmap2_call_result PMAP2CALLITres;
|
||||
typedef pmap2_dump_result PMAP2DUMPres;
|
||||
|
||||
typedef pmap3_mapping PMAP3SETargs;
|
||||
typedef pmap3_mapping PMAP3UNSETargs;
|
||||
typedef pmap3_mapping PMAP3GETADDRargs;
|
||||
typedef pmap3_string_result PMAP3GETADDRres;
|
||||
typedef pmap3_dump_result PMAP3DUMPres;
|
||||
typedef pmap3_call_result PMAP3CALLITargs;
|
||||
typedef pmap3_call_result PMAP3CALLITres;
|
||||
typedef pmap3_netbuf PMAP3UADDR2TADDRres;
|
||||
typedef pmap3_netbuf PMAP3TADDR2UADDRargs;
|
||||
typedef pmap3_string_result PMAP3TADDR2UADDRres;
|
||||
|
||||
program PMAP_PROGRAM {
|
||||
version PMAP_V2 {
|
||||
void
|
||||
PMAP2_NULL(void) = 0;
|
||||
|
||||
bool
|
||||
PMAP2_SET(pmap2_mapping) = 1;
|
||||
uint32_t
|
||||
PMAP2_SET(PMAP2SETargs) = 1;
|
||||
|
||||
bool
|
||||
PMAP2_UNSET(pmap2_mapping) = 2;
|
||||
uint32_t
|
||||
PMAP2_UNSET(PMAP2UNSETargs) = 2;
|
||||
|
||||
unsigned int
|
||||
PMAP2_GETPORT(pmap2_mapping) = 3;
|
||||
uint32_t
|
||||
PMAP2_GETPORT(PMAP2GETPORTargs) = 3;
|
||||
|
||||
pmap2_dump_result
|
||||
PMAP2DUMPres
|
||||
PMAP2_DUMP(void) = 4;
|
||||
|
||||
pmap2_call_result
|
||||
PMAP2_CALLIT(pmap2_call_args) = 5;
|
||||
PMAP2CALLITres
|
||||
PMAP2_CALLIT(PMAP2CALLITargs) = 5;
|
||||
} = 2;
|
||||
version PMAP_V3 {
|
||||
void
|
||||
PMAP3_NULL(void) = 0;
|
||||
|
||||
bool
|
||||
PMAP3_SET(pmap3_mapping) = 1;
|
||||
uint32_t
|
||||
PMAP3_SET(PMAP3SETargs) = 1;
|
||||
|
||||
bool
|
||||
PMAP3_UNSET(pmap3_mapping) = 2;
|
||||
uint32_t
|
||||
PMAP3_UNSET(PMAP3UNSETargs) = 2;
|
||||
|
||||
pmap3_string_result
|
||||
PMAP3_GETADDR(pmap3_mapping) = 3;
|
||||
PMAP3GETADDRres
|
||||
PMAP3_GETADDR(PMAP3GETADDRargs) = 3;
|
||||
|
||||
pmap3_dump_result
|
||||
PMAP3DUMPres
|
||||
PMAP3_DUMP(void) = 4;
|
||||
|
||||
pmap3_call_result
|
||||
PMAP3_CALLIT(pmap3_call_args) = 5;
|
||||
PMAP3CALLITres
|
||||
PMAP3_CALLIT(PMAP3CALLITargs) = 5;
|
||||
|
||||
unsigned int
|
||||
uint32_t
|
||||
PMAP3_GETTIME(void) = 6;
|
||||
|
||||
pmap3_netbuf
|
||||
PMAP3UADDR2TADDRres
|
||||
PMAP3_UADDR2TADDR(string) = 7;
|
||||
|
||||
struct pmap3_string_result
|
||||
PMAP3_TADDR2UADDR(pmap3_netbuf) = 8;
|
||||
PMAP3TADDR2UADDRres
|
||||
PMAP3_TADDR2UADDR(PMAP3TADDR2UADDRargs) = 8;
|
||||
} = 3;
|
||||
} = 100000;
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ int rpc_rquota1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_dat
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota1/null call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -91,7 +90,6 @@ int rpc_rquota1_getquota_async(struct rpc_context *rpc, rpc_cb cb, char *export,
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota1/getquota call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -120,7 +118,6 @@ int rpc_rquota1_getactivequota_async(struct rpc_context *rpc, rpc_cb cb, char *e
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota1/getactivequota call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -140,7 +137,6 @@ int rpc_rquota2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_dat
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota2/null call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -170,7 +166,6 @@ int rpc_rquota2_getquota_async(struct rpc_context *rpc, rpc_cb cb, char *export,
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota2/getquota call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
@ -200,7 +195,6 @@ int rpc_rquota2_getactivequota_async(struct rpc_context *rpc, rpc_cb cb, char *e
|
|||
|
||||
if (rpc_queue_pdu(rpc, pdu) != 0) {
|
||||
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota2/getactivequota call");
|
||||
rpc_free_pdu(rpc, pdu);
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;_USE_32BIT_TIME_T;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
|
@ -112,7 +112,7 @@
|
|||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
|
@ -137,7 +137,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;_USE_32BIT_TIME_T;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
@ -162,7 +162,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_U_=;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\include\nfsc;..\..\include;..\..\.;..\..\win32;..\..\mount;..\..\nfs;..\..\nfs4;..\..\portmap;..\..\lib</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
|
@ -192,6 +192,8 @@
|
|||
<ClCompile Include="..\..\nfs\libnfs-raw-nfs.c" />
|
||||
<ClCompile Include="..\..\nfs\nfs.c" />
|
||||
<ClCompile Include="..\..\nfs\nfsacl.c" />
|
||||
<ClCompile Include="..\..\nfs4\libnfs-raw-nfs4.c" />
|
||||
<ClCompile Include="..\..\nfs4\nfs4.c" />
|
||||
<ClCompile Include="..\..\nlm\libnfs-raw-nlm.c" />
|
||||
<ClCompile Include="..\..\nlm\nlm.c" />
|
||||
<ClCompile Include="..\..\nsm\libnfs-raw-nsm.c" />
|
||||
|
@ -206,6 +208,7 @@
|
|||
<ClInclude Include="..\..\include\nfsc\libnfs-zdr.h" />
|
||||
<ClInclude Include="..\..\mount\libnfs-raw-mount.h" />
|
||||
<ClInclude Include="..\..\nfs\libnfs-raw-nfs.h" />
|
||||
<ClInclude Include="..\..\nfs4\libnfs-raw-nfs4.h" />
|
||||
<ClInclude Include="..\..\nlm\libnfs-raw-nlm.h" />
|
||||
<ClInclude Include="..\..\nsm\libnfs-raw-nsm.h" />
|
||||
<ClInclude Include="..\..\portmap\libnfs-raw-portmap.h" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
|
@ -20,6 +20,12 @@
|
|||
<ClCompile Include="..\..\nfs\nfsacl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\nfs4\libnfs-raw-nfs4.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\nfs4\nfs4.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\rquota\libnfs-raw-rquota.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -76,6 +82,9 @@
|
|||
<ClInclude Include="..\..\nfs\libnfs-raw-nfs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\nfs4\libnfs-raw-nfs4.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\rquota\libnfs-raw-rquota.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -64,11 +64,11 @@
|
|||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
|
|
|
@ -64,11 +64,11 @@
|
|||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<LibraryPath>..\libnfs\Release;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
<LibraryPath>..\libnfs\Debug;..\..\bin;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
|
|
|
@ -34,13 +34,15 @@ THE SOFTWARE.
|
|||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef int uid_t;
|
||||
typedef int gid_t;
|
||||
typedef unsigned int uid_t;
|
||||
typedef unsigned int gid_t;
|
||||
typedef int socklen_t;
|
||||
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR 0000400
|
||||
#define S_IWUSR 0000200
|
||||
#define S_IXUSR 0000100
|
||||
#endif
|
||||
#define S_IRWXG 0000070 /* RWX mask for group */
|
||||
#define S_IRGRP 0000040
|
||||
#define S_IWGRP 0000020
|
||||
|
@ -77,8 +79,17 @@ typedef int socklen_t;
|
|||
#define minor(a) 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NONBLOCK
|
||||
#define O_NONBLOCK 0x40000000
|
||||
#endif
|
||||
|
||||
#ifndef O_SYNC
|
||||
#define O_SYNC 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NOFOLLOW
|
||||
#define O_NOFOLLOW 00400000
|
||||
#endif
|
||||
|
||||
#define MSG_DONTWAIT 0
|
||||
#define ssize_t SSIZE_T
|
||||
|
@ -102,11 +113,18 @@ struct pollfd {
|
|||
#define close closesocket
|
||||
#define ioctl ioctlsocket
|
||||
|
||||
#ifndef ESTALE
|
||||
#define ESTALE 116
|
||||
#endif
|
||||
|
||||
/* Wrapper macros to call misc. functions win32 is missing */
|
||||
#define poll(x, y, z) win32_poll(x, y, z)
|
||||
#define snprintf sprintf_s
|
||||
#define inet_pton(x,y,z) win32_inet_pton(x,y,z)
|
||||
#define open(x, y, z) _open(x, y, z)
|
||||
#ifndef lseek
|
||||
#define lseek(x, y, z) _lseek(x, y, z)
|
||||
#endif
|
||||
#define read(x, y, z) _read(x, y, z)
|
||||
#define write(x, y, z) _write(x, y, z)
|
||||
int getpid(void);
|
||||
|
|
Loading…
Reference in New Issue