예제 #1
0
static void DNSSD_API enum_reply(DNSServiceRef client, const DNSServiceFlags flags, uint32_t ifIndex,
                                 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
{
    DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault);
    int labels = 0, depth = 0, i, initial = 0;
    char text[64];
    const char *label[128];

    (void)client;       // Unused
    (void)ifIndex;      // Unused
    (void)context;      // Unused

    // 1. Print the header
    if (num_printed++ == 0) printf("Timestamp     Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
    printtimestamp();
    if (errorCode)
        printf("Error code %d\n", errorCode);
    else if (!*replyDomain)
        printf("Error: No reply domain\n");
    else
    {
        printf("%-10s", DomainMsg(flags));
        printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
        if (partialflags) printf("Flags: %4X  ", partialflags);
        else printf("             ");

        // 2. Count the labels
        while (*replyDomain)
        {
            label[labels++] = replyDomain;
            replyDomain = GetNextLabel(replyDomain, text);
        }

        // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
        if      (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
        else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
        else initial = 1;
        labels -= initial;

        // 4. Print the initial one-, two- or three-label clump
        for (i=0; i<initial; i++)
        {
            GetNextLabel(label[labels+i], text);
            if (i>0) printf(".");
            printf("%s", text);
        }
        printf("\n");

        // 5. Print the remainder of the hierarchy
        for (depth=0; depth<labels; depth++)
        {
            printf("                                             ");
            for (i=0; i<=depth; i++) printf("- ");
            GetNextLabel(label[labels-1-depth], text);
            printf("> %s\n", text);
        }
    }

    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
예제 #2
0
static void DNSSD_API resolve_reply(DNSServiceRef client, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
                                    const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txtRecord, void *context)
{
    union {
        uint16_t s;
        u_char b[2];
    } port = { opaqueport };
    uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];

    (void)client;       // Unused
    (void)ifIndex;      // Unused
    (void)context;      // Unused

    printtimestamp();
    if (errorCode) printf("Error code %d\n", errorCode);
    else
    {
        printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber);
        if (flags) printf(" Flags: %X", flags);
        // Don't show degenerate TXT records containing nothing but a single empty string
        if (txtLen > 1) {
            printf("\n");
            ShowTXTRecord(txtLen, txtRecord);
        }
        printf("\n");
    }

    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
예제 #3
0
static void myTimerCallBack(void)
    {
    DNSServiceErrorType err = kDNSServiceErr_Unknown;

    switch (operation)
        {
        case 'A':
            {
            switch (addtest)
                {
                case 0: printf("Adding Test HINFO record\n");
                        err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_HINFO, sizeof(myhinfoW), &myhinfoW[0], 0);
                        addtest = 1;
                        break;
                case 1: printf("Updating Test HINFO record\n");
                        err = DNSServiceUpdateRecord(client, record, 0, sizeof(myhinfoX), &myhinfoX[0], 0);
                        addtest = 2;
                        break;
                case 2: printf("Removing Test HINFO record\n");
                        err = DNSServiceRemoveRecord(client, record, 0);
                        addtest = 0;
                        break;
                }
            }
            break;

        case 'U':
            {
            if (updatetest[1] != 'Z') updatetest[1]++;
            else                      updatetest[1] = 'A';
            updatetest[0] = 3 - updatetest[0];
            updatetest[2] = updatetest[1];
            printtimestamp();
            printf("Updating Test TXT record to %c\n", updatetest[1]);
            err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 0);
            }
            break;

        case 'N':
            {
            printf("Adding big NULL record\n");
            err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
            if (err) printf("Failed: %d\n", err); else printf("Succeeded\n");
            timeOut = LONG_TIME;
            }
            break;
        }

    if (err != kDNSServiceErr_NoError)
        {
        fprintf(stderr, "DNSService add/update/remove failed %ld\n", (long int)err);
        stopNow = 1;
        }
    }
예제 #4
0
static void DNSSD_API browse_reply(DNSServiceRef client, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
                                   const char *replyName, const char *replyType, const char *replyDomain, void *context)
{
    char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
    (void)client;       // Unused
    (void)context;      // Unused
    if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-25s %-25s %s\n", "Domain", "Service Type", "Instance Name");
    printtimestamp();
    if (errorCode) printf("Error code %d\n", errorCode);
    else printf("%s%6X%3d %-25s %-25s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName);
    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
예제 #5
0
static void DNSSD_API qr_reply(DNSServiceRef sdRef, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
                               const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
{
    char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
    const unsigned char *rd  = rdata;
    const unsigned char *end = (const unsigned char *) rdata + rdlen;
    char rdb[1000];
    int unknowntype = 0;

    (void)sdRef;    // Unused
    (void)flags;    // Unused
    (void)ifIndex;  // Unused
    (void)ttl;      // Unused
    (void)context;  // Unused

    if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
    printtimestamp();
    if (errorCode)
        printf("Error code %d\n", errorCode);
    else
    {
        switch (rrtype)
        {
        case kDNSServiceType_A:
            sprintf(rdb, "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
            break;
        case kDNSServiceType_AAAA:
            sprintf(rdb, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
                    rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
                    rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
            break;
            break;
        default :
            sprintf(rdb, "%d bytes%s", rdlen, rdlen ? ":" : "");
            unknowntype = 1;
            break;
        }

        printf("%s%6X%3d %-30s%4d%4d %s", op, flags, ifIndex, fullname, rrtype, rrclass, rdb);
        if (unknowntype) while (rd < end) printf(" %02X", *rd++);
        printf("\n");

        if (operation == 'C')
            if (flags & kDNSServiceFlagsAdd)
                DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata);
    }

    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
예제 #6
0
// DNSXEnableProxy Callback from the Daemon
static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
{
    (void) connRef;
    printtimestamp();
    switch (errCode)
    {
        case kDNSX_NoError          :  printf("  SUCCESS   \n");     break;
        case kDNSX_DictError        :  printf(" DICT ERROR \n");     break;
        case kDNSX_DaemonNotRunning :  printf(" NO DAEMON  \n");
                                       DNSXRefDeAlloc(ClientRef);    break;
        case kDNSX_Engaged          :  printf(" ENGAGED    \n");
                                       DNSXRefDeAlloc(ClientRef);    break;
        case kDNSX_UnknownErr       :
        default                     :  printf("UNKNOWN ERR \n");
                                       DNSXRefDeAlloc(ClientRef);    break;
    }

}
예제 #7
0
static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context)
    {
    (void)sdref;       // Unused
    (void)context;     // Unused
    (void)flags;       // Unused
    
    if (num_printed++ == 0) printf("Timestamp     if   %-20s %-15s %-15s %-15s %-6s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
    printtimestamp();
    if (errorCode && errorCode != kDNSServiceErr_DoubleNAT) printf("Error code %d\n", errorCode);
    else
        {
        const unsigned char *digits = (const unsigned char *)&publicAddress;
        char                 addr[256];

        snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
        printf("%-4d %-20s %-15d %-15d %-15d %-6d%s\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl, errorCode == kDNSServiceErr_DoubleNAT ? " Double NAT" : "");
        }
    fflush(stdout);
    }
예제 #8
0
// DNSXEnableProxy Callback from the Daemon
static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
{
    (void) connRef;
    printtimestamp();
    switch (errCode)
    {
        case kDNSX_NoError          :  printf("  SUCCESS   \n");
            break;
        case kDNSX_DaemonNotRunning :  printf(" NO DAEMON  \n");
            DNSXRefDeAlloc(ClientRef);    break;
        case kDNSX_BadParam          :  printf(" BAD PARAMETER \n");
            DNSXRefDeAlloc(ClientRef);    break;
        case kDNSX_UnknownErr       :
        default                     :  printf(" UNKNOWN ERR \n");
            DNSXRefDeAlloc(ClientRef);    break;
    }
    fflush(NULL);
    
}
예제 #9
0
static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context)
    {
    char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
    char addr[256] = "";
    (void) sdref;
    (void) context;
    
    if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-25s %-44s %s\n", "Hostname", "Address", "TTL");
    printtimestamp();

    if (address && address->sa_family == AF_INET)
        {
        const unsigned char *b = (const unsigned char *) &((struct sockaddr_in *)address)->sin_addr;
        snprintf(addr, sizeof(addr), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
        }
    else if (address && address->sa_family == AF_INET6)
        {
        char if_name[IFNAMSIZ];        // Older Linux distributions don't define IF_NAMESIZE
        const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *)address;
        const unsigned char       *b  = (const unsigned char *      )&s6->sin6_addr;
        if (!if_indextoname(s6->sin6_scope_id, if_name))
            snprintf(if_name, sizeof(if_name), "<%d>", s6->sin6_scope_id);
        snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
                b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7],
                b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF], if_name);
        }

    printf("%s%6X%3d %-25s %-44s %d", op, flags, interfaceIndex, hostname, addr, ttl);
    if (errorCode)
        {
        if (errorCode == kDNSServiceErr_NoSuchRecord) printf("   No Such Record");
        else                                          printf("   Error code %d", errorCode);
        }
    printf("\n");

    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
    }
예제 #10
0
int main(int argc, char **argv)
{
    DNSXErrorType err;

    // Default i/p intf is lo0 and o/p intf is primary interface
    IfIndex Ipintfs[MaxInputIf] =  {1, 0, 0, 0, 0};
    IfIndex Opintf = kDNSIfindexAny;

    // Extract program name from argv[0], which by convention contains the path to this executable
    const char *a0 = strrchr(argv[0], kFilePathSep) + 1; 
    if (a0 == (const char *)1)
        a0 = argv[0];

    // Must run as root
    if (0 != geteuid()) 
    {        
        fprintf(stderr, "%s MUST run as root!!\n", a0); 
        exit(-1); 
    }
    if ((sizeof(argv) == 8))
        printf("dnsctl running in 64-bit mode\n");
    else if ((sizeof(argv) == 4))
        printf("dnsctl running in 32-bit mode\n");

    // expects atleast one argument
    if (argc < 2)
        goto Usage;

    if ( !strcmp(argv[1], "-DP") || !strcmp(argv[1], "-dp") )
    {
        if (argc == 2)
        {
            printtimestamp();
            printf("Proceeding to Enable DNSProxy on mDNSResponder with Default Parameters\n");
            dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
            err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
        }            
        else if (argc > 2)
        {
            argc--;
            argv++;
            if (!strcmp(argv[1], "-o"))
            {
                Opintf = if_nametoindex(argv[2]);
                if (!Opintf) 
                    Opintf = atoi(argv[2]);
                if (!Opintf) 
                { 
                    fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]); 
                    Opintf = kDNSIfindexAny;
                }
                argc -= 2;
                argv += 2;
            }
            if (argc > 2 && !strcmp(argv[1], "-i")) 
            {
                int i;
                argc--;
                argv++;
                for (i = 0; i < MaxInputIf && argc > 1; i++)
                {
                    Ipintfs[i] = if_nametoindex(argv[1]);
                    if (!Ipintfs[i])
                        Ipintfs[i] = atoi(argv[1]);  
                    if (!Ipintfs[i])
                    {
                        fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]); 
                        Ipintfs[i] = 1;
                    }
                    argc--;
                    argv++;
                }
            }  
            printtimestamp();
            printf("Proceeding to Enable DNSProxy on mDNSResponder \n");
            dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
            err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);                
        }
    }
    else
    {
        goto Usage;
    }

    dispatch_main(); 

Usage:
    print_usage(a0);
    return 0;
}
예제 #11
0
static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
    const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
    {
    char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
    const unsigned char *rd  = rdata;
    const unsigned char *end = (const unsigned char *) rdata + rdlen;
    char rdb[1000] = "", *p = rdb;
    int unknowntype = 0;

    (void)sdref;    // Unused
    (void)flags;    // Unused
    (void)ifIndex;  // Unused
    (void)ttl;      // Unused
    (void)context;  // Unused

    if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
    printtimestamp();

    if (!errorCode)
        {
        switch (rrtype)
            {
            case kDNSServiceType_A:
                snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
                break;
    
            case kDNSServiceType_NS:
            case kDNSServiceType_CNAME:
            case kDNSServiceType_PTR:
            case kDNSServiceType_DNAME:
                p += snprintd(p, sizeof(rdb), &rd);
                break;
    
            case kDNSServiceType_SOA:
                p += snprintd(p, rdb + sizeof(rdb) - p, &rd);        // mname
                p += snprintf(p, rdb + sizeof(rdb) - p, " ");
                p += snprintd(p, rdb + sizeof(rdb) - p, &rd);        // rname
                p += snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
                    ntohl(((uint32_t*)rd)[0]), ntohl(((uint32_t*)rd)[1]), ntohl(((uint32_t*)rd)[2]), ntohl(((uint32_t*)rd)[3]), ntohl(((uint32_t*)rd)[4]));
                break;
    
            case kDNSServiceType_AAAA:
                snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
                    rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
                    rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
                break;
    
            case kDNSServiceType_SRV:
                p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ",    // priority, weight, port
                    ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
                rd += 6;
                p += snprintd(p, rdb + sizeof(rdb) - p, &rd);            // target host
                break;
    
            default : snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : ""); unknowntype = 1; break;
            }
        }

    printf("%s%6X%3d %-30s%4d%4d %s", op, flags, ifIndex, fullname, rrtype, rrclass, rdb);
    if (unknowntype) while (rd < end) printf(" %02X", *rd++);
    if (errorCode)
        {
        if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record");
        else                                          printf("Error code %d", errorCode);
        }
    printf("\n");

    if (operation == 'C')
        if (flags & kDNSServiceFlagsAdd)
            DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata);

    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
    }
예제 #12
0
int main(int argc, char **argv) {
    uint32_t length;            // length of the BlockHeader message
    BlockHeader *bhmsg = NULL;  // serialized BlockHeader message
    Blob *bmsg = NULL;          // serialized Blob message (size is given in the header)

    FILE * fd;

    char lenbuf[4];
    unsigned char *buf = NULL;

    enum {
        osmheader,
        osmdata
    } state = osmheader;

    if (argc == 2) {
        fd = fopen(argv[1], "r");
	if (fd == NULL) {
            fprintf(stderr, "Can't open %s", argv[1]);
            return -1;
        }
    } else {
        fd = stdin;
    }

    fputs_unlocked("<?xml version='1.0' encoding='UTF-8'?>\n<osm version=\"0.6\" generator=\"" PACKAGE_STRING "\">""\n", stdout);

    do {
    if (!fread(lenbuf, 4, 1, fd)) break;

    length = ntohl(*((uint32_t *) lenbuf));  // convert the buffer to a value

    if (verbose) fprintf(stderr, "Length BlockHeader: %d\n", length);

    if (length == 0 || length > MAX_BLOCK_HEADER_SIZE) {
        if (feof(fd)) {
	  break;
        }

        fprintf(stderr, "Block Header isn't present or exceeds minimum/maximum size\n");
        return 1;
    }

    
    /* Since we know the length of the BlockHeader now, we can allocate it */
    buf = (unsigned char *) malloc(length * sizeof(unsigned char));
    if (buf == NULL) {
        fprintf (stderr, "Error allocating BlockHeader buffer\n");
        return 1;
    }

    /* We are reading the BlockHeader */
    if(! fread(buf, length, 1, fd)) break;

    bhmsg = block_header__unpack (NULL, length, buf);
    free(buf);
    if (bhmsg == NULL) {
        fprintf(stderr, "Error unpacking BlockHeader message\n");
        return 1;
    }

    length = bhmsg->datasize;
    if (verbose) fprintf(stderr, "Type: %s\nLength: %u\n", bhmsg->type, length);
    if (length <= 0 || length > MAX_BLOB_SIZE) {
        fprintf(stderr, "Blob isn't present or exceeds minimum/maximum size\n");
        return 1;
    }

    if (strcmp(bhmsg->type, "OSMHeader") == 0) {
        state = osmheader;
    } else if (strcmp(bhmsg->type, "OSMData") == 0) {
        state = osmdata;
    }

    block_header__free_unpacked (bhmsg, &protobuf_c_system_allocator);

    /* We are now reading the 'Blob' */
    buf = (unsigned char *) malloc(length * sizeof(unsigned char *));
    if(! fread(buf, length, 1, fd)) break;

    bmsg = blob__unpack (NULL, length, buf);
    if (bmsg == NULL) {
        fprintf(stderr, "Error unpacking Blob message\n");
        return 1;
    }
    free(buf);
    
    unsigned char *uncompressed;
    if (bmsg->has_raw) {
        uncompressed = bmsg->raw.data;
	bmsg->raw_size = bmsg->raw.len; // I wonder if we should do this.
    } else {
        uncompressed = handleCompressedBlob(bmsg);
        if (uncompressed == NULL) {
            fprintf(stderr, "Uncompression failed\n");
            return 1;
        }
    }

    if (state == osmheader) {
        HeaderBlock *hmsg = header_block__unpack (NULL, bmsg->raw_size, uncompressed);
        if (hmsg == NULL) {
            fprintf(stderr, "Error unpacking HeaderBlock message\n");
            return 1;
        }

        if (verbose) fprintf(stderr, "%s\n", hmsg->required_features[0]);

        header_block__free_unpacked (hmsg, &protobuf_c_system_allocator);
    } else if (state == osmdata) {
        /*
         * Unpack Block and check if all went well
         */
        PrimitiveBlock *pmsg = primitive_block__unpack (NULL, bmsg->raw_size, uncompressed);
        if (pmsg == NULL) {
            fprintf(stderr, "Error unpacking PrimitiveBlock message\n");
            return 1;
        }

        double lat_offset = NANO_DEGREE * pmsg->lat_offset;
        double lon_offset = NANO_DEGREE * pmsg->lon_offset;
        double granularity = NANO_DEGREE * pmsg->granularity;

        if (verbose) fprintf(stderr, "\t""Granularity: %d""\n", pmsg->granularity);
        if (verbose) fprintf(stderr, "\t""Primitive groups: %li""\n", pmsg->n_primitivegroup);
        for (unsigned int j = 0; j < pmsg->n_primitivegroup; j++) {
            if (verbose) fprintf(stderr,"\t\t""Nodes: %li""\n"\
                   "\t\t""Ways: %li""\n"\
                   "\t\t""Relations: %li""\n",
                   (pmsg->primitivegroup[j]->dense ?
                    pmsg->primitivegroup[j]->dense->n_id :
                           pmsg->primitivegroup[j]->n_nodes),
                   pmsg->primitivegroup[j]->n_ways,
                   pmsg->primitivegroup[j]->n_relations);

            /* TODO: Nodes is *untested* */
            if (pmsg->primitivegroup[j]->n_nodes > 0) {
                for (unsigned k = 0; k < pmsg->primitivegroup[j]->n_nodes; k++) {
                    Node *node = pmsg->primitivegroup[j]->nodes[k];

                    printf("\t""<node id=\"%li\" lat=\"%.07f\" lon=\"%.07f\"",
                        node->id,
                        lat_offset + (node->lat * granularity),
                        lon_offset + (node->lon * granularity));
                    if (node->info) {
                        Info *info = node->info;
                        if (info->has_version) {
                            printnumericattribute("version", info->version);
                        }
                        if (info->has_changeset) {
                            printnumericattribute("changeset", info->changeset);
                        }
                        if (info->has_user_sid) {
                            ProtobufCBinaryData user = pmsg->stringtable->s[info->user_sid];
                            printuser(user);
                        }
                        if (info->has_uid) {
                            printnumericattribute("uid", info->uid);
                        }
                        if (info->has_timestamp) {
                            printtimestamp("timestamp", info->timestamp);
                        }
                    }

                    if (node->n_keys == 0 || node->n_vals == 0) {
                        fputs_unlocked("/>""\n", stdout);
                    } else {
                        fputs_unlocked(">""\n", stdout);

                        for (unsigned l = 0; l < node->n_keys; l++) {
                            ProtobufCBinaryData key = pmsg->stringtable->s[node->keys[l]];
                            ProtobufCBinaryData val = pmsg->stringtable->s[node->vals[l]];

                            printtag(key, val);
                        }

                        fputs_unlocked("\t""</node>""\n", stdout);
                    }
                }
            }
            else
            if (pmsg->primitivegroup[j]->n_ways > 0) {
                for (unsigned k = 0; k < pmsg->primitivegroup[j]->n_ways; k++) {
                    Way *way = pmsg->primitivegroup[j]->ways[k];
                    printsotid("way", way->id);
                    if (way->info) {
                        Info *info = way->info;
                        if (info->has_version) {
                            printnumericattribute("version", info->version);
                        }
                        if (info->has_changeset) {
                            printnumericattribute("changeset", info->changeset);
                        }
                        if (info->has_user_sid) {
                            ProtobufCBinaryData user = pmsg->stringtable->s[info->user_sid];
                            printuser(user);
                        }
                        if (info->has_uid) {
                            printnumericattribute("uid", info->uid);
                        }
                        if (info->has_timestamp) {
                            printtimestamp("timestamp", info->timestamp);
                        }
                    }

                    if ((way->n_keys == 0 || way->n_vals == 0) && way->n_refs == 0) {
                        fputs_unlocked("/>""\n", stdout);
                    } else {
                        long int deltaref = 0;
                        
                        fputs_unlocked(">""\n", stdout);
                        
                        for (unsigned l = 0; l < way->n_refs; l++) {
                            deltaref += way->refs[l];
                            printnd(deltaref);
                        }

                        for (unsigned l = 0; l < way->n_keys; l++) {
                            ProtobufCBinaryData key = pmsg->stringtable->s[way->keys[l]];
                            ProtobufCBinaryData val = pmsg->stringtable->s[way->vals[l]];

                            printtag(key, val);
                        }

                        fputs_unlocked("\t""</way>""\n", stdout);
                    }
                }
            }
            else
            if (pmsg->primitivegroup[j]->n_relations > 0) {
                for (unsigned k = 0; k < pmsg->primitivegroup[j]->n_relations; k++) {
                    Relation *relation = pmsg->primitivegroup[j]->relations[k];
                    printsotid("relation", relation->id);
                    if (relation->info) {
                        Info *info = relation->info;
                        if (info->has_version) {
                            printnumericattribute("version", info->version);
                        }
                        if (info->has_changeset) {
                            printnumericattribute("changeset", info->changeset);
                        }
                        if (info->has_user_sid) {
                            ProtobufCBinaryData user = pmsg->stringtable->s[info->user_sid];
                            printuser(user);
                        }
                        if (info->has_uid) {
                            printnumericattribute("uid", info->uid);
                        }
                        if (info->has_timestamp) {
                            printtimestamp("timestamp", info->timestamp);
                        }
                    }

                    if ((relation->n_keys == 0 || relation->n_vals == 0) && relation->n_memids == 0) {
                        fputs_unlocked("/>""\n", stdout);
                    } else {
                        long int deltamemids = 0;
                        
                        fputs_unlocked(">""\n", stdout);
                        
                        for (unsigned l = 0; l < relation->n_memids; l++) {
                            char *type;
                            ProtobufCBinaryData role =  pmsg->stringtable->s[relation->roles_sid[l]];
                            deltamemids += relation->memids[l];

                            switch (relation->types[l]) {
                                case RELATION__MEMBER_TYPE__NODE:
                                    type = "node";
                                    break;
                                case RELATION__MEMBER_TYPE__WAY:
                                    type = "way";
                                    break;
                                case RELATION__MEMBER_TYPE__RELATION:
                                    type = "relation";
                                    break;
                                default:
                                    fprintf(stderr, "Unsupported type: %u""\n", relation->types[l]);
                                    return 1;
                            }

                            printmember(type, deltamemids, role);
                        }

                        for (unsigned l = 0; l < relation->n_keys; l++) {
                            ProtobufCBinaryData key = pmsg->stringtable->s[relation->keys[l]];
                            ProtobufCBinaryData val = pmsg->stringtable->s[relation->vals[l]];

                            printtag(key, val);
                        }

                        fputs_unlocked("\t""</relation>""\n", stdout);
                    }
                }
            }
            else
            if (pmsg->primitivegroup[j]->n_changesets > 0) {
                for (unsigned k = 0; k < pmsg->primitivegroup[j]->n_changesets; k++) {
                    ChangeSet *changeset = pmsg->primitivegroup[j]->changesets[k];

                    printsotid("changeset", changeset->id);
                    if (changeset->info) {
                        Info *info = changeset->info;
                        /* Not in Changeset                    
                        if (info->has_version) {
                            printnumericattribute("version", info->version);
                        }
                        if (info->has_changeset) {
                            printnumericattribute("changeset", info->changeset);
                        }*/
                        if (info->has_user_sid) {
                            ProtobufCBinaryData user = pmsg->stringtable->s[info->user_sid];
                            printuser(user);
                        }
                        if (info->has_uid) {
                            printnumericattribute("uid", info->uid);
                        }
                        if (info->has_timestamp) {
                            printtimestamp("created_at", info->timestamp);

                            if (changeset->has_closetime_delta) {
                                printtimestamp("closed_at", (info->timestamp + changeset->closetime_delta));
                            }
                        }
                    }

                    printf(" open=\"%s\" min_lon=\"%.07f\" min_lat=\"%.07f\" max_lon=\"%.07f\" max_lat=\"%.07f\"",
                        (changeset->open ? "true" : "false"),
                        lat_offset + (changeset->bbox->left * granularity),
                        lon_offset + (changeset->bbox->bottom * granularity),
                        lat_offset + (changeset->bbox->right * granularity),
                        lon_offset + (changeset->bbox->top * granularity));

                    if (changeset->n_keys == 0 || changeset->n_vals == 0) {
                        fputs_unlocked("/>""\n", stdout);
                    } else {
                        fputs_unlocked(">""\n", stdout);

                        for (unsigned l = 0; l < changeset->n_keys; l++) {
                            ProtobufCBinaryData key = pmsg->stringtable->s[changeset->keys[l]];
                            ProtobufCBinaryData val = pmsg->stringtable->s[changeset->vals[l]];

                            printtag(key, val);
                        }

                        fputs_unlocked("\t""</changeset>""\n", stdout);
                    }
                }
            }
            else
            if (pmsg->primitivegroup[j]->dense) {
                unsigned l = 0;
                unsigned long int deltaid = 0;
                long int deltalat = 0;
                long int deltalon = 0;
                unsigned long int deltatimestamp = 0;
                unsigned long int deltachangeset = 0;
                long int deltauid = 0;
                unsigned long int deltauser_sid = 0;

                DenseNodes *dense = pmsg->primitivegroup[j]->dense;
                

                for (unsigned k = 0; k < dense->n_id; k++) {
                    unsigned char has_tags = 0;
                    deltaid += dense->id[k];
                    deltalat += dense->lat[k];
                    deltalon += dense->lon[k];
                    
                    printf("\t""<node id=\"%li\" lat=\"%.07f\" lon=\"%.07f\"", deltaid,
                            lat_offset + (deltalat * granularity),
                            lon_offset + (deltalon * granularity));

                    if (dense->denseinfo) {
                        DenseInfo *denseinfo = dense->denseinfo;

                        deltatimestamp += denseinfo->timestamp[k];
                        deltachangeset += denseinfo->changeset[k];
                        deltauid += denseinfo->uid[k];
                        deltauser_sid += denseinfo->user_sid[k];

                        printnumericattribute("version", denseinfo->version[k]);
                        printnumericattribute("changeset", deltachangeset);
			if (deltauid != -1) { // osmosis devs failed to read the specs
	                        printuser(pmsg->stringtable->s[deltauser_sid]);
	                        printnumericattribute("uid", deltauid);
			}
                        printtimestamp("timestamp", deltatimestamp);
                    }

                    if (l < dense->n_keys_vals) {
                        while (dense->keys_vals[l] != 0 && l < dense->n_keys_vals) {
                            if (has_tags < 1) {
                                has_tags++;
                                fputs_unlocked(">\n", stdout);
                            }
                            
                            ProtobufCBinaryData key = pmsg->stringtable->s[dense->keys_vals[l]];
                            ProtobufCBinaryData val = pmsg->stringtable->s[dense->keys_vals[l+1]];

                            printtag(key, val);

                            l += 2;
                        }
                        l += 1;
                    }

                    if (has_tags < 1) {
                        fputs_unlocked("/>""\n", stdout);
                    } else {
                        fputs_unlocked("\t""</node>""\n", stdout);
                    } 
                }
            }
        }

        primitive_block__free_unpacked (pmsg, &protobuf_c_system_allocator);
    }
    if (!bmsg->has_raw) free(uncompressed);
    blob__free_unpacked (bmsg, &protobuf_c_system_allocator);

    } while (!feof(fd));

    fputs_unlocked("</osm>""\n", stdout);

    if (!feof(fd)) {
      fprintf(stderr, "Input processing terminated early\n");
      return 1;
    }

    return 0;
}