Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Examples? #1

Open
ktm5j opened this issue Dec 1, 2019 · 4 comments
Open

Examples? #1

ktm5j opened this issue Dec 1, 2019 · 4 comments

Comments

@ktm5j
Copy link

ktm5j commented Dec 1, 2019

Hello! Could you please provide a working example using both sendSnapshot() and receive() from the libzfs_core module with a simple TCP socket?

I've been trying to make this work and I don't know what I'm doing wrong. I can make it work using plain C with libzfs_core.. any advice would be appreciated!

@adamdruppe
Copy link

what code do you have right now?

@ktm5j
Copy link
Author

ktm5j commented Dec 2, 2019

I'm having trouble getting these functions to work in some circumstances.. However just last night I discovered that if use the extern(c) functions from your module directly (lzc_send and lzc_receive) then I can make it work.

For this example, I want to take in 2-3 args from command line: Port to open socket on, snapshot to send and optionally a "from" snapshot. So the command looks like ./send 2020 pool/dataset@snapshot or ./send 2020 pool/dataset@snapshot2 pool/dataset@snapshot1 for an incremental transfer

The following does what I want, using the lzc functions

import core.thread;

import std.conv;
import std.stdio;
import std.socket;
import std.string;

import symmetry.api.libzfs_core;

void main(string[] args) {
    if (args.length < 3)
        exit(1);

    Socket server = new TcpSocket();
    Socket client;
    server.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
    server.bind(new InternetAddress(InternetAddress.ADDR_ANY, to!ushort(args[1])));
    server.listen(10);

    assert(datasetExists(args[2]));
    while(true) {
        writeln("Waiting for client");

        try {
            client = server.accept();

            if (args.length >= 4)        // Incremental
                lzc_send(args[2].toCString, args[3].toCString, cast(int)client.handle, cast(lzc_send_flags)0);
            else                         // Single
               lzc_send(args[2].toCString, null, cast(int)client.handle, cast(lzc_send_flags)0);

        } catch (Exception e) {
            logError("error: %s", e.msg);
            logError("sockerr: %s", server.getErrorText());
        }
        client.close();
    }
}

But if I use the sendSnapshot(args[2], client); function with similar inputs then I get a zfs error: 5, strace shows an error occurring during an ioctl call:

socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 4
bind(4, {sa_family=AF_INET, sin_port=htons(2026), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
listen(4, 10)                           = 0
write(1, "Waiting for client
) = 53
accept(4, NULL, NULL)                   = 5
ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x40, 0), 0x7fffa9208a60) = -1 EINVAL (Invalid argument)
futex(0x7f27d924f1c0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(2, "\33[49;38;5;9m", 12)          = 12
write(2, "error: ", 7error: )                  = 7
write(2, "zfs error", 9zfs error)                = 9
write(2, "\33[0m", 4)                   = 4
write(2, "\n", 1
)                       = 1

Any thoughts? Thanks!

@adamdruppe
Copy link

Huh, the implementation of that function is similar to what you had:

https://github.com/symmetryinvestments/libzfs-core-d/blob/master/source/symmetry/api/libzfs_core.d#L4937

My guess is that fromSnapshot being "" just might be a problem. Perhaps that is being interpreted differently than null. I don't have a system ready right now to test the code myself, but would you mind copy/pasting this code for me:

ORIGINAL FUNCTION

void sendSnapshot(string snapshotName, Socket socket, SendFlag[] flags=[], string fromSnapshot="")
{
 import std.algorithm:fold;
 auto lzcFlags = flags.fold!((a,b) => a| b)(cast(SendFlag)0).to!lzc_send_flags;
 auto result = lzc_send(snapshotName.toCString, fromSnapshot.toCString,cast(int)socket.handle,lzcFlags);
 enforce(result == 0, "zfs error");
}

NEW FUNCTION

void sendSnapshot(string snapshotName, Socket socket, SendFlag[] flags=[], string fromSnapshot = null) // changed "" to null
{
 import std.algorithm:fold;
 auto lzcFlags = flags.fold!((a,b) => a| b)(cast(SendFlag)0).to!lzc_send_flags;
 auto result = lzc_send(snapshotName.toCString, fromSnapshot.length ? fromSnapshot.toCString : null,cast(int)socket.handle,lzcFlags); // changed fromSnapshot to check for null
 enforce(result == 0, "zfs error");
}

and lemme know? This looks like the only real difference between teh function in there and the function you have working.

@ktm5j
Copy link
Author

ktm5j commented Dec 3, 2019

Yes I based my code off of the implementation of your sendSnapshot() function, which is why it looks so similar! And that's why I was so confused that one would work but not the other.

I should be able to try your alternate code tomorrow, or the weekend at the latest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants