From 1e742660bf3fed39b7efa2502d88ee6415522385 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 31 Mar 2009 18:28:49 -0700 Subject: Tidy up some convert_string_internal error cases, found by Andrew Bartlett. Jeremy. --- source3/lib/charcnv.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c index c3b345142f..03b32c13d4 100644 --- a/source3/lib/charcnv.c +++ b/source3/lib/charcnv.c @@ -242,7 +242,7 @@ static size_t convert_string_internal(charset_t from, charset_t to, DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; - break; + return (size_t)-1; case E2BIG: reason="No more room"; if (!conv_silent) { @@ -263,11 +263,12 @@ static size_t convert_string_internal(charset_t from, charset_t to, DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; - break; + + return (size_t)-1; default: if (!conv_silent) DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); - break; + return (size_t)-1; } /* smb_panic(reason); */ } @@ -412,7 +413,11 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); + size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); + if (ret == (size_t)-1) { + return ret; + } + return retval + ret; #endif } } @@ -448,7 +453,11 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); + size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); + if (ret == (size_t)-1) { + return ret; + } + return retval + ret; #endif } } @@ -484,7 +493,11 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); + size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); + if (ret == (size_t)-1) { + return ret; + } + return retval + ret; #endif } } -- cgit From 5000640bf449be27e138a1fb86561d589953c83c Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Wed, 1 Apr 2009 18:44:15 -0700 Subject: s4 torture: Add new streams oplock test --- source4/torture/raw/oplock.c | 176 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 0aeded8664..3493a552c3 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2855,6 +2855,181 @@ done: return ret; } +/* Test how oplocks work on streams. */ +static bool test_raw_oplock_stream1(struct torture_context *tctx, + struct smbcli_state *cli1, + struct smbcli_state *cli2) +{ + NTSTATUS status; + union smb_open io; + const char *fname_base = BASEDIR "\\test_stream1.txt"; + const char *stream = "Stream One:$DATA"; + const char *fname_stream, *fname_default_stream; + const char *default_stream = "::$DATA"; + bool ret = true; + int fnum = -1; + int i; + int stream_fnum = -1; + uint32_t batch_req = NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK | NTCREATEX_FLAGS_EXTENDED; + uint32_t exclusive_req = NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_EXTENDED; + + /* Only passes against windows at the moment. */ + if (torture_setting_bool(tctx, "samba3", false) || + torture_setting_bool(tctx, "samba4", false)) { + torture_skip(tctx, "STREAM1 disabled against samba3+4\n"); + } + + fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream); + fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base, + default_stream); + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + smbcli_unlink(cli1->tree, fname_base); + + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + + /* Setup generic open parameters. */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA| + SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL); + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + + /* Create the file with a stream */ + io.ntcreatex.in.fname = fname_stream; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + smbcli_close(cli1->tree, io.ntcreatex.out.file.fnum); + + /* Change the disposition to open now that the file has been created. */ + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + + /* Try some permutations of taking oplocks on streams. */ +#define NSTREAM_OPLOCK_RESULTS 8 + struct { + const char *fname; + bool open_base_file; + uint32_t oplock_req; + uint32_t oplock_granted; + } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = { + /* Request oplock on stream without the base file open. */ + {fname_stream, false, batch_req, NO_OPLOCK_RETURN}, + {fname_default_stream, false, batch_req, NO_OPLOCK_RETURN}, + {fname_stream, false, exclusive_req, EXCLUSIVE_OPLOCK_RETURN}, + {fname_default_stream, false, exclusive_req, EXCLUSIVE_OPLOCK_RETURN}, + + /* Request oplock on stream with the base file open. */ + {fname_stream, true, batch_req, NO_OPLOCK_RETURN}, + {fname_default_stream, true, batch_req, NO_OPLOCK_RETURN}, + {fname_stream, true, exclusive_req, EXCLUSIVE_OPLOCK_RETURN}, + {fname_default_stream, true, exclusive_req, LEVEL_II_OPLOCK_RETURN}, + + }; + + for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) { + const char *fname = stream_oplock_results[i].fname; + bool open_base_file = stream_oplock_results[i].open_base_file; + uint32_t oplock_req = stream_oplock_results[i].oplock_req; + uint32_t oplock_granted = + stream_oplock_results[i].oplock_granted; + int base_fnum = -1; + + if (open_base_file) { + torture_comment(tctx, "Opening base file: %s with " + "%d\n", fname_base, oplock_req); + io.ntcreatex.in.fname = fname_base; + io.ntcreatex.in.flags = batch_req; + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(io.ntcreatex.out.oplock_level, + BATCH_OPLOCK_RETURN); + base_fnum = io.ntcreatex.out.file.fnum; + } + + torture_comment(tctx, "%d: Opening stream: %s with %d\n", i, + fname, oplock_req); + io.ntcreatex.in.fname = fname; + io.ntcreatex.in.flags = oplock_req; + + /* Do the open with the desired oplock on the stream. */ + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(io.ntcreatex.out.oplock_level, oplock_granted); + smbcli_close(cli1->tree, io.ntcreatex.out.file.fnum); + + /* Cleanup the base file if it was opened. */ + if (base_fnum != -1) { + smbcli_close(cli2->tree, base_fnum); + } + } + + /* Open the stream with an exclusive oplock. */ + torture_comment(tctx, "Opening stream: %s with %d\n", + fname_stream, exclusive_req); + io.ntcreatex.in.fname = fname_stream; + io.ntcreatex.in.flags = exclusive_req; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN); + stream_fnum = io.ntcreatex.out.file.fnum; + + /* Open the base file and see if it contends. */ + ZERO_STRUCT(break_info); + torture_comment(tctx, "Opening base file: %s with " + "%d\n", fname_base, batch_req); + io.ntcreatex.in.fname = fname_base; + io.ntcreatex.in.flags = batch_req; + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(io.ntcreatex.out.oplock_level, + BATCH_OPLOCK_RETURN); + smbcli_close(cli2->tree, io.ntcreatex.out.file.fnum); + + CHECK_VAL(break_info.count, 0); + CHECK_VAL(break_info.failures, 0); + + /* Open the stream again to see if it contends. */ + ZERO_STRUCT(break_info); + torture_comment(tctx, "Opening stream again: %s with " + "%d\n", fname_base, batch_req); + io.ntcreatex.in.fname = fname_stream; + io.ntcreatex.in.flags = exclusive_req; + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(io.ntcreatex.out.oplock_level, + LEVEL_II_OPLOCK_RETURN); + smbcli_close(cli2->tree, io.ntcreatex.out.file.fnum); + + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + CHECK_VAL(break_info.failures, 0); + + /* Close the stream. */ + if (stream_fnum != -1) { + smbcli_close(cli1->tree, stream_fnum); + } + + done: + smbcli_close(cli1->tree, fnum); + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + /* basic testing of oplocks */ @@ -2893,6 +3068,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "BATCH23", test_raw_oplock_batch23); torture_suite_add_2smb_test(suite, "BATCH24", test_raw_oplock_batch24); torture_suite_add_2smb_test(suite, "BATCH25", test_raw_oplock_batch25); + torture_suite_add_2smb_test(suite, "STREAM1", test_raw_oplock_stream1); return suite; } -- cgit From f92140b71623ecb0eb7238a550ae9d8d488a4c90 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Wed, 1 Apr 2009 18:55:52 -0700 Subject: s4 torture: Remove unused parameter --- source4/torture/raw/streams.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c index d0d21ccc06..818eb402dd 100644 --- a/source4/torture/raw/streams.c +++ b/source4/torture/raw/streams.c @@ -1309,7 +1309,6 @@ static bool test_stream_rename2(struct torture_context *tctx, static bool create_file_with_stream(struct torture_context *tctx, struct smbcli_state *cli, TALLOC_CTX *mem_ctx, - const char *base_fname, const char *stream) { NTSTATUS status; @@ -1359,8 +1358,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx, stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream); stream_list[1] = default_stream_name; - if (!create_file_with_stream(tctx, cli, mem_ctx, fname, - fname_stream)) { + if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) { goto done; } @@ -1407,8 +1405,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx, */ printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__); smbcli_unlink(cli->tree, fname); - if (!create_file_with_stream(tctx, cli, mem_ctx, fname, - fname_stream)) { + if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) { goto done; } @@ -1425,8 +1422,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx, */ printf("(%s) Checking ntcreatex disp: supersede\n", __location__); smbcli_unlink(cli->tree, fname); - if (!create_file_with_stream(tctx, cli, mem_ctx, fname, - fname_stream)) { + if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) { goto done; } @@ -1444,8 +1440,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx, printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n", __location__); smbcli_unlink(cli->tree, fname); - if (!create_file_with_stream(tctx, cli, mem_ctx, fname, - fname_stream)) { + if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) { goto done; } @@ -1463,8 +1458,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx, */ printf("(%s) Checking openx disp: overwrite_if\n", __location__); smbcli_unlink(cli->tree, fname); - if (!create_file_with_stream(tctx, cli, mem_ctx, fname, - fname_stream)) { + if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) { goto done; } @@ -1517,7 +1511,7 @@ static bool test_stream_large_streaminfo(struct torture_context *tctx, for (i = 0; i < 10000; i++) { fname_stream = talloc_asprintf(mem_ctx, "%s:%s%d", fname, lstream_name, i); - ret = create_file_with_stream(tctx, cli, mem_ctx, fname, + ret = create_file_with_stream(tctx, cli, mem_ctx, fname_stream); if (!ret) { goto done; @@ -1556,8 +1550,7 @@ static bool test_stream_attributes(struct torture_context *tctx, fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream); /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */ - ret = create_file_with_stream(tctx, cli, mem_ctx, fname, - fname_stream); + ret = create_file_with_stream(tctx, cli, mem_ctx, fname_stream); if (!ret) { goto done; } -- cgit From 87fe4d732d18d18ed56c99cba6a395a0bf9e9d95 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Thu, 2 Apr 2009 03:01:34 +0000 Subject: s3 onefs: Quiet a log message about oplocks being requested on streams --- source3/modules/onefs_open.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c index d628443ef9..f315b34c8b 100644 --- a/source3/modules/onefs_open.c +++ b/source3/modules/onefs_open.c @@ -199,23 +199,6 @@ static NTSTATUS onefs_open_file(files_struct *fsp, if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && stream != NULL) { SMB_ASSERT(fsp->base_fsp); - /* - * We have never seen an oplock taken on a stream, and our - * current implementation doesn't support it. If a request is - * seen, log a loud error message and ignore the requested - * oplock. - */ - if ((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) != - NO_OPLOCK) { - DEBUG(0, ("Oplock(%d) being requested on a stream! " - "Ignoring oplock request: base=%s, " - "stream=%s\n", - oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK, - base, stream)); - /* Recover by requesting NO_OPLOCK instead. */ - oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK; - } - DEBUG(10,("Opening a stream: base=%s(%d), stream=%s\n", base, fsp->base_fsp->fh->fd, stream)); @@ -522,10 +505,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, * * 1. Open the base file of a stream: Always done stat-only * - * 2. Open the stream: Oplocks are disallowed on streams, so an - * oplock will never be contended. - * - * 3. open_file_fchmod(), which is called from 3 places: + * 2. open_file_fchmod(), which is called from 3 places: * A. try_chown: Posix acls only. Never called on onefs. * B. set_ea_dos_attributes: Can't be called from onefs, because * SMB_VFS_SETXATTR return ENOSYS. @@ -1773,6 +1753,21 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, "failed: %s\n", base, nt_errstr(status))); goto fail; } + + /* + * Testing against windows xp/2003/vista shows that oplocks + * can actually be requested and granted on streams (see the + * RAW-OPLOCK-STREAM1 smbtorture test). + */ + if ((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) != + NO_OPLOCK) { + DEBUG(5, ("Oplock(%d) being requested on a stream! " + "Ignoring oplock request: fname=%s\n", + oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK, + fname)); + /* Request NO_OPLOCK instead. */ + oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK; + } } /* Covert generic bits in the security descriptor. */ -- cgit From c57b32c5ab754cdf99527e4dfc4bb6ff3ca93e25 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 1 Apr 2009 20:20:19 -0700 Subject: Allow pdbedit to change a user rid/sid. Based on a fix from Alexander Zagrebin . Jeremy. --- source3/passdb/pdb_tdb.c | 60 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index 6c49eb1dc2..dd6e678c99 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -817,12 +817,17 @@ static bool tdb_update_ridrec_only( struct samu* newpwd, int flag ) static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag) { - if (!pdb_get_user_rid(newpwd)) { + uint32_t oldrid; + uint32_t newrid; + + if (!(newrid = pdb_get_user_rid(newpwd))) { DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd))); return False; } + oldrid = newrid; + /* open the database */ if ( !tdbsam_open( tdbsam_filename ) ) { @@ -835,11 +840,60 @@ static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, return false; } - if (!tdb_update_samacct_only(newpwd, flag) - || !tdb_update_ridrec_only(newpwd, flag)) { + /* If we are updating, we may be changing this users RID. Retrieve the old RID + so we can check. */ + + if (flag == TDB_MODIFY) { + struct samu *account = samu_new(talloc_tos()); + if (account == NULL) { + DEBUG(0,("tdb_update_sam: samu_new() failed\n")); + goto cancel; + } + if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) { + DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n", + pdb_get_username(newpwd))); + TALLOC_FREE(account); + goto cancel; + } + if (!(oldrid = pdb_get_user_rid(account))) { + DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n")); + TALLOC_FREE(account); + goto cancel; + } + TALLOC_FREE(account); + } + + /* Update the new samu entry. */ + if (!tdb_update_samacct_only(newpwd, flag)) { goto cancel; } + /* Now take care of the case where the RID changed. We need + * to delete the old RID key and add the new. */ + + if (flag == TDB_MODIFY && newrid != oldrid) { + fstring keystr; + + /* Delete old RID key */ + DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid)); + slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid); + if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) { + DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr)); + goto cancel; + } + /* Insert new RID key */ + DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid)); + if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) { + goto cancel; + } + } else { + DEBUG(10, ("tdb_update_sam: %s key for RID %u\n", + flag == TDB_MODIFY ? "Updating" : "Inserting", newrid)); + if (!tdb_update_ridrec_only(newpwd, flag)) { + goto cancel; + } + } + if (db_sam->transaction_commit(db_sam) != 0) { DEBUG(0, ("Could not commit transaction\n")); return false; -- cgit From 9d95f8704d4dab70d50290ebd1e3c0b8800261a7 Mon Sep 17 00:00:00 2001 From: Zach Loafman Date: Wed, 1 Apr 2009 11:06:51 -0700 Subject: s/NT_STATUS_WIN7_INVALID_RANGE/NT_STATUS_INVALID_LOCK_RANGE/g --- libcli/util/ntstatus.h | 4 ++-- source4/libcli/util/nterr.c | 2 +- source4/torture/raw/lock.c | 4 ++-- source4/torture/smb2/lock.c | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h index 1608e2874f..a97ef5337e 100644 --- a/libcli/util/ntstatus.h +++ b/libcli/util/ntstatus.h @@ -60,8 +60,8 @@ typedef uint32_t NTSTATUS; #define ERROR_INSUFFICIENT_BUFFER NT_STATUS(0x007a) #define ERROR_INVALID_DATATYPE NT_STATUS(0x070c) -/* XXX Win7 Status code: Name unknown. */ -#define NT_STATUS_WIN7_INVALID_RANGE NT_STATUS(0xC0000000 | 0x01a1) +/* Win7 status codes. */ +#define NT_STATUS_INVALID_LOCK_RANGE NT_STATUS(0xC0000000 | 0x01a1) /* Win32 Error codes extracted using a loop in smbclient then printing a netmon sniff to a file. */ diff --git a/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c index 7f544b5922..c196433710 100644 --- a/source4/libcli/util/nterr.c +++ b/source4/libcli/util/nterr.c @@ -549,7 +549,7 @@ static const nt_err_code_struct nt_errs[] = { "NT_STATUS_OBJECTID_NOT_FOUND", NT_STATUS_OBJECTID_NOT_FOUND }, { "NT_STATUS_DOWNGRADE_DETECTED", NT_STATUS_DOWNGRADE_DETECTED }, { "NT_STATUS_DS_BUSY", NT_STATUS_DS_BUSY }, - { "XXX_INVALID_RANGE", NT_STATUS_WIN7_INVALID_RANGE }, + { "NT_STATUS_INVALID_LOCK_RANGE", NT_STATUS_INVALID_LOCK_RANGE }, { "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES }, { "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED }, { "STATUS_NOTIFY_CLEANUP", STATUS_NOTIFY_CLEANUP }, diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index 72a03e1623..7e3ac29809 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -364,7 +364,7 @@ static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli) lock[0].count = 2; status = smb_raw_lock(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) - CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE); + CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); else CHECK_STATUS(status, NT_STATUS_OK); lock[0].pid--; @@ -376,7 +376,7 @@ static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli) /* XXX This is very strange - Win7 gives us an invalid range when we * unlock the range even though the range is locked! Win7 bug? */ if (TARGET_IS_WIN7(tctx)) - CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE); + CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); else { CHECK_STATUS(status, NT_STATUS_OK); status = smb_raw_lock(cli->tree, &io); diff --git a/source4/torture/smb2/lock.c b/source4/torture/smb2/lock.c index 5f0293c681..844309efd4 100644 --- a/source4/torture/smb2/lock.c +++ b/source4/torture/smb2/lock.c @@ -101,7 +101,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; status = smb2_lock(tree, &lck); if (TARGET_IS_WIN7(torture)) { - CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE); + CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); } else { CHECK_STATUS(status, NT_STATUS_OK); } @@ -110,7 +110,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree lck.in.reserved = 0x123ab2; status = smb2_lock(tree, &lck); if (TARGET_IS_WIN7(torture)) { - CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE); + CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); } else { CHECK_STATUS(status, NT_STATUS_OK); } @@ -118,7 +118,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree lck.in.reserved = 0x123ab3; status = smb2_lock(tree, &lck); if (TARGET_IS_WIN7(torture)) { - CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE); + CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); } else if (TARGET_IS_WINDOWS(torture)) { CHECK_STATUS(status, NT_STATUS_OK); } else { @@ -129,7 +129,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree lck.in.reserved = 0x123ab4; status = smb2_lock(tree, &lck); if (TARGET_IS_WIN7(torture)) { - CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE); + CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); } else { CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); } @@ -137,7 +137,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree lck.in.reserved = 0x123ab5; status = smb2_lock(tree, &lck); if (TARGET_IS_WIN7(torture)) { - CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE); + CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE); } else if (TARGET_IS_WINDOWS(torture)) { CHECK_STATUS(status, NT_STATUS_OK); } else { -- cgit From 108cf27bb1fe0e602d00a8cc0b54c1d72a1630c8 Mon Sep 17 00:00:00 2001 From: Zack Kirsch Date: Wed, 1 Apr 2009 17:46:40 -0700 Subject: s4 torture: Addition to RAW-BENCH-LOCK to take a configurable number of locks before starting the test This can be useful for benchmarking as well as stress testing. --- source4/torture/raw/lockbench.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/source4/torture/raw/lockbench.c b/source4/torture/raw/lockbench.c index d20175a018..c7f99aeb3c 100644 --- a/source4/torture/raw/lockbench.c +++ b/source4/torture/raw/lockbench.c @@ -317,13 +317,15 @@ bool torture_bench_lock(struct torture_context *torture) { bool ret = true; TALLOC_CTX *mem_ctx = talloc_new(torture); - int i; + int i, j; int timelimit = torture_setting_int(torture, "timelimit", 10); struct timeval tv; struct benchlock_state *state; int total = 0, minops=0; struct smbcli_state *cli; bool progress; + off_t offset; + int initial_locks = torture_setting_int(torture, "initial_locks", 0); progress = torture_setting_bool(torture, "progress", true); @@ -371,6 +373,21 @@ bool torture_bench_lock(struct torture_context *torture) goto failed; } + /* Optionally, lock initial_locks for each proc beforehand. */ + if (i == 0 && initial_locks > 0) { + printf("Initializing %d locks on each proc.\n", + initial_locks); + } + + for (j = 0; j < initial_locks; j++) { + offset = (0xFFFFFED8LLU * (i+2)) + j; + if (!NT_STATUS_IS_OK(smbcli_lock64(state[i].tree, + state[i].fnum, offset, 1, 0, WRITE_LOCK))) { + printf("Failed initializing, lock=%d\n", j); + goto failed; + } + } + state[i].stage = LOCK_INITIAL; lock_send(&state[i]); } @@ -413,6 +430,7 @@ bool torture_bench_lock(struct torture_context *torture) return ret; failed: + smbcli_deltree(state[0].tree, BASEDIR); talloc_free(mem_ctx); return false; } -- cgit From 37aff885a62cdc5c3298e6f44165f9d9a22729c5 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 19 Mar 2009 12:30:26 +0100 Subject: s3-spoolss: implement _spoolss_GetPrinterDriver2 level 101 (Bug #5140). Guenther --- source3/rpc_server/srv_spoolss_nt.c | 243 +++++++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 5 deletions(-) diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 15c137a88c..7bb0571042 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -4889,6 +4889,174 @@ static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx, return WERR_OK; } +/******************************************************************** + ********************************************************************/ + +static WERROR fill_spoolss_DriverFileInfo(TALLOC_CTX *mem_ctx, + struct spoolss_DriverFileInfo *r, + const char *cservername, + const char *file_name, + enum spoolss_DriverFileType file_type, + uint32_t file_version) +{ + r->file_name = talloc_asprintf(mem_ctx, "\\\\%s%s", + cservername, file_name); + W_ERROR_HAVE_NO_MEMORY(r->file_name); + r->file_type = file_type; + r->file_version = file_version; + + return WERR_OK; +} + +/******************************************************************** + ********************************************************************/ + +static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx, + const NT_PRINTER_DRIVER_INFO_LEVEL *driver, + const char *cservername, + struct spoolss_DriverFileInfo **info_p, + uint32_t *count_p) +{ + struct spoolss_DriverFileInfo *info = NULL; + uint32_t count = 0; + WERROR result; + uint32_t i; + + *info_p = NULL; + *count_p = 0; + + if (strlen(driver->info_3->driverpath)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->driverpath, + SPOOLSS_DRIVER_FILE_TYPE_RENDERING, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->info_3->configfile)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->configfile, + SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->info_3->datafile)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->datafile, + SPOOLSS_DRIVER_FILE_TYPE_DATA, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->info_3->helpfile)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->helpfile, + SPOOLSS_DRIVER_FILE_TYPE_HELP, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + for (i=0; driver->info_3->dependentfiles[i][0] != '\0'; i++) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->dependentfiles[i], + SPOOLSS_DRIVER_FILE_TYPE_OTHER, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + *info_p = info; + *count_p = count; + + return WERR_OK; +} + +/******************************************************************** + * fill a spoolss_DriverInfo101 sttruct + ********************************************************************/ + +static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo101 *r, + const NT_PRINTER_DRIVER_INFO_LEVEL *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + WERROR result; + + r->version = driver->info_3->cversion; + + r->driver_name = talloc_strdup(mem_ctx, driver->info_3->name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->info_3->environment); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + result = spoolss_DriverFileInfo_from_driver(mem_ctx, driver, + cservername, + &r->file_info, + &r->file_count); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->monitor_name = talloc_strdup(mem_ctx, driver->info_3->monitorname); + W_ERROR_HAVE_NO_MEMORY(r->monitor_name); + + r->default_datatype = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype); + W_ERROR_HAVE_NO_MEMORY(r->default_datatype); + + r->previous_names = string_array_from_driver_info(mem_ctx, + NULL, + cservername); + r->driver_date = 0; + r->driver_version = 0; + + r->manufacturer_name = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->manufacturer_name); + r->manufacturer_url = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->manufacturer_url); + r->hardware_id = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->hardware_id); + r->provider = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->provider); + + return WERR_OK; +} + /******************************************************************** * construct_printer_driver_info_1 ********************************************************************/ @@ -5077,6 +5245,69 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx, return status; } +/******************************************************************** + * construct_printer_info_101 + * fill a printer_info_101 struct + ********************************************************************/ + +static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo101 *r, + int snum, + const char *servername, + const char *architecture, + uint32_t version) +{ + NT_PRINTER_INFO_LEVEL *printer = NULL; + NT_PRINTER_DRIVER_INFO_LEVEL driver; + WERROR result; + + ZERO_STRUCT(driver); + + result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum)); + + DEBUG(8,("construct_printer_driver_info_101: status: %s\n", + win_errstr(result))); + + if (!W_ERROR_IS_OK(result)) { + return WERR_INVALID_PRINTER_NAME; + } + + result = get_a_printer_driver(&driver, 3, printer->info_2->drivername, + architecture, version); + + DEBUG(8,("construct_printer_driver_info_101: status: %s\n", + win_errstr(result))); + + if (!W_ERROR_IS_OK(result)) { + /* + * Is this a W2k client ? + */ + + if (version < 3) { + free_a_printer(&printer, 2); + return WERR_UNKNOWN_PRINTER_DRIVER; + } + + /* Yes - try again with a WinNT driver. */ + version = 2; + result = get_a_printer_driver(&driver, 3, printer->info_2->drivername, + architecture, version); + DEBUG(8,("construct_printer_driver_info_6: status: %s\n", + win_errstr(result))); + if (!W_ERROR_IS_OK(result)) { + free_a_printer(&printer, 2); + return WERR_UNKNOWN_PRINTER_DRIVER; + } + } + + result = fill_printer_driver_info101(mem_ctx, r, &driver, servername); + + free_a_printer(&printer, 2); + free_a_printer_driver(driver, 3); + + return result; +} + /**************************************************************** _spoolss_GetPrinterDriver2 ****************************************************************/ @@ -5146,13 +5377,15 @@ WERROR _spoolss_GetPrinterDriver2(pipes_struct *p, r->in.architecture, r->in.client_major_version); break; - default: -#if 0 /* JERRY */ case 101: - /* apparently this call is the equivalent of - EnumPrinterDataEx() for the DsDriver key */ + result = construct_printer_driver_info_101(p->mem_ctx, + &r->out.info->info101, + snum, + servername, + r->in.architecture, + r->in.client_major_version); break; -#endif + default: result = WERR_UNKNOWN_LEVEL; break; } -- cgit From 8d98070a9f0a1a17d05e381b8e4c5a8f7a7e8233 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 26 Mar 2009 14:27:45 +0100 Subject: tsocket: split out a smaller tdgram_context abstraction The idea is to have a tdgram and a tstream abstraction which only provide tevent_req based io functions. metze --- lib/tsocket/tsocket.c | 264 +++++++++++++ lib/tsocket/tsocket.h | 43 +++ lib/tsocket/tsocket_bsd.c | 844 +++++++++++++++++++++++++++++++++++++++++ lib/tsocket/tsocket_internal.h | 41 ++ 4 files changed, 1192 insertions(+) diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c index 1a12e691a9..922429a1c1 100644 --- a/lib/tsocket/tsocket.c +++ b/lib/tsocket/tsocket.c @@ -229,3 +229,267 @@ int _tsocket_address_create_socket(const struct tsocket_address *addr, return addr->ops->create_socket(addr, type, mem_ctx, sock, location); } +struct tdgram_context { + const char *location; + const struct tdgram_context_ops *ops; + void *private_data; +}; + +struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx, + const struct tdgram_context_ops *ops, + void *pstate, + size_t psize, + const char *type, + const char *location) +{ + struct tdgram_context *dgram; + void **ppstate = (void **)pstate; + void *state; + + dgram = talloc(mem_ctx, struct tdgram_context); + if (dgram == NULL) { + return NULL; + } + dgram->location = location; + dgram->ops = ops; + + state = talloc_size(dgram, psize); + if (state == NULL) { + talloc_free(dgram); + return NULL; + } + talloc_set_name_const(state, type); + + dgram->private_data = state; + + *ppstate = state; + return dgram; +} + +void *_tdgram_context_data(struct tdgram_context *dgram) +{ + return dgram->private_data; +} + +struct tdgram_recvfrom_state { + const struct tdgram_context_ops *ops; + uint8_t *buf; + size_t len; + struct tsocket_address *src; +}; + +static void tdgram_recvfrom_done(struct tevent_req *subreq); + +struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram) +{ + struct tevent_req *req; + struct tdgram_recvfrom_state *state; + struct tevent_req *subreq; + + req = tevent_req_create(mem_ctx, &state, + struct tdgram_recvfrom_state); + if (req == NULL) { + return NULL; + } + + state->ops = dgram->ops; + + subreq = state->ops->recvfrom_send(state, ev, dgram); + if (tevent_req_nomem(subreq, req)) { + goto post; + } + tevent_req_set_callback(subreq, tdgram_recvfrom_done, req); + + return req; + + post: + tevent_req_post(req, ev); + return req; +} + +static void tdgram_recvfrom_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct tdgram_recvfrom_state *state = tevent_req_data(req, + struct tdgram_recvfrom_state); + ssize_t ret; + int sys_errno; + + ret = state->ops->recvfrom_recv(subreq, &sys_errno, state, + &state->buf, &state->src); + if (ret == -1) { + tevent_req_error(req, sys_errno); + return; + } + + state->len = ret; + + tevent_req_done(req); +} + +ssize_t tdgram_recvfrom_recv(struct tevent_req *req, + int *perrno, + TALLOC_CTX *mem_ctx, + uint8_t **buf, + struct tsocket_address **src) +{ + struct tdgram_recvfrom_state *state = tevent_req_data(req, + struct tdgram_recvfrom_state); + ssize_t ret; + + ret = tsocket_simple_int_recv(req, perrno); + if (ret == 0) { + *buf = talloc_move(mem_ctx, &state->buf); + ret = state->len; + if (src) { + *src = talloc_move(mem_ctx, &state->src); + } + } + + tevent_req_received(req); + return ret; +} + +struct tdgram_sendto_state { + const struct tdgram_context_ops *ops; + ssize_t ret; +}; + +static void tdgram_sendto_done(struct tevent_req *subreq); + +struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram, + const uint8_t *buf, size_t len, + const struct tsocket_address *dst) +{ + struct tevent_req *req; + struct tdgram_sendto_state *state; + struct tevent_req *subreq; + + req = tevent_req_create(mem_ctx, &state, + struct tdgram_sendto_state); + if (req == NULL) { + return NULL; + } + + state->ops = dgram->ops; + state->ret = -1; + + subreq = state->ops->sendto_send(state, ev, dgram, + buf, len, dst); + if (tevent_req_nomem(subreq, req)) { + goto post; + } + tevent_req_set_callback(subreq, tdgram_sendto_done, req); + + return req; + + post: + tevent_req_post(req, ev); + return req; +} + +static void tdgram_sendto_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct tdgram_sendto_state *state = tevent_req_data(req, + struct tdgram_sendto_state); + ssize_t ret; + int sys_errno; + + ret = state->ops->sendto_recv(subreq, &sys_errno); + if (ret == -1) { + tevent_req_error(req, sys_errno); + return; + } + + state->ret = ret; + + tevent_req_done(req); +} + +ssize_t tdgram_sendto_recv(struct tevent_req *req, + int *perrno) +{ + struct tdgram_sendto_state *state = tevent_req_data(req, + struct tdgram_sendto_state); + ssize_t ret; + + ret = tsocket_simple_int_recv(req, perrno); + if (ret == 0) { + ret = state->ret; + } + + tevent_req_received(req); + return ret; +} + +struct tdgram_disconnect_state { + const struct tdgram_context_ops *ops; +}; + +static void tdgram_disconnect_done(struct tevent_req *subreq); + +struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram) +{ + struct tevent_req *req; + struct tdgram_disconnect_state *state; + struct tevent_req *subreq; + + req = tevent_req_create(mem_ctx, &state, + struct tdgram_disconnect_state); + if (req == NULL) { + return NULL; + } + + state->ops = dgram->ops; + + subreq = state->ops->disconnect_send(state, ev, dgram); + if (tevent_req_nomem(subreq, req)) { + goto post; + } + tevent_req_set_callback(subreq, tdgram_disconnect_done, req); + + return req; + + post: + tevent_req_post(req, ev); + return req; +} + +static void tdgram_disconnect_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct tdgram_disconnect_state *state = tevent_req_data(req, + struct tdgram_disconnect_state); + int ret; + int sys_errno; + + ret = state->ops->disconnect_recv(subreq, &sys_errno); + if (ret == -1) { + tevent_req_error(req, sys_errno); + return; + } + + tevent_req_done(req); +} + +int tdgram_disconnect_recv(struct tevent_req *req, + int *perrno) +{ + int ret; + + ret = tsocket_simple_int_recv(req, perrno); + + tevent_req_received(req); + return ret; +} + diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h index 9bcfb5cb7e..077fd1ef35 100644 --- a/lib/tsocket/tsocket.h +++ b/lib/tsocket/tsocket.h @@ -29,6 +29,7 @@ struct tsocket_context; struct tsocket_address; +struct tdgram_context; struct iovec; enum tsocket_type { @@ -120,6 +121,32 @@ int _tsocket_address_create_socket(const struct tsocket_address *addr, _tsocket_address_create_socket(addr, type, mem_ctx, sock,\ __location__) +/* + * tdgram_context related functions + */ +struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram); +ssize_t tdgram_recvfrom_recv(struct tevent_req *req, + int *perrno, + TALLOC_CTX *mem_ctx, + uint8_t **buf, + struct tsocket_address **src); + +struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram, + const uint8_t *buf, size_t len, + const struct tsocket_address *dst); +ssize_t tdgram_sendto_recv(struct tevent_req *req, + int *perrno); + +struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram); +int tdgram_disconnect_recv(struct tevent_req *req, + int *perrno); + /* * BSD sockets: inet, inet6 and unix */ @@ -160,6 +187,22 @@ int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx, _tsocket_context_bsd_wrap_existing(mem_ctx, fd, cod, _sock, \ __location__) +int _tdgram_inet_udp_socket(const struct tsocket_address *local, + const struct tsocket_address *remote, + TALLOC_CTX *mem_ctx, + struct tdgram_context **dgram, + const char *location); +#define tdgram_inet_udp_socket(local, remote, mem_ctx, dgram) \ + _tdgram_inet_udp_socket(local, remote, mem_ctx, dgram, __location__) + +int _tdgram_unix_dgram_socket(const struct tsocket_address *local, + const struct tsocket_address *remote, + TALLOC_CTX *mem_ctx, + struct tdgram_context **dgram, + const char *location); +#define tdgram_unix_dgram_socket(local, remote, mem_ctx, dgram) \ + _tdgram_unix_dgram_socket(local, remote, mem_ctx, dgram, __location__) + /* * Async helpers */ diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c index 8254f5d9d3..6c60ef2ebd 100644 --- a/lib/tsocket/tsocket_bsd.c +++ b/lib/tsocket/tsocket_bsd.c @@ -24,9 +24,168 @@ #include "replace.h" #include "system/filesys.h" #include "system/network.h" +#include "system/filesys.h" #include "tsocket.h" #include "tsocket_internal.h" +static int tsocket_bsd_error_from_errno(int ret, + int sys_errno, + bool *retry) +{ + *retry = false; + + if (ret >= 0) { + return 0; + } + + if (ret != -1) { + return EIO; + } + + if (sys_errno == 0) { + return EIO; + } + + if (sys_errno == EINTR) { + *retry = true; + return sys_errno; + } + + if (sys_errno == EINPROGRESS) { + *retry = true; + return sys_errno; + } + + if (sys_errno == EAGAIN) { + *retry = true; + return sys_errno; + } + +#ifdef EWOULDBLOCK + if (sys_errno == EWOULDBLOCK) { + *retry = true; + return sys_errno; + } +#endif + + return sys_errno; +} + +static int tsocket_bsd_common_prepare_fd(int fd, bool high_fd) +{ + int i; + int sys_errno = 0; + int fds[3]; + int num_fds = 0; + + int result, flags; + + if (fd == -1) { + return -1; + } + + /* first make a fd >= 3 */ + if (high_fd) { + while (fd < 3) { + fds[num_fds++] = fd; + fd = dup(fd); + if (fd == -1) { + sys_errno = errno; + break; + } + } + for (i=0; i= 0) { + flags |= FD_CLOEXEC; + result = fcntl(fd, F_SETFD, flags); + } + if (result < 0) { + goto fail; + } +#endif + return fd; + + fail: + if (fd != -1) { + sys_errno = errno; + close(fd); + errno = sys_errno; + } + return -1; +} + +static ssize_t tsocket_bsd_pending(int fd) +{ + int ret; + int value = 0; + + ret = ioctl(fd, FIONREAD, &value); + if (ret == -1) { + return ret; + } + + if (ret == 0) { + if (value == 0) { + int error=0; + socklen_t len = sizeof(error); + /* + * if no data is available check if the socket + * is in error state. For dgram sockets + * it's the way to return ICMP error messages + * of connected sockets to the caller. + */ + ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, + &error, &len); + if (ret == -1) { + return ret; + } + if (error != 0) { + errno = error; + return -1; + } + } + return value; + } + + /* this should not be reached */ + errno = EIO; + return -1; +} + static const struct tsocket_context_ops tsocket_context_bsd_ops; static const struct tsocket_address_ops tsocket_address_bsd_ops; @@ -1125,3 +1284,688 @@ static const struct tsocket_context_ops tsocket_context_bsd_ops = { .disconnect = tsocket_context_bsd_disconnect }; + +struct tdgram_bsd { + int fd; + + void *event_ptr; + struct tevent_fd *fde; + + void *readable_private; + void (*readable_handler)(void *private_data); + void *writeable_private; + void (*writeable_handler)(void *private_data); + + struct tevent_req *read_req; + struct tevent_req *write_req; +}; + +static void tdgram_bsd_fde_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, + void *private_data) +{ + struct tdgram_bsd *bsds = talloc_get_type_abort(private_data, + struct tdgram_bsd); + + if (flags & TEVENT_FD_WRITE) { + bsds->writeable_handler(bsds->writeable_private); + return; + } + if (flags & TEVENT_FD_READ) { + bsds->readable_handler(bsds->readable_private); + return; + } +} + +static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds, + struct tevent_context *ev, + void (*handler)(void *private_data), + void *private_data) +{ + if (ev == NULL) { + if (handler) { + errno = EINVAL; + return -1; + } + + bsds->readable_handler = NULL; + bsds->readable_private = NULL; + TEVENT_FD_NOT_READABLE(bsds->fde); + + if (bsds->fde && !bsds->writeable_handler) { + /* we don't need the fd event anymore */ + bsds->event_ptr = NULL; + TALLOC_FREE(bsds->fde); + } + return 0; + } + + if (bsds->fde == NULL) { + bsds->fde = tevent_add_fd(ev, bsds, + bsds->fd, TEVENT_FD_READ, + tdgram_bsd_fde_handler, + bsds); + if (!bsds->fde) { + return -1; + } + + /* cache the event context we're running on */ + bsds->event_ptr = ev; + } + + /* read and write must use the same tevent_context */ + if (bsds->event_ptr != ev) { + errno = EINVAL; + return -1; + } + + TEVENT_FD_READABLE(bsds->fde); + bsds->readable_handler = handler; + bsds->readable_private = private_data; + + return 0; +} + +static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds, + struct tevent_context *ev, + void (*handler)(void *private_data), + void *private_data) +{ + if (ev == NULL) { + if (handler) { + errno = EINVAL; + return -1; + } + + bsds->writeable_handler = NULL; + bsds->writeable_private = NULL; + TEVENT_FD_NOT_WRITEABLE(bsds->fde); + + if (bsds->fde && !bsds->readable_handler) { + /* we don't need the fd event anymore */ + bsds->event_ptr = NULL; + TALLOC_FREE(bsds->fde); + } + return 0; + } + + if (bsds->fde == NULL) { + bsds->fde = tevent_add_fd(ev, bsds, + bsds->fd, TEVENT_FD_WRITE, + tdgram_bsd_fde_handler, + bsds); + if (!bsds->fde) { + return -1; + } + + /* cache the event context we're running on */ + bsds->event_ptr = ev; + } + + /* read and write must use the same tevent_context */ + if (bsds->event_ptr != ev) { + errno = EINVAL; + return -1; + } + + TEVENT_FD_WRITEABLE(bsds->fde); + bsds->writeable_handler = handler; + bsds->writeable_private = private_data; + + return 0; +} + +struct tdgram_bsd_recvfrom_state { + struct tdgram_context *dgram; + + uint8_t *buf; + size_t len; + struct tsocket_address *src; +}; + +static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state) +{ + struct tdgram_bsd *bsds = tdgram_context_data(state->dgram, + struct tdgram_bsd); + + bsds->read_req = NULL; + tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL); + + return 0; +} + +static void tdgram_bsd_recvfrom_handler(void *private_data); + +static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram) +{ + struct tevent_req *req; + struct tdgram_bsd_recvfrom_state *state; + struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd); + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct tdgram_bsd_recvfrom_state); + if (!req) { + return NULL; + } + + state->dgram = dgram; + state->buf = NULL; + state->len = 0; + state->src = NULL; + + if (bsds->read_req) { + tevent_req_error(req, EBUSY); + goto post; + } + bsds->read_req = req; + + talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor); + + if (bsds->fd == -1) { + tevent_req_error(req, ENOTCONN); + goto post; + } + + ret = tdgram_bsd_set_readable_handler(bsds, ev, + tdgram_bsd_recvfrom_handler, + req); + if (ret == -1) { + tevent_req_error(req, errno); + goto post; + } + + return req; + + post: + tevent_req_post(req, ev); + return req; +} + +static void tdgram_bsd_recvfrom_handler(void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort(private_data, + struct tevent_req); + struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req, + struct tdgram_bsd_recvfrom_state); + struct tdgram_context *dgram = state->dgram; + struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd); + struct tsocket_address_bsd *bsda; + ssize_t ret; + struct sockaddr *sa = NULL; + socklen_t sa_len = 0; + int err; + bool retry; + + ret = tsocket_bsd_pending(bsds->fd); + if (ret == 0) { + /* retry later */ + return; + } + err = tsocket_bsd_error_from_errno(ret, errno, &retry); + if (retry) { + /* retry later */ + return; + } + if (tevent_req_error(req, err)) { + return; + } + + state->buf = talloc_array(state, uint8_t, ret); + if (tevent_req_nomem(state->buf, req)) { + return; + } + state->len = ret; + + state->src = tsocket_address_create(state, + &tsocket_address_bsd_ops, + &bsda, + struct tsocket_address_bsd, + __location__ "bsd_recvfrom"); + if (tevent_req_nomem(state->src, req)) { + return; + } + + ZERO_STRUCTP(bsda); + + sa = &bsda->u.sa; + sa_len = sizeof(bsda->u.ss); + + ret = recvfrom(bsds->fd, state->buf, state->len, 0, sa, &sa_len); + err = tsocket_error_from_errno(ret, errno, &retry); + if (retry) { + /* retry later */ + return; + } + if (tevent_req_error(req, err)) { + return; + } + + if (ret != state->len) { + tevent_req_error(req, EIO); + return; + } + + tevent_req_done(req); +} + +static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req, + int *perrno, + TALLOC_CTX *mem_ctx, + uint8_t **buf, + struct tsocket_address **src) +{ + struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req, + struct tdgram_bsd_recvfrom_state); + ssize_t ret; + + ret = tsocket_simple_int_recv(req, perrno); + if (ret == 0) { + *buf = talloc_move(mem_ctx, &state->buf); + ret = state->len; + if (src) { + *src = talloc_move(mem_ctx, &state->src); + } + } + + tevent_req_received(req); + return ret; +} + +struct tdgram_bsd_sendto_state { + struct tdgram_context *dgram; + + const uint8_t *buf; + size_t len; + const struct tsocket_address *dst; + + ssize_t ret; +}; + +static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state) +{ + struct tdgram_bsd *bsds = tdgram_context_data(state->dgram, + struct tdgram_bsd); + + bsds->write_req = NULL; + tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL); + return 0; +} + +static void tdgram_bsd_sendto_handler(void *private_data); + +static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram, + const uint8_t *buf, + size_t len, + const struct tsocket_address *dst) +{ + struct tevent_req *req; + struct tdgram_bsd_sendto_state *state; + struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd); + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct tdgram_bsd_sendto_state); + if (!req) { + return NULL; + } + + state->dgram = dgram; + state->buf = buf; + state->len = len; + state->dst = dst; + state->ret = -1; + + if (bsds->write_req) { + tevent_req_error(req, EBUSY); + goto post; + } + bsds->write_req = req; + + talloc_set_destructor(state, tdgram_bsd_sendto_destructor); + + if (bsds->fd == -1) { + tevent_req_error(req, ENOTCONN); + goto post; + } + + ret = tdgram_bsd_set_writeable_handler(bsds, ev, + tdgram_bsd_sendto_handler, + req); + if (ret == -1) { + tevent_req_error(req, errno); + goto post; + } + + return req; + + post: + tevent_req_post(req, ev); + return req; +} + +static void tdgram_bsd_sendto_handler(void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort(private_data, + struct tevent_req); + struct tdgram_bsd_sendto_state *state = tevent_req_data(req, + struct tdgram_bsd_sendto_state); + struct tdgram_context *dgram = state->dgram; + struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd); + struct sockaddr *sa = NULL; + socklen_t sa_len = 0; + ssize_t ret; + int err; + bool retry; + + if (state->dst) { + struct tsocket_address_bsd *bsda = + talloc_get_type(state->dst->private_data, + struct tsocket_address_bsd); + + sa = &bsda->u.sa; + sa_len = sizeof(bsda->u.ss); + } + + ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_len); + err = tsocket_error_from_errno(ret, errno, &retry); + if (retry) { + /* retry later */ + return; + } + if (tevent_req_error(req, err)) { + return; + } + + state->ret = ret; + + tevent_req_done(req); +} + +static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno) +{ + struct tdgram_bsd_sendto_state *state = tevent_req_data(req, + struct tdgram_bsd_sendto_state); + ssize_t ret; + + ret = tsocket_simple_int_recv(req, perrno); + if (ret == 0) { + ret = state->ret; + } + + tevent_req_received(req); + return ret; +} + +struct tdgram_bsd_disconnect_state { + int ret; +}; + +static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram) +{ + struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd); + struct tevent_req *req; + struct tdgram_bsd_disconnect_state *state; + int ret; + int err; + bool dummy; + + req = tevent_req_create(mem_ctx, &state, + struct tdgram_bsd_disconnect_state); + if (req == NULL) { + return NULL; + } + state->ret = -1; + + if (bsds->read_req || bsds->write_req) { + tevent_req_error(req, EBUSY); + goto post; + } + + if (bsds->fd == -1) { + tevent_req_error(req, ENOTCONN); + goto post; + } + + state->ret = close(bsds->fd); + bsds->fd = -1; + err = tsocket_error_from_errno(ret, errno, &dummy); + if (tevent_req_error(req, err)) { + goto post; + } + + tevent_req_done(req); +post: + tevent_req_post(req, ev); + return req; +} + +static int tdgram_bsd_disconnect_recv(struct tevent_req *req, + int *perrno) +{ + struct tdgram_bsd_disconnect_state *state = tevent_req_data(req, + struct tdgram_bsd_disconnect_state); + int ret; + + ret = tsocket_simple_int_recv(req, perrno); + if (ret == 0) { + ret = state->ret; + } + + tevent_req_received(req); + return ret; +} + +static const struct tdgram_context_ops tdgram_bsd_ops = { + .name = "bsd", + + .recvfrom_send = tdgram_bsd_recvfrom_send, + .recvfrom_recv = tdgram_bsd_recvfrom_recv, + + .sendto_send = tdgram_bsd_sendto_send, + .sendto_recv = tdgram_bsd_sendto_recv, + + .disconnect_send = tdgram_bsd_disconnect_send, + .disconnect_recv = tdgram_bsd_disconnect_recv, +}; + +static int tdgram_bsd_destructor(struct tdgram_bsd *bsds) +{ + TALLOC_FREE(bsds->fde); + if (bsds->fd != -1) { + close(bsds->fd); + bsds->fd = -1; + } + return 0; +} + +static int tdgram_bsd_dgram_socket(const struct tsocket_address *local, + const struct tsocket_address *remote, + TALLOC_CTX *mem_ctx, + struct tdgram_context **_dgram, + const char *location) +{ + struct tsocket_address_bsd *lbsda = + talloc_get_type_abort(local->private_data, + struct tsocket_address_bsd); + struct tsocket_address_bsd *rbsda = NULL; + struct tdgram_context *dgram; + struct tdgram_bsd *bsds; + int fd; + int ret; + bool do_bind = false; + bool do_reuseaddr = false; + + if (remote) { + rbsda = talloc_get_type_abort(remote->private_data, + struct tsocket_address_bsd); + } + + switch (lbsda->u.sa.sa_family) { + case AF_UNIX: + if (lbsda->u.un.sun_path[0] != 0) { + do_reuseaddr = true; + do_bind = true; + } + break; + case AF_INET: + if (lbsda->u.in.sin_port != 0) { + do_reuseaddr = true; + do_bind = true; + } + if (lbsda->u.in.sin_addr.s_addr == INADDR_ANY) { + do_bind = true; + } + break; +#ifdef HAVE_IPV6 + case AF_INET6: + if (lbsda->u.in6.sin6_port != 0) { + do_reuseaddr = true; + do_bind = true; + } + if (memcmp(&in6addr_any, + &lbsda->u.in6.sin6_addr, + sizeof(in6addr_any)) != 0) { + do_bind = true; + } + break; +#endif + default: + errno = EINVAL; + return -1; + } + + fd = socket(lbsda->u.sa.sa_family, SOCK_DGRAM, 0); + if (fd < 0) { + return fd; + } + + fd = tsocket_bsd_common_prepare_fd(fd, true); + if (fd < 0) { + return fd; + } + + dgram = tdgram_context_create(mem_ctx, + &tdgram_bsd_ops, + &bsds, + struct tdgram_bsd, + location); + if (!dgram) { + int saved_errno = errno; + close(fd); + errno = saved_errno; + return -1; + } + ZERO_STRUCTP(bsds); + bsds->fd = fd; + talloc_set_destructor(bsds, tdgram_bsd_destructor); + + if (lbsda->broadcast) { + int val = 1; + + ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, + (const void *)&val, sizeof(val)); + if (ret == -1) { + int saved_errno = errno; + talloc_free(dgram); + errno = saved_errno; + return ret; + } + } + + if (do_reuseaddr) { + int val = 1; + + ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (const void *)&val, sizeof(val)); + if (ret == -1) { + int saved_errno = errno; + talloc_free(dgram); + errno = saved_errno; + return ret; + } + } + + if (do_bind) { + ret = bind(fd, &lbsda->u.sa, sizeof(lbsda->u.ss)); + if (ret == -1) { + int saved_errno = errno; + talloc_free(dgram); + errno = saved_errno; + return ret; + } + } + + if (rbsda) { + ret = connect(fd, &rbsda->u.sa, sizeof(rbsda->u.ss)); + if (ret == -1) { + int saved_errno = errno; + talloc_free(dgram); + errno = saved_errno; + return ret; + } + } + + *_dgram = dgram; + return 0; +} + +int _tdgram_inet_udp_socket(const struct tsocket_address *local, + const struct tsocket_address *remote, + TALLOC_CTX *mem_ctx, + struct tdgram_context **dgram, + const char *location) +{ + struct tsocket_address_bsd *lbsda = + talloc_get_type_abort(local->private_data, + struct tsocket_address_bsd); + int ret; + + switch (lbsda->u.sa.sa_family) { + case AF_INET: + break; +#ifdef HAVE_IPV6 + case AF_INET6: + break; +#endif + default: + errno = EINVAL; + return -1; + } + + ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location); + + return ret; +} + +int _tdgram_unix_dgram_socket(const struct tsocket_address *local, + const struct tsocket_address *remote, + TALLOC_CTX *mem_ctx, + struct tdgram_context **dgram, + const char *location) +{ + struct tsocket_address_bsd *lbsda = + talloc_get_type_abort(local->private_data, + struct tsocket_address_bsd); + int ret; + + switch (lbsda->u.sa.sa_family) { + case AF_UNIX: + break; + default: + errno = EINVAL; + return -1; + } + + ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location); + + return ret; +} + diff --git a/lib/tsocket/tsocket_internal.h b/lib/tsocket/tsocket_internal.h index e4a4908f3e..d1f240eba0 100644 --- a/lib/tsocket/tsocket_internal.h +++ b/lib/tsocket/tsocket_internal.h @@ -149,6 +149,47 @@ struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx, _tsocket_address_create(mem_ctx, ops, state, sizeof(type), \ #type, location) +struct tdgram_context_ops { + const char *name; + + struct tevent_req *(*recvfrom_send)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram); + ssize_t (*recvfrom_recv)(struct tevent_req *req, + int *perrno, + TALLOC_CTX *mem_ctx, + uint8_t **buf, + struct tsocket_address **src); + + struct tevent_req *(*sendto_send)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram, + const uint8_t *buf, size_t len, + const struct tsocket_address *dst); + ssize_t (*sendto_recv)(struct tevent_req *req, + int *perrno); + + struct tevent_req *(*disconnect_send)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram); + int (*disconnect_recv)(struct tevent_req *req, + int *perrno); +}; + +struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx, + const struct tdgram_context_ops *ops, + void *pstate, + size_t psize, + const char *type, + const char *location); +#define tdgram_context_create(mem_ctx, ops, state, type, location) \ + _tdgram_context_create(mem_ctx, ops, state, sizeof(type), \ + #type, location) + +void *_tdgram_context_data(struct tdgram_context *dgram); +#define tdgram_context_data(_req, _type) \ + talloc_get_type_abort(_tdgram_context_data(_req), _type) + int tsocket_error_from_errno(int ret, int sys_errno, bool *retry); int tsocket_simple_int_recv(struct tevent_req *req, int *perrno); int tsocket_common_prepare_fd(int fd, bool high_fd); -- cgit From 85742dbc0651a3413e90afa18023cd55ae72e6db Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 28 Mar 2009 23:25:28 +0100 Subject: tsocket: add tdgram_sendto_queue_send/recv() metze --- lib/tsocket/tsocket.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/tsocket/tsocket.h | 13 +++++ 2 files changed, 143 insertions(+) diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c index 922429a1c1..a8f3a3909b 100644 --- a/lib/tsocket/tsocket.c +++ b/lib/tsocket/tsocket.c @@ -493,3 +493,133 @@ int tdgram_disconnect_recv(struct tevent_req *req, return ret; } +struct tdgram_sendto_queue_state { + /* this structs are owned by the caller */ + struct { + struct tevent_context *ev; + struct tdgram_context *dgram; + const uint8_t *buf; + size_t len; + const struct tsocket_address *dst; + } caller; + ssize_t ret; +}; + +static void tdgram_sendto_queue_trigger(struct tevent_req *req, + void *private_data); +static void tdgram_sendto_queue_done(struct tevent_req *subreq); + +/** + * @brief Queue a dgram blob for sending through the socket + * @param[in] mem_ctx The memory context for the result + * @param[in] ev The event context the operation should work on + * @param[in] dgram The tdgram_context to send the message buffer + * @param[in] queue The existing dgram queue + * @param[in] buf The message buffer + * @param[in] len The message length + * @param[in] dst The destination socket address + * @retval The async request handle + * + * This function queues a blob for sending to destination through an existing + * dgram socket. The async callback is triggered when the whole blob is + * delivered to the underlying system socket. + * + * The caller needs to make sure that all non-scalar input parameters hang + * arround for the whole lifetime of the request. + */ +struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram, + struct tevent_queue *queue, + const uint8_t *buf, + size_t len, + struct tsocket_address *dst) +{ + struct tevent_req *req; + struct tdgram_sendto_queue_state *state; + bool ok; + + req = tevent_req_create(mem_ctx, &state, + struct tdgram_sendto_queue_state); + if (!req) { + return NULL; + } + + state->caller.ev = ev; + state->caller.dgram = dgram; + state->caller.buf = buf; + state->caller.len = len; + state->caller.dst = dst; + state->ret = -1; + + ok = tevent_queue_add(queue, + ev, + req, + tdgram_sendto_queue_trigger, + NULL); + if (!ok) { + tevent_req_nomem(NULL, req); + goto post; + } + + return req; + + post: + tevent_req_post(req, ev); + return req; +} + +static void tdgram_sendto_queue_trigger(struct tevent_req *req, + void *private_data) +{ + struct tdgram_sendto_queue_state *state = tevent_req_data(req, + struct tdgram_sendto_queue_state); + struct tevent_req *subreq; + + subreq = tdgram_sendto_send(state, + state->caller.ev, + state->caller.dgram, + state->caller.buf, + state->caller.len, + state->caller.dst); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req); +} + +static void tdgram_sendto_queue_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct tdgram_sendto_queue_state *state = tevent_req_data(req, + struct tdgram_sendto_queue_state); + ssize_t ret; + int sys_errno; + + ret = tdgram_sendto_recv(subreq, &sys_errno); + talloc_free(subreq); + if (ret == -1) { + tevent_req_error(req, sys_errno); + return; + } + state->ret = ret; + + tevent_req_done(req); +} + +ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno) +{ + struct tdgram_sendto_queue_state *state = tevent_req_data(req, + struct tdgram_sendto_queue_state); + ssize_t ret; + + ret = tsocket_simple_int_recv(req, perrno); + if (ret == 0) { + ret = state->ret; + } + + tevent_req_received(req); + return ret; +} + diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h index 077fd1ef35..ec891c34dd 100644 --- a/lib/tsocket/tsocket.h +++ b/lib/tsocket/tsocket.h @@ -259,5 +259,18 @@ struct tevent_req *tsocket_readv_send(struct tsocket_context *sock, void *private_data); int tsocket_readv_recv(struct tevent_req *req, int *perrno); +/* + * Queue helpers + */ + +struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tdgram_context *dgram, + struct tevent_queue *queue, + const uint8_t *buf, + size_t len, + struct tsocket_address *dst); +ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno); + #endif /* _TSOCKET_H */ -- cgit From c59ee5a139421762adb6f3f4bbfc21723c2ce407 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 2 Apr 2009 10:36:03 +0200 Subject: tsocket: optimize tdgram_bsd a lot The desire is to do as less syscalls during the tdgram_sendto_send/recv() and tdgram_recvfrom_send/recv() operations. 1. we first try the sendto()/recvfrom() syscall and only use a fd event if we got EAGAIN. 2. we cache the fd event and only change it's flags if really needed. For the highload case we do almost no epoll_ctl() and epoll_wait()/select() syscalls anymore. This speeds up the LDAP-BENCH-CLDAP test by more than 20%. (With a modified version of this test which let the server skip any ldb calls and just return success I'm getting about 8000 requests per second, while I'm getting just about 6000 requests per second without optimization) metze --- lib/tsocket/tsocket_bsd.c | 81 +++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c index 6c60ef2ebd..db1fd38bdb 100644 --- a/lib/tsocket/tsocket_bsd.c +++ b/lib/tsocket/tsocket_bsd.c @@ -1313,6 +1313,10 @@ static void tdgram_bsd_fde_handler(struct tevent_context *ev, return; } if (flags & TEVENT_FD_READ) { + if (!bsds->readable_handler) { + TEVENT_FD_NOT_READABLE(bsds->fde); + return; + } bsds->readable_handler(bsds->readable_private); return; } @@ -1328,19 +1332,25 @@ static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds, errno = EINVAL; return -1; } - + if (!bsds->readable_handler) { + return 0; + } bsds->readable_handler = NULL; bsds->readable_private = NULL; - TEVENT_FD_NOT_READABLE(bsds->fde); - if (bsds->fde && !bsds->writeable_handler) { - /* we don't need the fd event anymore */ - bsds->event_ptr = NULL; - TALLOC_FREE(bsds->fde); - } return 0; } + /* read and write must use the same tevent_context */ + if (bsds->event_ptr != ev) { + if (bsds->readable_handler || bsds->writeable_handler) { + errno = EINVAL; + return -1; + } + bsds->event_ptr = NULL; + TALLOC_FREE(bsds->fde); + } + if (bsds->fde == NULL) { bsds->fde = tevent_add_fd(ev, bsds, bsds->fd, TEVENT_FD_READ, @@ -1352,15 +1362,10 @@ static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds, /* cache the event context we're running on */ bsds->event_ptr = ev; + } else if (!bsds->readable_handler) { + TEVENT_FD_READABLE(bsds->fde); } - /* read and write must use the same tevent_context */ - if (bsds->event_ptr != ev) { - errno = EINVAL; - return -1; - } - - TEVENT_FD_READABLE(bsds->fde); bsds->readable_handler = handler; bsds->readable_private = private_data; @@ -1377,19 +1382,26 @@ static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds, errno = EINVAL; return -1; } - + if (!bsds->writeable_handler) { + return 0; + } bsds->writeable_handler = NULL; bsds->writeable_private = NULL; TEVENT_FD_NOT_WRITEABLE(bsds->fde); - if (bsds->fde && !bsds->readable_handler) { - /* we don't need the fd event anymore */ - bsds->event_ptr = NULL; - TALLOC_FREE(bsds->fde); - } return 0; } + /* read and write must use the same tevent_context */ + if (bsds->event_ptr != ev) { + if (bsds->readable_handler || bsds->writeable_handler) { + errno = EINVAL; + return -1; + } + bsds->event_ptr = NULL; + TALLOC_FREE(bsds->fde); + } + if (bsds->fde == NULL) { bsds->fde = tevent_add_fd(ev, bsds, bsds->fd, TEVENT_FD_WRITE, @@ -1401,15 +1413,10 @@ static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds, /* cache the event context we're running on */ bsds->event_ptr = ev; + } else if (!bsds->writeable_handler) { + TEVENT_FD_WRITEABLE(bsds->fde); } - /* read and write must use the same tevent_context */ - if (bsds->event_ptr != ev) { - errno = EINVAL; - return -1; - } - - TEVENT_FD_WRITEABLE(bsds->fde); bsds->writeable_handler = handler; bsds->writeable_private = private_data; @@ -1470,6 +1477,16 @@ static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx, goto post; } + /* + * this is a fast path, not waiting for the + * socket to become explicit readable gains + * about 10%-20% performance in benchmark tests. + */ + tdgram_bsd_recvfrom_handler(req); + if (!tevent_req_is_in_progress(req)) { + goto post; + } + ret = tdgram_bsd_set_readable_handler(bsds, ev, tdgram_bsd_recvfrom_handler, req); @@ -1634,6 +1651,16 @@ static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx, goto post; } + /* + * this is a fast path, not waiting for the + * socket to become explicit writeable gains + * about 10%-20% performance in benchmark tests. + */ + tdgram_bsd_sendto_handler(req); + if (!tevent_req_is_in_progress(req)) { + goto post; + } + ret = tdgram_bsd_set_writeable_handler(bsds, ev, tdgram_bsd_sendto_handler, req); -- cgit From 7e1411b5c7afa8b47d76ddb1fb93973201bb08a8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 28 Mar 2009 23:31:01 +0100 Subject: libcli/cldap: convert to tsocket_* function to tdgram_* metze --- libcli/cldap/cldap.c | 83 ++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c index d3fb0bb1e9..8a0c2eec5e 100644 --- a/libcli/cldap/cldap.c +++ b/libcli/cldap/cldap.c @@ -51,7 +51,7 @@ */ struct cldap_socket { /* the low level socket */ - struct tsocket_context *sock; + struct tdgram_context *sock; /* * Are we in connected mode, which means @@ -120,8 +120,6 @@ struct cldap_search_state { static int cldap_socket_destructor(struct cldap_socket *c) { - tsocket_disconnect(c->sock); - while (c->searches.list) { struct cldap_search_state *s = c->searches.list; DLIST_REMOVE(c->searches.list, s); @@ -146,7 +144,7 @@ static bool cldap_recvfrom_setup(struct cldap_socket *c) return true; } - c->recv_subreq = tsocket_recvfrom_send(c->sock, c); + c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock); if (!c->recv_subreq) { return false; } @@ -186,11 +184,11 @@ static void cldap_recvfrom_done(struct tevent_req *subreq) goto nomem; } - ret = tsocket_recvfrom_recv(subreq, - &in->recv_errno, - in, - &in->buf, - &in->src); + ret = tdgram_recvfrom_recv(subreq, + &in->recv_errno, + in, + &in->buf, + &in->src); talloc_free(subreq); subreq = NULL; if (ret >= 0) { @@ -337,23 +335,15 @@ NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx, goto nomem; } - ret = tsocket_address_create_socket(local_addr, - TSOCKET_TYPE_DGRAM, - c, &c->sock); + ret = tdgram_inet_udp_socket(local_addr, remote_addr, + c, &c->sock); if (ret != 0) { status = map_nt_error_from_unix(errno); goto nterror; } talloc_free(any); - tsocket_set_event_context(c->sock, c->event.ctx); - if (remote_addr) { - ret = tsocket_connect(c->sock, remote_addr); - if (ret != 0) { - status = map_nt_error_from_unix(errno); - goto nterror; - } c->connected = true; } @@ -408,7 +398,7 @@ struct cldap_reply_state { DATA_BLOB blob; }; -static void cldap_reply_state_destroy(struct tevent_req *req); +static void cldap_reply_state_destroy(struct tevent_req *subreq); /* queue a cldap reply for send @@ -419,7 +409,7 @@ NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io) struct ldap_message *msg; DATA_BLOB blob1, blob2; NTSTATUS status; - struct tevent_req *req; + struct tevent_req *subreq; if (cldap->connected) { return NT_STATUS_PIPE_CONNECTED; @@ -476,17 +466,18 @@ NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io) data_blob_free(&blob1); data_blob_free(&blob2); - req = tsocket_sendto_queue_send(state, - cldap->sock, - cldap->send_queue, - state->blob.data, - state->blob.length, - state->dest); - if (!req) { + subreq = tdgram_sendto_queue_send(state, + cldap->event.ctx, + cldap->sock, + cldap->send_queue, + state->blob.data, + state->blob.length, + state->dest); + if (!subreq) { goto nomem; } /* the callback will just free the state, as we don't need a result */ - tevent_req_set_callback(req, cldap_reply_state_destroy, state); + tevent_req_set_callback(subreq, cldap_reply_state_destroy, state); return NT_STATUS_OK; @@ -497,13 +488,13 @@ failed: return status; } -static void cldap_reply_state_destroy(struct tevent_req *req) +static void cldap_reply_state_destroy(struct tevent_req *subreq) { - struct cldap_reply_state *state = tevent_req_callback_data(req, + struct cldap_reply_state *state = tevent_req_callback_data(subreq, struct cldap_reply_state); /* we don't want to know the result here, we just free the state */ - talloc_free(req); + talloc_free(subreq); talloc_free(state); } @@ -630,12 +621,13 @@ struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx, goto post; } - subreq = tsocket_sendto_queue_send(state, - state->caller.cldap->sock, - state->caller.cldap->send_queue, - state->request.blob.data, - state->request.blob.length, - state->request.dest); + subreq = tdgram_sendto_queue_send(state, + state->caller.cldap->event.ctx, + state->caller.cldap->sock, + state->caller.cldap->send_queue, + state->request.blob.data, + state->request.blob.length, + state->request.dest); if (tevent_req_nomem(subreq, req)) { goto post; } @@ -659,7 +651,7 @@ static void cldap_search_state_queue_done(struct tevent_req *subreq) int sys_errno = 0; struct timeval next; - ret = tsocket_sendto_queue_recv(subreq, &sys_errno); + ret = tdgram_sendto_queue_recv(subreq, &sys_errno); talloc_free(subreq); if (ret == -1) { NTSTATUS status; @@ -708,12 +700,13 @@ static void cldap_search_state_wakeup_done(struct tevent_req *subreq) return; } - subreq = tsocket_sendto_queue_send(state, - state->caller.cldap->sock, - state->caller.cldap->send_queue, - state->request.blob.data, - state->request.blob.length, - state->request.dest); + subreq = tdgram_sendto_queue_send(state, + state->caller.cldap->event.ctx, + state->caller.cldap->sock, + state->caller.cldap->send_queue, + state->request.blob.data, + state->request.blob.length, + state->request.dest); if (tevent_req_nomem(subreq, req)) { return; } -- cgit From 3bbad34a02350c96cb44d53da510c6273b6910d7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 2 Apr 2009 21:06:27 +0200 Subject: tsocket: remove DGRAM support from tsocket_context metze --- lib/tsocket/config.mk | 2 - lib/tsocket/tsocket.c | 15 --- lib/tsocket/tsocket.h | 32 ----- lib/tsocket/tsocket_bsd.c | 72 ----------- lib/tsocket/tsocket_internal.h | 8 -- lib/tsocket/tsocket_recvfrom.c | 164 ------------------------- lib/tsocket/tsocket_sendto.c | 271 ----------------------------------------- 7 files changed, 564 deletions(-) delete mode 100644 lib/tsocket/tsocket_recvfrom.c delete mode 100644 lib/tsocket/tsocket_sendto.c diff --git a/lib/tsocket/config.mk b/lib/tsocket/config.mk index c35f0afd6f..2e05f544c9 100644 --- a/lib/tsocket/config.mk +++ b/lib/tsocket/config.mk @@ -5,8 +5,6 @@ LIBTSOCKET_OBJ_FILES = $(addprefix ../lib/tsocket/, \ tsocket.o \ tsocket_helpers.o \ tsocket_bsd.o \ - tsocket_recvfrom.o \ - tsocket_sendto.o \ tsocket_connect.o \ tsocket_writev.o \ tsocket_readv.o) diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c index a8f3a3909b..076c6474a0 100644 --- a/lib/tsocket/tsocket.c +++ b/lib/tsocket/tsocket.c @@ -118,21 +118,6 @@ int tsocket_writev(struct tsocket_context *sock, return sock->ops->writev_data(sock, vector, count); } -ssize_t tsocket_recvfrom(struct tsocket_context *sock, - uint8_t *data, size_t len, - TALLOC_CTX *addr_ctx, - struct tsocket_address **src_addr) -{ - return sock->ops->recvfrom_data(sock, data, len, addr_ctx, src_addr); -} - -ssize_t tsocket_sendto(struct tsocket_context *sock, - const uint8_t *data, size_t len, - const struct tsocket_address *dest_addr) -{ - return sock->ops->sendto_data(sock, data, len, dest_addr); -} - int tsocket_get_status(const struct tsocket_context *sock) { return sock->ops->get_status(sock); diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h index ec891c34dd..8f69490012 100644 --- a/lib/tsocket/tsocket.h +++ b/lib/tsocket/tsocket.h @@ -34,7 +34,6 @@ struct iovec; enum tsocket_type { TSOCKET_TYPE_STREAM = 1, - TSOCKET_TYPE_DGRAM, TSOCKET_TYPE_MESSAGE }; @@ -68,14 +67,6 @@ int tsocket_readv(struct tsocket_context *sock, int tsocket_writev(struct tsocket_context *sock, const struct iovec *vector, size_t count); -ssize_t tsocket_recvfrom(struct tsocket_context *sock, - uint8_t *data, size_t len, - TALLOC_CTX *addr_ctx, - struct tsocket_address **src_addr); -ssize_t tsocket_sendto(struct tsocket_context *sock, - const uint8_t *data, size_t len, - const struct tsocket_address *dest_addr); - int tsocket_get_status(const struct tsocket_context *sock); int _tsocket_get_local_address(const struct tsocket_context *sock, @@ -207,29 +198,6 @@ int _tdgram_unix_dgram_socket(const struct tsocket_address *local, * Async helpers */ -struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx); -ssize_t tsocket_recvfrom_recv(struct tevent_req *req, - int *perrno, - TALLOC_CTX *mem_ctx, - uint8_t **buf, - struct tsocket_address **src); - -struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - const uint8_t *buf, - size_t len, - const struct tsocket_address *dst); -ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno); - -struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx, - struct tsocket_context *sock, - struct tevent_queue *queue, - const uint8_t *buf, - size_t len, - struct tsocket_address *dst); -ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno); - struct tevent_req *tsocket_connect_send(struct tsocket_context *sock, TALLOC_CTX *mem_ctx, const struct tsocket_address *dst); diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c index db1fd38bdb..4ccaff46e3 100644 --- a/lib/tsocket/tsocket_bsd.c +++ b/lib/tsocket/tsocket_bsd.c @@ -615,9 +615,6 @@ static int tsocket_address_bsd_create_socket(const struct tsocket_address *addr, } bsd_type = SOCK_STREAM; break; - case TSOCKET_TYPE_DGRAM: - bsd_type = SOCK_DGRAM; - break; default: errno = EPROTONOSUPPORT; return -1; @@ -944,73 +941,6 @@ static int tsocket_context_bsd_writev_data(struct tsocket_context *sock, return ret; } -static ssize_t tsocket_context_bsd_recvfrom_data(struct tsocket_context *sock, - uint8_t *data, size_t len, - TALLOC_CTX *addr_ctx, - struct tsocket_address **remote) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - struct tsocket_address *addr = NULL; - struct tsocket_address_bsd *bsda; - ssize_t ret; - struct sockaddr *sa = NULL; - socklen_t sa_len = 0; - - if (remote) { - addr = tsocket_address_create(addr_ctx, - &tsocket_address_bsd_ops, - &bsda, - struct tsocket_address_bsd, - __location__ "recvfrom"); - if (!addr) { - return -1; - } - - ZERO_STRUCTP(bsda); - - sa = &bsda->u.sa; - sa_len = sizeof(bsda->u.ss); - } - - ret = recvfrom(bsds->fd, data, len, 0, sa, &sa_len); - if (ret < 0) { - int saved_errno = errno; - talloc_free(addr); - errno = saved_errno; - return ret; - } - - if (remote) { - *remote = addr; - } - return ret; -} - -static ssize_t tsocket_context_bsd_sendto_data(struct tsocket_context *sock, - const uint8_t *data, size_t len, - const struct tsocket_address *remote) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - struct sockaddr *sa = NULL; - socklen_t sa_len = 0; - ssize_t ret; - - if (remote) { - struct tsocket_address_bsd *bsda = - talloc_get_type(remote->private_data, - struct tsocket_address_bsd); - - sa = &bsda->u.sa; - sa_len = sizeof(bsda->u.ss); - } - - ret = sendto(bsds->fd, data, len, 0, sa, sa_len); - - return ret; -} - static int tsocket_context_bsd_get_status(const struct tsocket_context *sock) { struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, @@ -1272,8 +1202,6 @@ static const struct tsocket_context_ops tsocket_context_bsd_ops = { .pending_data = tsocket_context_bsd_pending_data, .readv_data = tsocket_context_bsd_readv_data, .writev_data = tsocket_context_bsd_writev_data, - .recvfrom_data = tsocket_context_bsd_recvfrom_data, - .sendto_data = tsocket_context_bsd_sendto_data, .get_status = tsocket_context_bsd_get_status, .get_local_address = tsocket_context_bsd_get_local_address, diff --git a/lib/tsocket/tsocket_internal.h b/lib/tsocket/tsocket_internal.h index d1f240eba0..893394405f 100644 --- a/lib/tsocket/tsocket_internal.h +++ b/lib/tsocket/tsocket_internal.h @@ -57,14 +57,6 @@ struct tsocket_context_ops { int (*writev_data)(struct tsocket_context *sock, const struct iovec *vector, size_t count); - ssize_t (*recvfrom_data)(struct tsocket_context *sock, - uint8_t *data, size_t len, - TALLOC_CTX *addr_ctx, - struct tsocket_address **remote_addr); - ssize_t (*sendto_data)(struct tsocket_context *sock, - const uint8_t *data, size_t len, - const struct tsocket_address *remote_addr); - /* info */ int (*get_status)(const struct tsocket_context *sock); int (*get_local_address)(const struct tsocket_context *sock, diff --git a/lib/tsocket/tsocket_recvfrom.c b/lib/tsocket/tsocket_recvfrom.c deleted file mode 100644 index 467738cfc2..0000000000 --- a/lib/tsocket/tsocket_recvfrom.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Stefan Metzmacher 2009 - - ** NOTE! The following LGPL license applies to the tevent - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library 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 3 of the License, or (at your option) any later version. - - This library 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 library; if not, see . -*/ - -#include "replace.h" -#include "system/network.h" -#include "tsocket.h" -#include "tsocket_internal.h" - -struct tsocket_recvfrom_state { - /* this structs are owned by the caller */ - struct { - struct tsocket_context *sock; - } caller; - - uint8_t *buf; - size_t len; - struct tsocket_address *src; -}; - -static int tsocket_recvfrom_state_destructor(struct tsocket_recvfrom_state *state) -{ - if (state->caller.sock) { - tsocket_set_readable_handler(state->caller.sock, NULL, NULL); - } - ZERO_STRUCT(state->caller); - - return 0; -} - -static void tsocket_recvfrom_handler(struct tsocket_context *sock, - void *private_data); - -struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx) -{ - struct tevent_req *req; - struct tsocket_recvfrom_state *state; - int ret; - int err; - bool dummy; - - req = tevent_req_create(mem_ctx, &state, - struct tsocket_recvfrom_state); - if (!req) { - return NULL; - } - - state->caller.sock = sock; - state->buf = NULL; - state->len = 0; - state->src = NULL; - - talloc_set_destructor(state, tsocket_recvfrom_state_destructor); - - ret = tsocket_set_readable_handler(sock, - tsocket_recvfrom_handler, - req); - err = tsocket_error_from_errno(ret, errno, &dummy); - if (tevent_req_error(req, err)) { - goto post; - } - - return req; - - post: - return tevent_req_post(req, sock->event.ctx); -} - -static void tsocket_recvfrom_handler(struct tsocket_context *sock, - void *private_data) -{ - struct tevent_req *req = talloc_get_type(private_data, - struct tevent_req); - struct tsocket_recvfrom_state *state = tevent_req_data(req, - struct tsocket_recvfrom_state); - ssize_t ret; - int err; - bool retry; - - ret = tsocket_pending(state->caller.sock); - if (ret == 0) { - /* retry later */ - return; - } - err = tsocket_error_from_errno(ret, errno, &retry); - if (retry) { - /* retry later */ - return; - } - if (tevent_req_error(req, err)) { - return; - } - - state->buf = talloc_array(state, uint8_t, ret); - if (tevent_req_nomem(state->buf, req)) { - return; - } - state->len = ret; - - ret = tsocket_recvfrom(state->caller.sock, - state->buf, - state->len, - state, - &state->src); - err = tsocket_error_from_errno(ret, errno, &retry); - if (retry) { - /* retry later */ - return; - } - if (tevent_req_error(req, err)) { - return; - } - - if (ret != state->len) { - tevent_req_error(req, EIO); - return; - } - - tevent_req_done(req); -} - -ssize_t tsocket_recvfrom_recv(struct tevent_req *req, - int *perrno, - TALLOC_CTX *mem_ctx, - uint8_t **buf, - struct tsocket_address **src) -{ - struct tsocket_recvfrom_state *state = tevent_req_data(req, - struct tsocket_recvfrom_state); - ssize_t ret; - - ret = tsocket_simple_int_recv(req, perrno); - if (ret == 0) { - *buf = talloc_move(mem_ctx, &state->buf); - ret = state->len; - if (src) { - *src = talloc_move(mem_ctx, &state->src); - } - } - - tevent_req_received(req); - return ret; -} - diff --git a/lib/tsocket/tsocket_sendto.c b/lib/tsocket/tsocket_sendto.c deleted file mode 100644 index 9c0a76bf16..0000000000 --- a/lib/tsocket/tsocket_sendto.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Stefan Metzmacher 2009 - - ** NOTE! The following LGPL license applies to the tevent - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library 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 3 of the License, or (at your option) any later version. - - This library 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 library; if not, see . -*/ - -#include "replace.h" -#include "system/network.h" -#include "tsocket.h" -#include "tsocket_internal.h" - -struct tsocket_sendto_state { - /* this structs are owned by the caller */ - struct { - struct tsocket_context *sock; - const uint8_t *buf; - size_t len; - const struct tsocket_address *dst; - } caller; - - ssize_t ret; -}; - -static int tsocket_sendto_state_destructor(struct tsocket_sendto_state *state) -{ - if (state->caller.sock) { - tsocket_set_writeable_handler(state->caller.sock, NULL, NULL); - } - ZERO_STRUCT(state->caller); - - return 0; -} - -static void tsocket_sendto_handler(struct tsocket_context *sock, - void *private_data); - -struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - const uint8_t *buf, - size_t len, - const struct tsocket_address *dst) -{ - struct tevent_req *req; - struct tsocket_sendto_state *state; - int ret; - int err; - bool dummy; - - req = tevent_req_create(mem_ctx, &state, - struct tsocket_sendto_state); - if (!req) { - return NULL; - } - - state->caller.sock = sock; - state->caller.buf = buf; - state->caller.len = len; - state->caller.dst = dst; - state->ret = -1; - - /* - * this is a fast path, not waiting for the - * socket to become explicit writeable gains - * about 10%-20% performance in benchmark tests. - */ - tsocket_sendto_handler(sock, req); - if (!tevent_req_is_in_progress(req)) { - goto post; - } - - talloc_set_destructor(state, tsocket_sendto_state_destructor); - - ret = tsocket_set_writeable_handler(sock, - tsocket_sendto_handler, - req); - err = tsocket_error_from_errno(ret, errno, &dummy); - if (tevent_req_error(req, err)) { - goto post; - } - - return req; - - post: - return tevent_req_post(req, sock->event.ctx); -} - -static void tsocket_sendto_handler(struct tsocket_context *sock, - void *private_data) -{ - struct tevent_req *req = talloc_get_type(private_data, - struct tevent_req); - struct tsocket_sendto_state *state = tevent_req_data(req, - struct tsocket_sendto_state); - ssize_t ret; - int err; - bool retry; - - ret = tsocket_sendto(state->caller.sock, - state->caller.buf, - state->caller.len, - state->caller.dst); - err = tsocket_error_from_errno(ret, errno, &retry); - if (retry) { - /* retry later */ - return; - } - if (tevent_req_error(req, err)) { - return; - } - - state->ret = ret; - - tevent_req_done(req); -} - -ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno) -{ - struct tsocket_sendto_state *state = tevent_req_data(req, - struct tsocket_sendto_state); - ssize_t ret; - - ret = tsocket_simple_int_recv(req, perrno); - if (ret == 0) { - ret = state->ret; - } - - tevent_req_received(req); - return ret; -} - -struct tsocket_sendto_queue_state { - /* this structs are owned by the caller */ - struct { - struct tsocket_context *sock; - const uint8_t *buf; - size_t len; - const struct tsocket_address *dst; - } caller; - ssize_t ret; -}; - -static void tsocket_sendto_queue_trigger(struct tevent_req *req, - void *private_data); -static void tsocket_sendto_queue_done(struct tevent_req *subreq); - -/** - * @brief Queue a dgram blob for sending through the socket - * @param[in] mem_ctx The memory context for the result - * @param[in] sock The socket to send the message buffer - * @param[in] queue The existing dgram queue - * @param[in] buf The message buffer - * @param[in] len The message length - * @param[in] dst The destination socket address - * @retval The async request handle - * - * This function queues a blob for sending to destination through an existing - * dgram socket. The async callback is triggered when the whole blob is - * delivered to the underlying system socket. - * - * The caller needs to make sure that all non-scalar input parameters hang - * arround for the whole lifetime of the request. - */ -struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx, - struct tsocket_context *sock, - struct tevent_queue *queue, - const uint8_t *buf, - size_t len, - struct tsocket_address *dst) -{ - struct tevent_req *req; - struct tsocket_sendto_queue_state *state; - bool ok; - - req = tevent_req_create(mem_ctx, &state, - struct tsocket_sendto_queue_state); - if (!req) { - return NULL; - } - - state->caller.sock = sock; - state->caller.buf = buf; - state->caller.len = len; - state->caller.dst = dst; - state->ret = -1; - - ok = tevent_queue_add(queue, - sock->event.ctx, - req, - tsocket_sendto_queue_trigger, - NULL); - if (!ok) { - tevent_req_nomem(NULL, req); - goto post; - } - - return req; - - post: - return tevent_req_post(req, sock->event.ctx); -} - -static void tsocket_sendto_queue_trigger(struct tevent_req *req, - void *private_data) -{ - struct tsocket_sendto_queue_state *state = tevent_req_data(req, - struct tsocket_sendto_queue_state); - struct tevent_req *subreq; - - subreq = tsocket_sendto_send(state->caller.sock, - state, - state->caller.buf, - state->caller.len, - state->caller.dst); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, tsocket_sendto_queue_done ,req); -} - -static void tsocket_sendto_queue_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct tsocket_sendto_queue_state *state = tevent_req_data(req, - struct tsocket_sendto_queue_state); - ssize_t ret; - int sys_errno; - - ret = tsocket_sendto_recv(subreq, &sys_errno); - talloc_free(subreq); - if (ret == -1) { - tevent_req_error(req, sys_errno); - return; - } - state->ret = ret; - - tevent_req_done(req); -} - -ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno) -{ - struct tsocket_sendto_queue_state *state = tevent_req_data(req, - struct tsocket_sendto_queue_state); - ssize_t ret; - - ret = tsocket_simple_int_recv(req, perrno); - if (ret == 0) { - ret = state->ret; - } - - tevent_req_received(req); - return ret; -} - -- cgit From 168eb23252c14234d09f7038b9894edf86e0efe1 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 2 Apr 2009 18:47:51 +0200 Subject: s3-lsa: don't SAFE_FREE talloced structs. Guenther --- source3/rpc_server/srv_lsa_nt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index 5fdcaf2d4a..0eee4a903b 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/rpc_server/srv_lsa_nt.c @@ -1434,14 +1434,14 @@ NTSTATUS _lsa_EnumAccounts(pipes_struct *p, sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr, num_entries - *r->in.resume_handle); if (!sids) { - SAFE_FREE(sid_list); + talloc_free(sid_list); return NT_STATUS_NO_MEMORY; } for (i = *r->in.resume_handle, j = 0; i < num_entries; i++, j++) { sids[j].sid = sid_dup_talloc(p->mem_ctx, &sid_list[i]); if (!sids[j].sid) { - SAFE_FREE(sid_list); + talloc_free(sid_list); return NT_STATUS_NO_MEMORY; } } -- cgit From 31ab1d6a6487fb442ccd5b2cd093b4a2b7b80291 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 2 Apr 2009 18:48:15 +0200 Subject: s3-lsa: use LSA_ROLE definitions in _lsa_QueryInfoPolicy(). Guenther --- source3/rpc_server/srv_lsa_nt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index 0eee4a903b..0ce2b40f65 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/rpc_server/srv_lsa_nt.c @@ -648,14 +648,14 @@ NTSTATUS _lsa_QueryInfoPolicy(pipes_struct *p, * only a BDC is a backup controller * of the domain, it controls. */ - info->role.role = 2; + info->role.role = LSA_ROLE_BACKUP; break; default: /* * any other role is a primary * of the domain, it controls. */ - info->role.role = 3; + info->role.role = LSA_ROLE_PRIMARY; break; } break; -- cgit