C : dereferencing pointer to a struct has wrong values [mqtt-c, pointers] - c

I suspect this is a basic issue, I just have a moment of dumbness.
I'm trying to make very simple mqtt client with MQTT-C library as a part of testing tool of my other solution.When I receive subscribed message I have weired issue : inside mqtt-c library (just before a call to a function pointer which happens to be mine "subsriber callback") everything seems ok, but right after a call to my function, dereferencing a pointer shows struct with completly wrong values inside. If I go one step up in callstack, so back to mqtt, the values inspector gives (set to dereference uint32_t value - precisely pointer's address), again, correct structure.
The structure, pointer to which mqtt passes to callback, is allocated on stack inside function in mqtt library. I don't think that thread could change, which would invalidate stack. I have also included mqtt.h, which means that my function should understand the structure.
I will paste some relevant code snippets, any help will be appreciated, including general advices.
ssize_t __mqtt_recv(struct mqtt_client *client)
{
struct mqtt_response response;
ssize_t mqtt_recv_ret = MQTT_OK;
MQTT_PAL_MUTEX_LOCK(&client->mutex);
/* read until there is nothing left to read, or there was an error */
while(mqtt_recv_ret == MQTT_OK) {
/* read in as many bytes as possible */
ssize_t rv, consumed;
struct mqtt_queued_message *msg = NULL;
rv = mqtt_pal_recvall(client->socketfd, client->recv_buffer.curr, client->recv_buffer.curr_sz, 0);
if (rv < 0) {
/* an error occurred */
client->error = (enum MQTTErrors)rv;
MQTT_PAL_MUTEX_UNLOCK(&client->mutex);
return rv;
} else {
client->recv_buffer.curr += rv;
client->recv_buffer.curr_sz -= (unsigned long)rv;
}
/* attempt to parse */
consumed = mqtt_unpack_response(&response, client->recv_buffer.mem_start, (size_t) (client->recv_buffer.curr - client->recv_buffer.mem_start));
if (consumed < 0) {
client->error = (enum MQTTErrors)consumed;
MQTT_PAL_MUTEX_UNLOCK(&client->mutex);
return consumed;
} else if (consumed == 0) {
/* if curr_sz is 0 then the buffer is too small to ever fit the message */
if (client->recv_buffer.curr_sz == 0) {
printf("receive buff sz is zero??\n");
client->error = MQTT_ERROR_RECV_BUFFER_TOO_SMALL;
MQTT_PAL_MUTEX_UNLOCK(&client->mutex);
return MQTT_ERROR_RECV_BUFFER_TOO_SMALL;
}
/* just need to wait for the rest of the data */
MQTT_PAL_MUTEX_UNLOCK(&client->mutex);
return MQTT_OK;
}
switch (response.fixed_header.control_type) {
//(...)
case MQTT_CONTROL_PUBLISH:
/* stage response, none if qos==0, PUBACK if qos==1, PUBREC if qos==2 */
if (response.decoded.publish.qos_level == 1) {
rv = __mqtt_puback(client, response.decoded.publish.packet_id);
if (rv != MQTT_OK) {
client->error = (enum MQTTErrors)rv;
mqtt_recv_ret = rv;
break;
}
} else if (response.decoded.publish.qos_level == 2) {
/* check if this is a duplicate */
if (mqtt_mq_find(&client->mq, MQTT_CONTROL_PUBREC, &response.decoded.publish.packet_id) != NULL) {
break;
}
rv = __mqtt_pubrec(client, response.decoded.publish.packet_id);
if (rv != MQTT_OK) {
client->error = (enum MQTTErrors)rv;
mqtt_recv_ret = rv;
break;
}
}
/* call publish callback */
printf("address: %d; size: %d\n", (uint32_t) &response.decoded.publish, response.decoded.publish.application_message_size);
//all ok here.
client->publish_response_callback(&client->publish_response_callback_state, &response.decoded.publish);
break;
//(...)
{
/* we've handled the response, now clean the buffer */
void* dest = (unsigned char*)client->recv_buffer.mem_start;
void* src = (unsigned char*)client->recv_buffer.mem_start + consumed;
size_t n = (size_t) (client->recv_buffer.curr - client->recv_buffer.mem_start - consumed);
memmove(dest, src, n);
client->recv_buffer.curr -= consumed;
client->recv_buffer.curr_sz += (unsigned long)consumed;
}
}
/* In case there was some error handling the (well formed) message, we end up here */
MQTT_PAL_MUTEX_UNLOCK(&client->mutex);
return mqtt_recv_ret;
}
struct mqtt_response {
/** #brief The mqtt_fixed_header of the deserialized packet. */
struct mqtt_fixed_header fixed_header;
/**
* #brief A union of the possible responses from the broker.
*
* #note The fixed_header contains the control type. This control type corresponds to the
* member of this union that should be accessed. For example if
* fixed_header#control_type == \c MQTT_CONTROL_PUBLISH then
* decoded#publish should be accessed.
*/
union {
struct mqtt_response_connack connack;
struct mqtt_response_publish publish;
struct mqtt_response_puback puback;
struct mqtt_response_pubrec pubrec;
struct mqtt_response_pubrel pubrel;
struct mqtt_response_pubcomp pubcomp;
struct mqtt_response_suback suback;
struct mqtt_response_unsuback unsuback;
struct mqtt_response_pingresp pingresp;
} decoded;
};
static void netReqHandler(void) {
int sockfd = myOpenSocket(ipaddr, port);//open_nb_socket(ipaddr, port);
mqtt_init(&client, sockfd, sendbuf, buffersizes, receivebuf, buffersizes, publish_callback);
printf("client error is %d\n", (&client)->error);
void publish_callback(void** unused, struct mqtt_response_publish *published) {
printf("app msg size : %d, addr: %d\n", published->application_message_size, (uint32_t) published);
char *nullTerminatedMessage = malloc(published->application_message_size + 1);
strncpy(nullTerminatedMessage, published->application_message, published->application_message_size);
nullTerminatedMessage[published->application_message_size] = '\0';

Related

recv all socket (until the message end symbol), C

I want to write a recvall function for socket in C. I assume, that every message in my protocol ends with \r\n. I wrote something like this below:
int recvall (int socket, char *buffer, int numBytes)
{
int bytesRcvd = 0;
numBytes = numBytes - 1;
while(bytesRcvd < numBytes)
{
int chunk = recv(socket, buffer + bytesRcvd, numBytes - bytesRcvd, 0);
if (chunk == 0 || chunk == -1)
break;
if(strstr(buffer, "\r\n"))
break;
bytesRcvd += (chunk);
}
buffer[bytesRcvd] = '\0';
return bytesRcvd;
}
But it shows me that it returns and reads 0 bytes. On the other hand, when I remove:
if(strstr(buffer, "\r\n"))
break;
it hangs. How to improve it?
One mistake here is that strstr expects a zero-terminated string. A fix:
buffer[chunk] = 0;
if(strstr(buffer, "\r\n"))
break;
However, there may be more data following "\r\n", and that data gets lost here.
A common design pattern for receiving data is:
Have a class that maintains a connection with send/receive buffers.
When it has received data into the receive buffer, it calls a message parsing callback passing buffer and buffer_size.
The message parsing callback consumes all available complete messages in the buffer and returns the number of bytes consumed (as you do).
The message parsing callback calls another callback, passing a complete message to it.
Something like this:
typedef struct
{
int socket;
// Message-parsing callback.
size_t(*on_recv_cb)(void*, void*, size_t);
void* on_recv_cb_data;
unsigned char recv_buffer[256 * 1024];
size_t recv_buffer_size; // Initialized with 0;
} Connection;
void Connection_on_socket_ready_for_read(Connection* self) {
// Assumes a non-blocking socket. Read once to avoid starvation of other sockets.
ssize_t received = read(self->socket, self->recv_buffer + self->recv_buffer_size, sizeof self->recv_buffer - self->recv_buffer_size);
if(received > 0) {
self->recv_buffer_size += received;
size_t consumed = self->on_recv_cb(self->on_recv_cb_data, self->recv_buffer, self->recv_buffer_size);
self->recv_buffer_size -= consumed;
memmove(self->on_recv_cb_data, self->recv_buffer + consumed, self->recv_buffer_size);
}
else if(received < 0) {
if(EAGAIN == errno)
return;
perror("error");
// Handle error.
}
else {
// Handle EOF.
}
}
typedef struct {
// Message callback.
void(*on_message_cb)(void*, char*, size_t);
void* on_message_cb_data;
} MessageParserCrLf;
size_t MessageParserCrLf_on_recv(void* cb_data, void* data, size_t data_size) {
MessageParserCrLf* self = cb_data;
char* message_begin = data;
char* message_end = data;
while(data_size - (message_end - (char*)data) >= 2) {
if(message_end[0] == '\r' && message_end[1] == '\n') {
message_end += 2;
self->on_message_cb(self->on_message_cb_data, message_begin, message_end - message_begin);
message_begin = message_end;
}
else {
++message_end;
}
}
return message_begin - (char*)data;
}
void on_message(void* cb_data, char* message, size_t message_size) {
(void)cb_data; // Unused here.
printf("on_message: %.*s\n", (int)message_size, message);
}
int main() {
MessageParserCrLf message_parser = {on_message, NULL};
Connection connection = {0, MessageParserCrLf_on_recv, &message_parser, {}, 0};
Connection_on_socket_ready_for_read(&connection);
}
Outputs:
[~/src/test]$ cat lines.txt
abc
def
end
[~/src/test]$ ./test < lines.txt
on_message: abc
on_message: def
on_message: end
If there is "\r\n" in the received buffer, the following line will break and end the while loop,
if(strstr(buffer, "\r\n")) break;
but bytesRcvd hasn't increased, so the function will return with bytesRcvd=0.
Try to put bytesRcvd increase before judging like this,
bytesRcvd += (chunk);
if(strstr(buffer, "\r\n"))
break;

How to make a FIFO buffer with can_frame structure inside?

In the moment I am working on a project on which a few processors are communication between then using can bus. The main controler (beagle bone) controls the other device using a can bus. Using a socket can linux framework I wrote a proccess that reads the can messages send from the other devices, and now I want to put the messages I get into a FIFO bufer, and then to obrabotam the messages.
So I need to write the FIFO buffer with can_frame structure inside.
For example:
struct can_buffer {
struct can_frame *frames;
int head;
int tail;
int size;
};
can_buffer new_can_buffer (size_t capacity)
{
can_buffer rb = malloc(sizeof(struct can_buffer));
if (rb) {
/* One byte is used for detecting the full condition. */
rb->size = capacity + 1;
rb->frames = malloc(rb->size * sizeof(struct can_frame));
if (rb->frames)
can_buffer_reset(rb);
else {
free(rb);
return 0;
}
}
return rb;
}
size_t can_buffer_size(const struct can_buffer *rb)
{
return rb->size;
}
size_t can_buffer_capacity(const struct can_buffer *rb)
{
return can_buffer_buffer_size(rb) - 1;
}
size_t can_buffer_free(const struct can_buffer *rb)
{
if (rb->head >= rb->tail)
return can_buffer_capacity(rb) - (rb->head - rb->tail);
else
return rb->tail - rb->head - 1;
}
int can_buffer_is_full(const struct can_buffer *rb)
{
return can_buffer_free(rb) == 0;
}
int can_buffer_is_empty(const struct can_buffer *rb)
{
return can_buffer_free(rb) ==can_buffer_capacity(rb);
}
void can_buffer_reset(can_buffer rb)
{
rb->head = rb->tail = 0;
}
.........
........
/* Add message to the end of the queue. */
void can_buffer_push(struct can_buffer *cb, struct can_frame *frame)
{
memcpy(&cb->frames[cb->tail], frame, sizeof(struct can_frame));
cb->tail = (cb->tail + 1) % cb->size;
}
/* Retrieve message from the start of the queue. */
can_frame *can_buffer_pop(struct can_buffer *cb)
{
struct can_frame *frame;
memcpy(frame, &cb->frames[cb->head], sizeof(struct can_frame));
cb->head = (cb->head + 1) % cb->size;
return frame;
}
But I canoot do it successfully. I think the problem is that every can_frame structure inside is a structure again,that is the problem (for example int, char etc), but I do not know how to solve this issue.
How can I make a FIFO buffer that can store the can_frame structure inside?
I need to write this in C lagnuage
in main i call
can_buffer can_buff;
can_buff = new_can_buffer(100);
can_buffer_push(can_buff,frame);
frame = can_frame i received
can_buff = fifo buffer
Well, you have incompletely modified the ringbuf routines. Specifically, you don't allocate enough space for the structures here:
if (rb) {
/* One byte is used for detecting the full condition. */
rb->size = capacity + 1;
rb->frames = malloc(rb->size);
if (rb->frames)
ringbuf_reset(rb);
else {
free(rb);
return 0;
}
}
The malloc needs to be
rb->frames = malloc(rb->size * sizeof(struct can_frame));
And the you should update the ringbuf_reset() call on the next line to your renamed can_buffer_reset()
Addendum:
I just noticed that you also need to update your ringbuf_reset() function to rb->head = rb->tail = 0
Addendum 2:
Referencing the newly added code, can_buffer_pop() will not work correctly as it doesn't check for the message existing and it doesn't allocate memory for the popped message.
There is also a typo in can_buffer_capacity().
Editorial:
I would strongly suggest writing a simple test program that executes these functions. It's frustrating but will catch a number of these small gotchas.

WinDivert issue - redirecting DNS back to self on windows

I was looking at basil00's torwall, and for fun was trying to pare it down to just intercept DNS. (provide an answer back to myself of 127.0.0.1 for webfiltering purposes, learning project)
however, at this point, I have it hijacking the dns packet, but it does not return a correct address. for every "blocked" domain, it's different.
for example, I put cbc.ca in my hosts.deny file (blacklist), and it returns an address of 0.4.114.2
then blacklisting slashdot, it will return 0.4.0.1
this has been quite confusing and frustrating, and after three days of research, I am out of ideas.
Here is the code to the redirect portion of my program, which seems to be where things go awry.
(note some of the comments will be goofy as I was hacking down a program for a different purpose and haven't cleaned it up yet)
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "windivert.h"
#include "domain.h"
#include "main.h"
#include "redirect.h"
#define MAX_PACKET 4096
#define NUM_WORKERS 4
// DNS headers
#define DNS_MAX_NAME 254
struct dnshdr
{
uint16_t id;
uint16_t options;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} __attribute__((__packed__));
struct dnsq
{
uint16_t type;
uint16_t class;
} __attribute__((__packed__));
struct dnsa
{
uint16_t name;
uint16_t type;
uint16_t class;
uint32_t ttl;
uint16_t length;
uint32_t addr;
} __attribute__((__packed__));
static DWORD redirect_worker(LPVOID arg);
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len);
// State:
static bool redirect_on = false;
static HANDLE handle = INVALID_HANDLE_VALUE;
static HANDLE workers[NUM_WORKERS] = {NULL}; // Worker threads
// Send a packet asynchronously:
static void send_packet(HANDLE handle, void *packet, size_t packet_len,
PWINDIVERT_ADDRESS addr)
{
addr->Direction = WINDIVERT_DIRECTION_INBOUND;
WinDivertHelperCalcChecksums(packet, packet_len, 0);
if (!WinDivertSend(handle, packet, packet_len, addr, NULL))
debug("Send packet failed (err=%d)\n", (int)GetLastError());
}
// Start traffic redirect through Tor:
extern void redirect_start(void)
{
debug("DNS divert START\n");
if (handle != INVALID_HANDLE_VALUE)
return;
handle = WinDivertOpen(
"outbound and udp.DstPort == 53 or inbound and udp.DstPort = 53", 0, 0, 0);
// Launch threads:
redirect_on = true;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
workers[i] = CreateThread(NULL, MAX_PACKET*3,
(LPTHREAD_START_ROUTINE)redirect_worker, (LPVOID)handle, 0, NULL);
if (workers[i] == NULL)
{
exit(EXIT_FAILURE);
}
}
}
// Stop traffic redirect through Tor:
extern void redirect_stop(void)
{
debug("DNS divert STOP\n");
if (handle == INVALID_HANDLE_VALUE)
return;
// Close the WinDivert handle; will cause the workers to exit.
redirect_on = false;
if (!WinDivertClose(handle))
{
exit(EXIT_FAILURE);
}
handle = INVALID_HANDLE_VALUE;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
WaitForSingleObject(workers[i], INFINITE);
workers[i] = NULL;
}
}
// Redirect worker thread:
static DWORD redirect_worker(LPVOID arg)
{
HANDLE handle = (HANDLE)arg;
// Packet processing loop:
char packet[MAX_PACKET];
UINT packet_len;
WINDIVERT_ADDRESS addr;
while (redirect_on)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
// Silently ignore any error.
continue;
}
PWINDIVERT_IPHDR iphdr = NULL;
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
PVOID data = NULL;
UINT data_len;
WinDivertHelperParsePacket(packet, packet_len, &iphdr, NULL, NULL,
NULL, &tcphdr, &udphdr, &data, &data_len);
int dnshandle = 0;
if (udphdr != NULL && ntohs(udphdr->DstPort) == 53)
dnshandle = handle_dns(handle, &addr, iphdr, udphdr, data, data_len);
if(dnshandle != 1)
{
if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
{
}
}
}
return 0;
}
// Handle DNS requests.
// NOTES:
// - If anything goes wrong, we simply drop the packet without error.
// - An alternative approach would be to let Tor resolve the address, however,
// this would be slow.
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len)
{
struct dnshdr *dnshdr = (struct dnshdr *)data;
data += sizeof(struct dnshdr);
data_len -= sizeof(struct dnshdr);
char name[DNS_MAX_NAME + 8]; // 8 bytes extra.
size_t i = 0;
while (i < data_len && data[i] != 0)
{
size_t len = data[i];
if (i + len >= DNS_MAX_NAME)
return -1;
name[i++] = '.';
for (size_t j = 0; j < len; j++, i++)
name[i] = data[i];
}
name[i++] = '\0';
// Generate a fake IP address and associate it with this domain name:
uint32_t fake_addr = domain_lookup_addr(name);
if (fake_addr == 0)
{
// This domain is blocked; so ignore the request.
// Construct a query response:
size_t len = sizeof(struct dnshdr) + data_len + sizeof(struct dnsa);
if (len > 512) // Max DNS packet size.
return -1;
len += sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_UDPHDR) + len;
char buf[len + 8]; // 8 bytes extra.
PWINDIVERT_IPHDR riphdr = (PWINDIVERT_IPHDR)buf;
PWINDIVERT_UDPHDR rudphdr = (PWINDIVERT_UDPHDR)(riphdr + 1);
struct dnshdr *rdnshdr = (struct dnshdr *)(rudphdr + 1);
char *rdata = (char *)(rdnshdr + 1);
UINT local_ip;
DivertHelperParseIPv4Address("127.0.0.1",&local_ip);
memset(riphdr, 0, sizeof(WINDIVERT_IPHDR));
riphdr->Version = 4;
riphdr->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(uint32_t);
riphdr->Length = htons(len);
riphdr->Id = htons(0xF00D);
WINDIVERT_IPHDR_SET_DF(riphdr, 1);
riphdr->TTL = 64;
riphdr->Protocol = IPPROTO_UDP;
riphdr->SrcAddr = iphdr->DstAddr;
riphdr->DstAddr = iphdr->SrcAddr;
memset(rudphdr, 0, sizeof(WINDIVERT_UDPHDR));
rudphdr->SrcPort = htons(53); // DNS
rudphdr->DstPort = udphdr->SrcPort;
rudphdr->Length = htons(len - sizeof(WINDIVERT_IPHDR));
rdnshdr->id = dnshdr->id;
rdnshdr->options = htons(0x8180); // Standard DNS response.
rdnshdr->qdcount = htons(0x0001);
rdnshdr->ancount = htons(0x0001);
rdnshdr->nscount = 0;
rdnshdr->arcount = 0;
memcpy(rdata, data, data_len);
struct dnsa *rdnsa = (struct dnsa *)(rdata + data_len);
rdnsa->name = htons(0xC00C);
rdnsa->type = htons(0x0001); // (A)
rdnsa->class = htons(0x0001); // (IN)
rdnsa->ttl = htonl(0x00000258) ; // 1 second
rdnsa->length = htons(0x0004);
rdnsa->addr = htonl(local_ip); // Fake address
send_packet(handle, &buf, len, addr);
debug("address: %u\n",addr->Direction);
debug("Intercept DNS %s\n", (name[0] == '.'? name+1: name));
return 1;
}
// Re-inject the matching packet.
/*
/
*/
return 0;
}
Here's the domain lookup side of it (mostly just hacked down to try to get the results I want:
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "domain.h"
#include "main.h"
#define RATE_LIMIT 8000
#define rand16() \
(rand() & 0xFF) | ((rand() & 0xFF) << 8)
// Domain blacklist:
struct blacklist
{
size_t size;
size_t len;
char **names;
};
static struct blacklist *blacklist = NULL;
// State:
static struct name *names[UINT16_MAX] = {NULL};
static HANDLE names_lock = NULL;
// Prototypes:
static struct blacklist *domain_blacklist_read(const char *filename);
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name);
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y);
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1);
// Initialize this module:
extern void domain_init(void)
{
// Load the domain blacklist.
blacklist = domain_blacklist_read("hosts.deny");
}
// Lookup an address given a domain name. If the name does not exist then
// create one.
extern uint32_t domain_lookup_addr(const char *name0)
{
if (name0[0] == '.')
name0++;
if (domain_blacklist_lookup(blacklist, name0))
{
debug("Block %s\n", name0);
return 0; // Blocked!
}
return;
}
// Read the blacklist file:
static struct blacklist *domain_blacklist_read(const char *filename)
{
struct blacklist *blacklist =
(struct blacklist *)malloc(sizeof(struct blacklist));
if (blacklist == NULL)
{
exit(EXIT_FAILURE);
}
blacklist->size = 0;
blacklist->len = 0;
blacklist->names = NULL;
FILE *stream = fopen(filename, "r");
if (stream == NULL)
{
return blacklist;
}
// Read blocked domains:
int c;
char buf[256];
while (true)
{
while (isspace(c = getc(stream)))
;
if (c == EOF)
break;
if (c == '#')
{
while ((c = getc(stream)) != '\n' && c != EOF)
;
continue;
}
size_t i = 0;
while (i < sizeof(buf)-1 && (c == '-' || c == '.' || isalnum(c)))
{
buf[i++] = c;
c = getc(stream);
}
if (i >= sizeof(buf)-1 || !isspace(c))
{
exit(EXIT_FAILURE);
}
buf[i] = '\0';
if (blacklist->len >= blacklist->size)
{
blacklist->size = (blacklist->size == 0? 32: 2 * blacklist->size);
blacklist->names = (char **)realloc(blacklist->names,
blacklist->size * sizeof(char *));
if (blacklist->names == NULL)
{
exit(EXIT_FAILURE);
}
}
size_t size = (i+1) * sizeof(char);
char *name = (char *)malloc(size);
if (name == NULL)
{
exit(EXIT_FAILURE);
}
for (size_t j = 0; j < i; j++)
name[j] = buf[i - 1 - j];
name[i] = '\0';
blacklist->names[blacklist->len++] = name;
}
fclose(stream);
qsort(blacklist->names, blacklist->len, sizeof(char *),
domain_blacklist_compare_0);
return blacklist;
}
// Check if a domain matches the blacklist or not:
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name)
{
if (blacklist->len == 0)
return false;
size_t len = strlen(name);
ssize_t lo = 0, hi = blacklist->len-1;
while (lo <= hi)
{
ssize_t mid = (lo + hi) / 2;
int cmp = domain_blacklist_compare(name, len, blacklist->names[mid]);
if (cmp > 0)
hi = mid-1;
else if (cmp < 0)
lo = mid+1;
else
return true;
}
return false;
}
// Domain compare function(s):
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y)
{
const char *name0 = *(const char **)x;
const char *name1 = *(const char **)y;
return strcmp(name0, name1);
}
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1)
{
size_t i = 0;
ssize_t j = (ssize_t)len - 1;
for (; j >= 0 && name1[i] != '\0'; i++, j--)
{
int cmp = (int)name1[i] - (int)name0[j];
if (cmp != 0)
return cmp;
}
if (j < 0 && name1[i] != '\0')
return 1;
return 0;
}
any assistance is appreciated.
Also, I have uploaded the code to: Github
Thank you.
There's one of two things going on here. You're reading and writing DNS packets incorrectly, and or you're failing to convert the addresses to or from host to network order before working with them.
I'm going to bet on you reading and writing DNS packets incorrectly. I've implemented my own filtering systems using WinDivert where I was hijacking and passing all DNS traffic through my own local DNS server and I've seen these fudged addresses come out exactly as the results you're getting when I was parsing and writing DNS packets incorrectly.
The bad news is, I can't point you to a full DNS library in C/C++ as I know of none that actually make the job easier (maybe, see edits). I personally had my diversion code written in C++ with WinDivert and then use Arsoft.Tools.Net C# DNS library for actually running a local DNS server and manipulating DNS responses.
There is one project in C++ that calls itself boost::net::dns because I think the writer was hoping it would be part of boost, which it isn't and probably won't be. Avoid this library as the internal mechanism for parsing and storing multiple A Records is bugged out and broken and you'll get the same wacky results you're getting here. I tried to work with him to get it fixed but, he was only interested in blaming my code.
I'll have a gander again and update my answer if I can find a decent lib for working with DNS packets in C++. Don't try to do it yourself, we're talking about entire protocols with entire books of RFC's to do this properly yourself.
Update
As promised, here are some results from my search:
Mozilla Necko (Formerly Netlib)
http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/
C-Ares:
https://github.com/bagder/c-ares
A list of alternative libraries C-Ares compiled:
http://c-ares.haxx.se/otherlibs.html
Also, it is linux specific but pretty clean code. You might be able to pilfer through libcrafter's DNS classes and move them to your own project.
https://github.com/pellegre/libcrafter/blob/master/libcrafter/crafter/Protocols/DNS.h
Again, unless your "learning project" is understanding and recreating one of the foundational pillars of the internet, don't implement this yourself. Try and use one of the previously listed libraries to handle your DNS packets.

How to account for a circular buffer size of 1 when using pthreads / cond_signal / cond_wait?

I'm trying to implement a program that uses a thread to read data from a file and write to a buffer of an arbitrary size, while two other threads read info from this buffer. Everything works fine, except for when I specify a buffer size of 1. When I do that, everything locks up. I'm more or less adapting the classic "consumer/producer" example from here Here's my code:
Struct I'm using:
struct prodcons {
char** buffer; pthread_mutex_t lock;
pthread_cond_t notempty; pthread_cond_t notfull;
int readpos, writepos, finished;
};
My "add to buffer" thread
static void buf_add(struct prodcons *b, char* data) {
/* Add the data after locking the buffer */
pthread_mutex_lock(&b-> lock);
printf("Reader adding %s\n", data);
int err;
/*Wait until buffer is not full*/
while ((b->writepos + 1) % numlines == b->readpos) {
err = pthread_cond_wait(&b->notfull, &b->lock);
if (err != 0) { fprintf(stderr, "cond wait");}
}
/* Needed to stop writes */
if (data != NULL) {
b->buffer[b->writepos] = strdup(data);
} else {
//fprintf(stderr, "End of file reached, adding NULL\n");
b->buffer[b->writepos] = NULL;
}
/* Increments the writing position */
(*b).writepos++;
if ((*b).writepos >= numlines) {
printf("Resetting write position\n");
(*b).writepos = 0;
}
/* Unlock */
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}
Here's what output looks like:
Reader adding 64.233.173.85
And then it just hangs. It's clear that it's never getting beyond that first while loop. It works with any other size, but not with 1. what would be the best way of implement a fix for this? If this helps, here is my "get from buffer" method.
static void *read_from_buffer(struct prodcons *b) {
pthread_mutex_lock(&b -> lock);
/* We have to wait for the buffer to have something in it */
while ((*b).writepos == (*b).readpos) {
pthread_cond_wait(&b->notempty, &b->lock);
}
/* Set the thread delay */
thread_delay.tv_sec = threaddelay / 100000;
thread_delay.tv_nsec = 1000*threaddelay%100000;
char *t = NULL;
/* Read the data and advance the reader pointer */
if ((*b).buffer[(*b).readpos] != NULL) {
t = (char*)malloc(strlen ((*b).buffer[(*b).readpos] ) + 1);
strcpy(t, (*b).buffer[(*b).readpos]);
printf("Consumer %u reading from buffer: got %s\n", (unsigned int)pthread_self(), t);
/*At this point, we should probably check is FQDN*/
if (strcmp(t, "-1") == 0) {
(*b).finished = 1;
} else {
nanosleep(&thread_delay, &thread_delay_rem);
check_cache(t, &cache);
}
}
/* We have to adjust the reading position */
(*b).readpos++;
if ( (*b).readpos >= numlines) {
(*b).readpos = 0;
}
/*Need to signal and unlock */
pthread_cond_signal (&b->notfull);
pthread_mutex_unlock(&b->lock);
return t;
}
I'm sure there is a fairly simple fix to handle this edge case, but I can't seem to figure it out. Any suggestions would be much appreciated!
EDIT: I also initialize my buffer like so:
static void init(struct prodcons *temp) {
(*temp).buffer = (char**)malloc(numlines * sizeof(char*));
Not having stepped through your code, but you're writing a terminating NUL '\0' byte, and that would take up an entire 1-byte buffer. The writer waits forever for space in the buffer.
while ((b->writepos + 1) % numlines == b->readpos) { /* always satisfied */

Disassemble HTTP Response (C)

In continuation of this question I ask the following question.
I've managed to read and understand what D.Shawley has recommended and I already finished a lot of work. But a problem occured to me again. I've managed to get the Content-Length of the page out of the HTTP response, but now I'm experiencing some problems with getting the length of the HTTP response header. As I understand from the RFC 2616 document, a response header can be preceded with several CRLFs and must be followed by one or more CRLFs. Now I'm heaving trouble with determining the end of the response header.
I've came up with the following files:
IEFDowner.h
/*
* IEFDowner.h
* Downer
*
* Created by ief2 on 2/08/10.
* Copyright 2010 ief2. All rights reserved.
*
* http://developerief2.site11.com
*
*/
#include <stdio.h> /* snprintf() */
#include <sys/socket.h> /* SOCKET */
#include <netdb.h> /* struct addrinfo */
#include <stdlib.h> /* exit() */
#include <string.h> /* memset(), strlen(), strcpy(), strstr() */
#include <errno.h> /* errno */
#include <unistd.h> /* close() */
enum _IEFDownerErrorType {
IEFNoError,
IEFGAIError, /* Use gai_strerror() to get the error message */
IEFConnectError, /* Failed to connect with the socket */
IEFSendError, /* Use strerror() to get the error message */
IEFReceiveError /* Error with recv() */
};
typedef enum _IEFDownerErrorType IEFDownerErrorType;
/*
Requests the data from the host at the given path thru the given protocol.
PAREMTERS
- host
The host to connect to.
- filepath
The path to the file which to download from the host.
- buffer
A buffer to fill with the received data
- maxSize
The maximum size of the buffer
- receivedBytes
The amount of received bytes
- errorType
The type of error received. See the header file for more info (enum _IEFDownerErrorType)
RETURN VALUE
The function returns 0 if it succeeded or another code if it failed.
*/
int
IEFDownerHTTPDownload(const char *host,
const char *filepath,
void *buffer,
unsigned long maxSize,
long *receivedBytes,
IEFDownerErrorType *errorType);
/*
Returns a pointer to a structure containing the IP4 or IP6 addresss.
PARAMETERS
- sa
A pointer to a structure of sockaddr.
RETURN VALUE
Returns a pointer to a structure of the type sockaddr_in or the type sockaddr_in6.
*/
void *
IEFDownerGetInAddr(struct sockaddr *sa);
/*
Gets the content-length information out of an HTTP response header.
PARAMETERS
- httpHeader
The null terminated response.
- contentLength
Upon return it contains the content length.
RETURN VALUE
The function returns 0 if it succeeded or -1 if it did not.
*/
int
IEFDownerGetContentLengthOfPage(const char *httpHeader,
int *contentLength);
/*
Gets the string lenth of the header information
PARAMETERS
- received
The received header
- headerSize
Upon return contains the header length
RETURN VALUE
The function returns 0 if it succeeded. If there was no header information found, it returns -1.
DISCUSSION
The header size includes the trailing CRLF's behind the header data.
All empty CRLF's are included until a non-empty line is met.
If there're zero empty lines after the first non empty line, the header information was not found.
*/
int
IEFDownerGetSizeOfHeader(const char *received,
int *headerSize);
IEFDowner.c
/*
* IEFDowner.c
* Downer
*
* Created by ief2 on 2/08/10.
* Copyright 2010 ief2. All rights reserved.
*
* http://developerief2.site11.com
*
*/
#include "IEFDowner.h"
int
IEFDownerHTTPDownload(const char *host, const char *filepath, void *buffer, unsigned long maxSize, long *rB, IEFDownerErrorType *errorType) {
int status; // contains returned statuses
int sockfd; // the socket file descriptor
struct addrinfo *infos; // linked list
struct addrinfo hints; // hints to getaddrinfo()
struct addrinfo *p; // used in the loop to get valid addrinfo
long receivedBytes; // the received bytes
unsigned requestLength; // the length of the request
char *request; // the http request
// GET ADDRESS INFO
// fill hints
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
// getaddrinfo
status = getaddrinfo(host,
"80",
&hints,
&infos);
if(status != 0) {
if(errorType) *errorType = IEFGAIError;
return status;
}
// FIND FIRST VALID SOCKET
for(p = infos; p != NULL; p = p->ai_next) {
// create
sockfd = socket(p->ai_family,
p->ai_socktype,
p->ai_protocol);
if(sockfd == -1)
continue;
// try to connect
status = connect(sockfd,
p->ai_addr,
p->ai_addrlen);
if(status == -1) {
close(sockfd);
continue;
}
break;
}
// no valid socket found
if(p == NULL) {
if(errorType) *errorType = IEFConnectError;
return status;
}
// GET RID OF INFOS
freeaddrinfo(infos);
// SEND HTTP REQUEST
// calculate request length and make
requestLength = strlen("GET ") + strlen(filepath) + strlen(" HTTP\1.0\n") + strlen("Host: ") + strlen(host) + strlen(":80\n\n") + 1;
request = malloc(sizeof(char) * requestLength);
snprintf(request, requestLength, "GET %s HTTP\1.0\nHost: %s:80\n\n", filepath, host);
// send
status = send(sockfd,
request,
requestLength - 1,
0);
if(status == -1) {
if(errorType) *errorType = IEFSendError;
close(sockfd);
return errno;
}
// RECEIVE DATA
receivedBytes = recv(sockfd,
buffer,
maxSize,
0);
if(receivedBytes == -1 || receivedBytes == 0) {
if(errorType) *errorType = IEFReceiveError;
close(sockfd);
return receivedBytes;
}
// SET POINTERS
if(errorType) *errorType = IEFNoError;
if(rB) *rB = receivedBytes;
return 0;
}
void *
IEFDownerGetInAddr(struct sockaddr *sa) {
// IP4
if(sa->sa_family == AF_INET)
return &(((struct sockaddr_in *) sa)->sin_addr);
// IP6
return &(((struct sockaddr_in6 *) sa)->sin6_addr);
}
int
IEFDownerGetContentLengthOfPage(const char *httpHeader, int *contentLength) {
register int i;
int length;
char *next;
char *completeHeader;
char *header;
char *fieldName;
// MAKE HEADER MUTABLE
completeHeader = malloc(sizeof(char) * (strlen(httpHeader) + 1));
strcpy(completeHeader, httpHeader);
header = completeHeader;
// SEARCH FOR LINE
// loop for all lines
next = header;
do {
header = next;
// replace newline
next = strstr(header, "\n");
if(next == NULL) {
free(header);
return -1;
}
*next = '\0';
for(i = 0; i != strlen("\n"); i++)
next++;
} while (strcasestr(header, "Content-Length:") == NULL);
// SCAN INTEGER
fieldName = strcasestr(header, "Content-Length:");
for(i = 0; i != strlen("Content-Length:"); i++)
fieldName++;
sscanf(fieldName, "%d", &length);
if(contentLength) *contentLength = length;
free(completeHeader);
return 0;
}
int
IEFDownerGetSizeOfHeader(const char *received, int *headerSize) {
int length;
int receivedLength;
char *next;
char *completeHeader;
char *header;
char *checkChar;
int firstNonEmptyLineFound;
int emptiesFound;
// MAKE HEADER MUTABLE
completeHeader = malloc(sizeof(char) * (strlen(received) + 1));
strcpy(completeHeader, received);
header = completeHeader;
// SEARCH FOR FIRST NON EMPTY LINE
receivedLength = strlen(header);
firstNonEmptyLineFound = 0;
for(next = header; *next != (char)NULL; next++) {
printf("%c",*next);
if(*next != '\n' && *next != '\r') {
firstNonEmptyLineFound = 1;
printf("\nFirst Non Empty Found\n\n");
next++;
break;
}
}
if(firstNonEmptyLineFound == 0) {
free(completeHeader);
return -1;
}
// SEARCH FOR FIRST EMPTY LINE
emptiesFound = 0;
for(; *next != (char)NULL; next++) {
checkChar = next;
printf("%c", *checkChar);
if(*checkChar == '\n' || *checkChar == '\r') {
checkChar++;
printf("%c", *checkChar);
if(*checkChar == '\n' || *checkChar == '\r') {
emptiesFound = 1;
printf("Empty Line Found\n\n");
break;
}
}
}
if(emptiesFound == 0) {
free(completeHeader);
return -1;
}
// GET END OF HEADER
for(; *next != (char)NULL; next++) {
printf("%c", *next);
if(*next != '\n' && *next != '\r') {
printf("End of header found");
break;
}
}
// INSERT NULL
*next == '\0';
length = strlen(header);
if(headerSize) *headerSize = length;
free(completeHeader);
return 0;
}
main.c
#include <stdio.h>
#include <stdarg.h>
#include "IEFDowner.h"
#define SERVERNAME "developerief2.site11.com"
#define PROTOCOL "80"
#define FILENAME "http://developerief2.site11.com/welcome/welcome.php"
#define MAXHEADERSIZE (1024*1024)
#define DESTFILE "/Users/ief2/Desktop/file.png"
void errorOut(int status, const char *format, ...);
int main (int argc, const char * argv[]) {
int status; // return status
void *headerData; // header data
int headerSize; // size of header
long rB; // received bytes
int pageSize; // size of bytes of page
// GET PAGE SIZE
// get data
headerData = malloc(1024);
status = IEFDownerHTTPDownload(SERVERNAME,
FILENAME,
(void *)headerData,
1024 - 1,
&rB, NULL);
if(status != 0)
errorOut(status, "An error occured while downloading header info\n");
// null terminate data
((char *)headerData)[rB] = '\0';
// get size
status = IEFDownerGetContentLengthOfPage((const char *)headerData, &pageSize);
if(status != 0)
errorOut(status, "An error occured while retreiving page size\n");
printf("Page Size: %d\n", pageSize);
printf("---------------------\n%s\n---------------------\n", headerData);
// CALCULATE HEADER SIZE
status = IEFDownerGetSizeOfHeader(headerData, &headerSize);
if(status != 0)
errorOut(status, "An error occured while getting the header size\n");
printf("Header Size: %d\n", headerSize);
return 0;
}
void errorOut(int status, const char *format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(status);
}
The result I'm getting is not correct. I'm getting the end of the response after the first line already:
[Session started at 2010-08-03 21:32:47 +0000.]
Page Size: 3600
---------------------
HTTP/1.1 200 OK
Date: Tue, 03 Aug 2010 19:32:44 GMT
Server: Apache
X-Powered-By: PHP/5.2.11
Content-Length: 3600
Connection: close
Content-Type: text/html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en">
<!-- HEAD -->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-16" />
<meta name="description" content="A site containing quality freeware for Mac OS X Tiger and newer. All applications are made by a 14 year old developer who masters AppleScript Studio, Objective-C, HTML, PHP, CSS and JavaScript." />
<meta name="keywords" content="free, freeware, mac os x, 10, tiger, leopard, mac os x, young, developer, freeware, AppleScript, Studio, Xcode, Objective-C, Cocoa" />
<title>Free OSX Software :: Welcome</title>
<!-- Shared Styles -->
<link rel="stylesheet" href="../site-style/styles.css" type="text/css" media="screen" title="no title" charset="utf-8" />
</head>
<!-- PAGE CONTENTS -->
<body>
---------------------
H
First Non Empty Found
TTP/1.1 200 OK
Empty Line Found
DEnd of header foundHeader Size: 1023
The Debugger has exited with status 0.
I hope somebody can help me,
ief2
It seems I have to read things better people write. Due to the previous question I should have already known that the new line in the HTTP responses are two characters: Carriage Return and a Line Feed ("\r\n"), so I should do a string compare.
New Code
int
IEFDownerGetSizeOfHeader(const char *received, int *headerSize) {
int length;
int receivedLength;
char *next;
char *completeHeader;
char *header;
char *checkChar;
int firstNonEmptyLineFound;
int emptiesFound;
// MAKE HEADER MUTABLE
completeHeader = malloc(sizeof(char) * (strlen(received) + 1));
strcpy(completeHeader, received);
header = completeHeader;
// SEARCH FOR FIRST NON EMPTY LINE
receivedLength = strlen(header);
firstNonEmptyLineFound = 0;
for(next = header; *next != (char)NULL; next++) {
if(strncmp(next, "\r\n", 2) != 0) {
firstNonEmptyLineFound = 1;
next++;
break;
}
}
if(firstNonEmptyLineFound == 0) {
free(completeHeader);
return -1;
}
// SEARCH FOR FIRST EMPTY LINE
emptiesFound = 0;
for(; *next != (char)NULL; next++) {
checkChar = next;
if(strncmp(checkChar, "\r\n", 2) == 0) {
checkChar++;
checkChar++;
if(strncmp(checkChar, "\r\n", 2) == 0) {
emptiesFound = 1;
next = checkChar;
break;
}
}
}
if(emptiesFound == 0) {
free(completeHeader);
return -1;
}
// GET END OF HEADER
for(; *next != (char)NULL; next++) {
if(strncmp(next, "\r\n", 2) != 0) {
break;
}
next++;
}
// INSERT NULL
*next = '\0';
length = strlen(header);
if(headerSize) *headerSize = length;
free(completeHeader);
return 0;
}
I hope this can be useful to some people,
ief2

Resources