DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
    (
    DNSServiceRef              *sdRef,
    DNSServiceFlags             flags,
    uint32_t                    interfaceIndex,
    const char                 *name,
    uint16_t                    rrtype,
    uint16_t                    rrclass,
    DNSServiceQueryRecordReply  callBack,
    void                       *context
    )
    {
    char *msg = NULL, *ptr;
    size_t len;
    ipc_msg_hdr *hdr;
    DNSServiceRef sdr;
    DNSServiceErrorType err;

    if (!sdRef) return kDNSServiceErr_BadParam;
    *sdRef = NULL;

    if (!name) name = "\0";

    // calculate total message length
    len = sizeof(flags);
    len += sizeof(uint32_t);  //interfaceIndex
    len += strlen(name) + 1;
    len += 2 * sizeof(uint16_t);  // rrtype, rrclass

    hdr = create_hdr(query_request, &len, &ptr, 1);
    if (!hdr) goto error;
    msg = (void *)hdr;

    put_flags(flags, &ptr);
    put_long(interfaceIndex, &ptr);
    put_string(name, &ptr);
    put_short(rrtype, &ptr);
    put_short(rrclass, &ptr);

    sdr = connect_to_server();
    if (!sdr) goto error;
    err = deliver_request(msg, sdr, 1);
    if (err)
        {
        DNSServiceRefDeallocate(sdr);
        return err;
        }

    sdr->op = query_request;
    sdr->process_reply = handle_query_response;
    sdr->app_callback = callBack;
    sdr->app_context = context;
    *sdRef = sdr;
    return err;

error:
    if (msg) free(msg);
    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
    return kDNSServiceErr_Unknown;
    }
//DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
    (
    DNSServiceRef    sdRef,
    DNSRecordRef     RecordRef,
    DNSServiceFlags  flags,
    uint16_t         rdlen,
    const void      *rdata,
    uint32_t         ttl
    )
    {
    ipc_msg_hdr *hdr;
    size_t len = 0;
    char *ptr;

	if (!sdRef) return kDNSServiceErr_BadReference;

    len += sizeof(uint16_t);
    len += rdlen;
    len += sizeof(uint32_t);
    len += sizeof(DNSServiceFlags);

    hdr = create_hdr(update_record_request, &len, &ptr, 0);
    if (!hdr) return kDNSServiceErr_Unknown;
    hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
    put_flags(flags, &ptr);
    put_short(rdlen, &ptr);
    put_rdata(rdlen, rdata, &ptr);
    put_long(ttl, &ptr);
    return deliver_request((char *)hdr, sdRef, 0);
    }
DNSServiceErrorType DNSSD_API DNSServiceBrowse
	(
	DNSServiceRef         *sdRef,
	DNSServiceFlags        flags,
	uint32_t               interfaceIndex,
	const char            *regtype,
	const char            *domain,
	DNSServiceBrowseReply  callBack,
	void                  *context
	)
    {
    char *msg = NULL, *ptr;
    size_t len;
    ipc_msg_hdr *hdr;
    DNSServiceRef sdr;
    DNSServiceErrorType err;

    if (!sdRef) return kDNSServiceErr_BadParam;
    *sdRef = NULL;

    if (!domain) domain = "";

    len = sizeof(flags);
    len += sizeof(interfaceIndex);
    len += strlen(regtype) + 1;
    len += strlen(domain) + 1;

    hdr = create_hdr(browse_request, &len, &ptr, 1);
    if (!hdr) goto error;
    msg = (char *)hdr;
    put_flags(flags, &ptr);
    put_long(interfaceIndex, &ptr);
    put_string(regtype, &ptr);
    put_string(domain, &ptr);

    sdr = connect_to_server();
    if (!sdr) goto error;
    err = deliver_request(msg, sdr, 1);
    if (err)
        {
        DNSServiceRefDeallocate(sdr);
        return err;
        }
    sdr->op = browse_request;
    sdr->process_reply = handle_browse_response;
    sdr->app_callback = callBack;
    sdr->app_context = context;
    *sdRef = sdr;
    return err;

error:
    if (msg) free(msg);
    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
    return kDNSServiceErr_Unknown;
    }
DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
	(
	DNSServiceRef             *sdRef,
	DNSServiceFlags            flags,
	uint32_t                   interfaceIndex,
	DNSServiceDomainEnumReply  callBack,
	void                      *context
	)
    {
    char *msg = NULL, *ptr;
    size_t len;
    ipc_msg_hdr *hdr;
    DNSServiceRef sdr;
    DNSServiceErrorType err;
    int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
    int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
    if (f1 + f2 != 1) return kDNSServiceErr_BadParam;

    if (!sdRef) return kDNSServiceErr_BadParam;
    *sdRef = NULL;

	len = sizeof(DNSServiceFlags);
    len += sizeof(uint32_t);

    hdr = create_hdr(enumeration_request, &len, &ptr, 1);
    if (!hdr) goto error;
    msg = (void *)hdr;

    put_flags(flags, &ptr);
    put_long(interfaceIndex, &ptr);

    sdr = connect_to_server();
    if (!sdr) goto error;
    err = deliver_request(msg, sdr, 1);
    if (err)
        {
        DNSServiceRefDeallocate(sdr);
        return err;
        }

    sdr->op = enumeration_request;
    sdr->process_reply = handle_enumeration_response;
    sdr->app_callback = callBack;
    sdr->app_context = context;
    *sdRef = sdr;
    return err;

error:
    if (msg) free(msg);
    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
    return kDNSServiceErr_Unknown;
    }
//sdRef returned by DNSServiceRegister()
DNSServiceErrorType DNSSD_API DNSServiceAddRecord
    (
    DNSServiceRef    sdRef,
    DNSRecordRef    *RecordRef,
    DNSServiceFlags  flags,
    uint16_t         rrtype,
    uint16_t         rdlen,
    const void      *rdata,
    uint32_t         ttl
    )
    {
    ipc_msg_hdr *hdr;
    size_t len = 0;
    char *ptr;
    DNSRecordRef rref;

    if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
        return kDNSServiceErr_BadReference;
    *RecordRef = NULL;

    len += 2 * sizeof(uint16_t);  //rrtype, rdlen
    len += rdlen;
    len += sizeof(uint32_t);
    len += sizeof(DNSServiceFlags);

    hdr = create_hdr(add_record_request, &len, &ptr, 0);
    if (!hdr) return kDNSServiceErr_Unknown;
    put_flags(flags, &ptr);
    put_short(rrtype, &ptr);
    put_short(rdlen, &ptr);
    put_rdata(rdlen, rdata, &ptr);
    put_long(ttl, &ptr);

    rref = malloc(sizeof(_DNSRecordRef_t));
    if (!rref) goto error;
    rref->app_context = NULL;
    rref->app_callback = NULL;
    rref->record_index = sdRef->max_index++;
    rref->sdr = sdRef;
    *RecordRef = rref;
    hdr->client_context.context = rref;
    hdr->reg_index = rref->record_index;
    return deliver_request((char *)hdr, sdRef, 0);

error:
    if (hdr) free(hdr);
    if (rref) free(rref);
    if (*RecordRef) *RecordRef = NULL;
    return kDNSServiceErr_Unknown;
}
Beispiel #6
0
void create_pkt(pkt *Pkt, uint8_t flag, uint32_t seq, uint8_t *data, uint32_t data_len)
{
    if (Pkt != NULL && ((data == NULL && data_len == 0)||(data != NULL && data_len > 0)))//MAGICNUM
    {
        Pkt->data_len = data_len;
        Pkt->datagram_len = HDR_LEN + data_len;
        memset(Pkt->datagram, 0,Pkt->datagram_len);
        if (data != NULL)
            s_memcpy(Pkt->data, data, Pkt->data_len);
        create_hdr(Pkt, seq, flag);
        get_hdr(Pkt);
    }
    else
    {
        fprintf(stderr, "creat_pkt invalid arguments\n");
    }
}
DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
	(
	DNSServiceFlags  flags,
	const char      *domain
	)
    {
    DNSServiceRef sdr;
    DNSServiceErrorType err;
    char *ptr = NULL;
    size_t len = sizeof(flags) + strlen(domain) + 1;
    ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);

    if (!hdr) return kDNSServiceErr_Unknown;
    put_flags(flags, &ptr);
    put_string(domain, &ptr);

    sdr = connect_to_server();
    if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
    err = deliver_request((char *)hdr, sdr, 1); // deliver_request frees the message for us
	DNSServiceRefDeallocate(sdr);
	return err;
    }
DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
	(
	DNSServiceFlags  flags,
	uint32_t         interfaceIndex,
	const char      *fullname,
	uint16_t         rrtype,
	uint16_t         rrclass,
	uint16_t         rdlen,
	const void      *rdata
	)
    {
    char *ptr;
    size_t len;
    ipc_msg_hdr *hdr;
    DNSServiceRef tmp;

    len = sizeof(DNSServiceFlags);
    len += sizeof(uint32_t);
    len += strlen(fullname) + 1;
    len += 3 * sizeof(uint16_t);
    len += rdlen;
    tmp = connect_to_server();
    if (!tmp) return(kDNSServiceErr_Unknown);
    hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
    if (!hdr) return(kDNSServiceErr_Unknown);

    put_flags(flags, &ptr);
    put_long(interfaceIndex, &ptr);
    put_string(fullname, &ptr);
    put_short(rrtype, &ptr);
    put_short(rrclass, &ptr);
    put_short(rdlen, &ptr);
    put_rdata(rdlen, rdata, &ptr);
	ConvertHeaderBytes(hdr);
    write_all(tmp->sockfd, (char *)hdr, (int) len);
    free(hdr);
    DNSServiceRefDeallocate(tmp);
    return(kDNSServiceErr_NoError);
    }
DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
	(
	DNSServiceRef    sdRef,
	DNSRecordRef     RecordRef,
	DNSServiceFlags  flags
	)
    {
    ipc_msg_hdr *hdr;
    size_t len = 0;
    char *ptr;
    DNSServiceErrorType err;

    if (!sdRef || !RecordRef || !sdRef->max_index)
        return kDNSServiceErr_BadReference;

    len += sizeof(flags);
    hdr = create_hdr(remove_record_request, &len, &ptr, 0);
    if (!hdr) return kDNSServiceErr_Unknown;
    hdr->reg_index = RecordRef->record_index;
    put_flags(flags, &ptr);
    err = deliver_request((char *)hdr, sdRef, 0);
    if (!err) free(RecordRef);
    return err;
    }
Beispiel #10
0
int
create_volume(struct tcplay_opts *opts)
{
	char *pass, *pass_again;
	char *h_pass = NULL;
	char buf[1024];
	disksz_t blocks, hidden_blocks = 0;
	size_t blksz;
	struct tchdr_enc *ehdr, *hehdr;
	struct tchdr_enc *ehdr_backup, *hehdr_backup;
	uint64_t tmp;
	int error, r, ret;

	pass = h_pass = pass_again = NULL;
	ehdr = hehdr = NULL;
	ehdr_backup = hehdr_backup = NULL;
	ret = -1; /* Default to returning error */

	if (opts->cipher_chain == NULL)
		opts->cipher_chain = tc_cipher_chains[0];
	if (opts->prf_algo == NULL)
		opts->prf_algo = &pbkdf_prf_algos[0];
	if (opts->h_cipher_chain == NULL)
		opts->h_cipher_chain = opts->cipher_chain;
	if (opts->h_prf_algo == NULL)
		opts->h_prf_algo = opts->prf_algo;

	if ((error = get_disk_info(opts->dev, &blocks, &blksz)) != 0) {
		tc_log(1, "could not get disk info\n");
		return -1;
	}

	if ((blocks*blksz) <= MIN_VOL_BYTES) {
		tc_log(1, "Cannot create volumes on devices with less "
		    "than %d bytes\n", MIN_VOL_BYTES);
		return -1;
	}

	if (opts->interactive) {
		if (((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) ||
		   ((pass_again = alloc_safe_mem(PASS_BUFSZ)) == NULL)) {
			tc_log(1, "could not allocate safe passphrase memory\n");
			goto out;
		}

		if ((error = read_passphrase("Passphrase: ", pass, MAX_PASSSZ,
		    PASS_BUFSZ, 0) ||
		    (read_passphrase("Repeat passphrase: ", pass_again,
		    MAX_PASSSZ, PASS_BUFSZ, 0)))) {
			tc_log(1, "could not read passphrase\n");
			goto out;
		}

		if (strcmp(pass, pass_again) != 0) {
			tc_log(1, "Passphrases don't match\n");
			goto out;
		}

		free_safe_mem(pass_again);
		pass_again = NULL;
	} else {
		/* In batch mode, use provided passphrase */
		if ((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) {
			tc_log(1, "could not allocate safe "
			    "passphrase memory");
			goto out;
		}

		if (opts->passphrase != NULL) {
			strncpy(pass, opts->passphrase, MAX_PASSSZ);
			pass[MAX_PASSSZ] = '\0';
		}
	}

	if (opts->nkeyfiles > 0) {
		/* Apply keyfiles to 'pass' */
		if ((error = apply_keyfiles((unsigned char *)pass, PASS_BUFSZ,
		    opts->keyfiles, opts->nkeyfiles))) {
			tc_log(1, "could not apply keyfiles\n");
			goto out;
		}
	}

	if (opts->hidden) {
		if (opts->interactive) {
			if (((h_pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) ||
			   ((pass_again = alloc_safe_mem(PASS_BUFSZ)) == NULL)) {
				tc_log(1, "could not allocate safe "
				    "passphrase memory\n");
				goto out;
			}

			if ((error = read_passphrase("Passphrase for hidden volume: ",
			   h_pass, MAX_PASSSZ, PASS_BUFSZ, 0) ||
			   (read_passphrase("Repeat passphrase: ", pass_again,
			   MAX_PASSSZ, PASS_BUFSZ, 0)))) {
				tc_log(1, "could not read passphrase\n");
				goto out;
			}

			if (strcmp(h_pass, pass_again) != 0) {
				tc_log(1, "Passphrases for hidden volume don't "
				    "match\n");
				goto out;
			}

			free_safe_mem(pass_again);
			pass_again = NULL;
		} else {
			/* In batch mode, use provided passphrase */
			if ((h_pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) {
				tc_log(1, "could not allocate safe "
				    "passphrase memory");
				goto out;
			}

			if (opts->h_passphrase != NULL) {
				strncpy(h_pass, opts->h_passphrase, MAX_PASSSZ);
				h_pass[MAX_PASSSZ] = '\0';
			}
		}

		if (opts->n_hkeyfiles > 0) {
			/* Apply keyfiles to 'h_pass' */
			if ((error = apply_keyfiles((unsigned char *)h_pass,
			    PASS_BUFSZ, opts->h_keyfiles, opts->n_hkeyfiles))) {
				tc_log(1, "could not apply keyfiles\n");
				goto out;
			}
		}

		if (opts->interactive) {
			hidden_blocks = 0;
		} else {
			hidden_blocks = opts->hidden_size_bytes/blksz;
			if (hidden_blocks == 0) {
				tc_log(1, "hidden_blocks to create volume "
				    "cannot be zero!\n");
				goto out;
			}

			if (opts->hidden_size_bytes >=
			    (blocks*blksz) - MIN_VOL_BYTES) {
				tc_log(1, "Hidden volume needs to be "
				    "smaller than the outer volume\n");
				goto out;
			}
		}

		/* This only happens in interactive mode */
		while (hidden_blocks == 0) {
			if ((r = _humanize_number(buf, sizeof(buf),
			    (uint64_t)(blocks * blksz))) < 0) {
				sprintf(buf, "%"DISKSZ_FMT" bytes", (blocks * blksz));
			}

			printf("The total volume size of %s is %s (bytes)\n", opts->dev, buf);
			memset(buf, 0, sizeof(buf));
			printf("Size of hidden volume (e.g. 127M):  ");
			fflush(stdout);

			if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
				tc_log(1, "Could not read from stdin\n");
				goto out;
			}

			/* get rid of trailing newline */
			buf[strlen(buf)-1] = '\0';
			if ((error = _dehumanize_number(buf,
			    &tmp)) != 0) {
				tc_log(1, "Could not interpret input: %s\n", buf);
				continue;
			}

			if (tmp >= (blocks*blksz) - MIN_VOL_BYTES) {
				tc_log(1, "Hidden volume needs to be "
				    "smaller than the outer volume\n");
				hidden_blocks = 0;
				continue;
			}

			hidden_blocks = (size_t)tmp;
			hidden_blocks /= blksz;
		}
	}

	if (opts->interactive) {
		/* Show summary and ask for confirmation */
		printf("Summary of actions:\n");
		if (opts->secure_erase)
			printf(" - Completely erase *EVERYTHING* on %s\n", opts->dev);
		printf(" - Create %svolume on %s\n", opts->hidden?("outer "):"", opts->dev);
		if (opts->hidden) {
			printf(" - Create hidden volume of %"DISKSZ_FMT" bytes at end of "
			    "outer volume\n",
			    hidden_blocks * blksz);
		}

		printf("\n Are you sure you want to proceed? (y/n) ");
		fflush(stdout);
		if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
			tc_log(1, "Could not read from stdin\n");
			goto out;
		}

		if ((buf[0] != 'y') && (buf[0] != 'Y')) {
			tc_log(1, "User cancelled action(s)\n");
			goto out;
		}
	}

	/* erase volume */
	if (opts->secure_erase) {
		tc_log(0, "Securely erasing the volume...\nThis process may take "
		    "some time depending on the size of the volume\n");

		if (opts->state_change_fn)
			opts->state_change_fn(opts->api_ctx, "secure_erase", 1);

		if ((error = secure_erase(opts->dev, blocks * blksz, blksz)) != 0) {
			tc_log(1, "could not securely erase device %s\n", opts->dev);
			goto out;
		}

		if (opts->state_change_fn)
			opts->state_change_fn(opts->api_ctx, "secure_erase", 0);
	}

	tc_log(0, "Creating volume headers...\nDepending on your system, this "
	    "process may take a few minutes as it uses true random data which "
	    "might take a while to refill\n");

	if (opts->weak_keys_and_salt) {
		tc_log(0, "WARNING: Using a weak random generator to get "
		    "entropy for the key material. Odds are this is NOT "
		    "what you want.\n");
	}

	if (opts->state_change_fn)
		opts->state_change_fn(opts->api_ctx, "create_header", 1);

	/* create encrypted headers */
	ehdr = create_hdr((unsigned char *)pass,
	    (opts->nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
	    opts->prf_algo, opts->cipher_chain, blksz, blocks, VOL_RSVD_BYTES_START/blksz,
	    blocks - (MIN_VOL_BYTES/blksz), 0, opts->weak_keys_and_salt, &ehdr_backup);
	if (ehdr == NULL) {
		tc_log(1, "Could not create header\n");
		goto out;
	}

	if (opts->hidden) {
		hehdr = create_hdr((unsigned char *)h_pass,
		    (opts->n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), opts->h_prf_algo,
		    opts->h_cipher_chain,
		    blksz, blocks,
		    blocks - (VOL_RSVD_BYTES_END/blksz) - hidden_blocks,
		    hidden_blocks, 1, opts->weak_keys_and_salt, &hehdr_backup);
		if (hehdr == NULL) {
			tc_log(1, "Could not create hidden volume header\n");
			goto out;
		}
	}

	if (opts->state_change_fn)
		opts->state_change_fn(opts->api_ctx, "create_header", 0);

	tc_log(0, "Writing volume headers to disk...\n");

	if ((error = write_to_disk(opts->dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
		tc_log(1, "Could not write volume header to device\n");
		goto out;
	}

	/* Write backup header; it's offset is relative to the end */
	if ((error = write_to_disk(opts->dev, (blocks*blksz - BACKUP_HDR_OFFSET_END),
	    blksz, ehdr_backup, sizeof(*ehdr_backup))) != 0) {
		tc_log(1, "Could not write backup volume header to device\n");
		goto out;
	}

	if (opts->hidden) {
		if ((error = write_to_disk(opts->dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
		    sizeof(*hehdr))) != 0) {
			tc_log(1, "Could not write hidden volume header to "
			    "device\n");
			goto out;
		}

		/* Write backup hidden header; offset is relative to end */
		if ((error = write_to_disk(opts->dev,
		    (blocks*blksz - BACKUP_HDR_HIDDEN_OFFSET_END), blksz,
		    hehdr_backup, sizeof(*hehdr_backup))) != 0) {
			tc_log(1, "Could not write backup hidden volume "
			    "header to device\n");
			goto out;
		}
	}

	/* Everything went ok */
	tc_log(0, "All done!\n");

	ret = 0;

out:
	if (pass)
		free_safe_mem(pass);
	if (h_pass)
		free_safe_mem(h_pass);
	if (pass_again)
		free_safe_mem(pass_again);
	if (ehdr)
		free_safe_mem(ehdr);
	if (hehdr)
		free_safe_mem(hehdr);
	if (ehdr_backup)
		free_safe_mem(ehdr_backup);
	if (hehdr_backup)
		free_safe_mem(hehdr_backup);

	return ret;
}
DNSServiceErrorType DNSSD_API DNSServiceRegister
    (
    DNSServiceRef                       *sdRef,
    DNSServiceFlags                     flags,
    uint32_t                            interfaceIndex,
    const char                          *name,
    const char                          *regtype,
    const char                          *domain,
    const char                          *host,
    uint16_t                            PortInNetworkByteOrder,
    uint16_t                            txtLen,
    const void                          *txtRecord,
    DNSServiceRegisterReply             callBack,
    void                                *context
    )
    {
    char *msg = NULL, *ptr;
    size_t len;
    ipc_msg_hdr *hdr;
    DNSServiceRef sdr;
    DNSServiceErrorType err;
    union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };

    if (!sdRef) return kDNSServiceErr_BadParam;
    *sdRef = NULL;

    if (!name) name = "";
    if (!regtype) return kDNSServiceErr_BadParam;
    if (!domain) domain = "";
    if (!host) host = "";
    if (!txtRecord) txtRecord = (void*)"";

    // auto-name must also have auto-rename
    if (!name[0]  && (flags & kDNSServiceFlagsNoAutoRename))
        return kDNSServiceErr_BadParam;

    // no callback must have auto-rename
    if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;

    len = sizeof(DNSServiceFlags);
    len += sizeof(uint32_t);  // interfaceIndex
    len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
    len += 2 * sizeof(uint16_t);  // port, txtLen
    len += txtLen;

    hdr = create_hdr(reg_service_request, &len, &ptr, 1);
    if (!hdr) goto error;
    if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
    msg = (char *)hdr;
    put_flags(flags, &ptr);
    put_long(interfaceIndex, &ptr);
    put_string(name, &ptr);
    put_string(regtype, &ptr);
    put_string(domain, &ptr);
    put_string(host, &ptr);
    *ptr++ = port.b[0];
    *ptr++ = port.b[1];
    put_short(txtLen, &ptr);
    put_rdata(txtLen, txtRecord, &ptr);

    sdr = connect_to_server();
    if (!sdr) goto error;
    err = deliver_request(msg, sdr, 1);
    if (err)
        {
        DNSServiceRefDeallocate(sdr);
        return err;
        }

    sdr->op = reg_service_request;
    sdr->process_reply = callBack ? handle_regservice_response : NULL;
    sdr->app_callback = callBack;
    sdr->app_context = context;
    *sdRef = sdr;

    return err;

error:
    if (msg) free(msg);
    if (*sdRef) 	{ free(*sdRef);  *sdRef = NULL; }
    return kDNSServiceErr_Unknown;
    }
DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
    (
    DNSServiceRef                  sdRef,
    DNSRecordRef                  *RecordRef,
    DNSServiceFlags                flags,
    uint32_t                       interfaceIndex,
    const char                    *fullname,
    uint16_t                       rrtype,
    uint16_t                       rrclass,
    uint16_t                       rdlen,
    const void                    *rdata,
    uint32_t                       ttl,
    DNSServiceRegisterRecordReply  callBack,
    void                          *context
    )
    {
    char *msg = NULL, *ptr;
    size_t len;
    ipc_msg_hdr *hdr = NULL;
    DNSServiceRef tmp = NULL;
    DNSRecordRef rref = NULL;
    int f1 = (flags & kDNSServiceFlagsShared) != 0;
    int f2 = (flags & kDNSServiceFlagsUnique) != 0;
    if (f1 + f2 != 1) return kDNSServiceErr_BadParam;

    if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
        return kDNSServiceErr_BadReference;
    *RecordRef = NULL;

	len = sizeof(DNSServiceFlags);
    len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
    len += 3 * sizeof(uint16_t);  // rrtype, rrclass, rdlen
    len += strlen(fullname) + 1;
    len += rdlen;

    hdr = create_hdr(reg_record_request, &len, &ptr, 0);
    if (!hdr) goto error;
    msg = (char *)hdr;
    put_flags(flags, &ptr);
    put_long(interfaceIndex, &ptr);
    put_string(fullname, &ptr);
    put_short(rrtype, &ptr);
    put_short(rrclass, &ptr);
    put_short(rdlen, &ptr);
    put_rdata(rdlen, rdata, &ptr);
    put_long(ttl, &ptr);

    rref = malloc(sizeof(_DNSRecordRef_t));
    if (!rref) goto error;
    rref->app_context = context;
    rref->app_callback = callBack;
    rref->record_index = sdRef->max_index++;
    rref->sdr = sdRef;
    *RecordRef = rref;
    hdr->client_context.context = rref;
    hdr->reg_index = rref->record_index;

    return deliver_request(msg, sdRef, 0);

error:
    if (rref) free(rref);
    if (tmp) free(tmp);
    if (hdr) free(hdr);
    return kDNSServiceErr_Unknown;
    }