diff options
author | Jack Sangdahl <[email protected]> | 2024-04-02 23:09:33 -0600 |
---|---|---|
committer | Jack Sangdahl <[email protected]> | 2024-04-02 23:09:33 -0600 |
commit | 7ddf686201d052e7c55d622dddd62b7e2ede880d (patch) | |
tree | 1ce98638df78223b5a42ef8ba7aa7b1f5d49941a | |
parent | f3172b837cc728dec1daa74ce98a72548f204b21 (diff) | |
download | csci3753-7ddf686201d052e7c55d622dddd62b7e2ede880d.tar.gz csci3753-7ddf686201d052e7c55d622dddd62b7e2ede880d.zip |
pa6
-rw-r--r-- | pa6_threaded_resolver/Makefile | 37 | ||||
-rw-r--r-- | pa6_threaded_resolver/array.c | 48 | ||||
-rw-r--r-- | pa6_threaded_resolver/array.h | 62 | ||||
-rw-r--r-- | pa6_threaded_resolver/multi-lookup.c | 172 | ||||
-rw-r--r-- | pa6_threaded_resolver/multi-lookup.h | 44 | ||||
-rw-r--r-- | pa6_threaded_resolver/process.png | bin | 0 -> 65316 bytes | |||
-rw-r--r-- | pa6_threaded_resolver/readme.md | 180 | ||||
-rw-r--r-- | pa6_threaded_resolver/util.c | 85 | ||||
-rw-r--r-- | pa6_threaded_resolver/util.h | 42 |
9 files changed, 670 insertions, 0 deletions
diff --git a/pa6_threaded_resolver/Makefile b/pa6_threaded_resolver/Makefile new file mode 100644 index 0000000..80efc14 --- /dev/null +++ b/pa6_threaded_resolver/Makefile @@ -0,0 +1,37 @@ +# Makefile v1 for CSCI3753-F23 PA6 + +# Add any additional source files you'd like to submit by appending +# .c filenames to the MSRCS line and .h filenames to the MHDRS line +MSRCS = multi-lookup.c array.c +MHDRS = multi-lookup.h array.h + +# Do not modify anything after this line +CC = gcc +CFLAGS = -Wextra -Wall -g -std=gnu99 +INCLUDES = +LFLAGS = +LIBS = -lpthread + +MAIN = multi-lookup + +SRCS = $(MSRCS) util.c +HDRS = $(MHDRS) util.h + +OBJS = $(SRCS:.c=.o) + +$(MAIN): $(OBJS) + $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS) + +%.o: %.c $(HDRS) + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +.PHONY: clean +clean: + $(RM) *.o *~ $(MAIN) + +SUBMITFILES = $(MSRCS) $(MHDRS) Makefile README +submit: + @read -r -p "Enter your identikey username: " username; \ + echo; echo Bundling the following files for submission; \ + tar --transform "s|^|PA6-$$username/|" -cvf PA6-$$username.txt $(SUBMITFILES); \ + echo; echo Please upload the file PA6-$$username.txt to Canvas to complete your submission; echo diff --git a/pa6_threaded_resolver/array.c b/pa6_threaded_resolver/array.c new file mode 100644 index 0000000..e43dbdf --- /dev/null +++ b/pa6_threaded_resolver/array.c @@ -0,0 +1,48 @@ +// Jack Sangdahl +// CSCI3753 SP24 +// PA6 Threaded Resolver +#include "array.h" + +int queue_init(queue *q, int queue_size) { + q->data = malloc(queue_size * sizeof(node)); + q->maxsize = queue_size; + q->front = 0; + q->back = -1; + q->size = 0; + return EXIT_SUCCESS; +} + +int queue_size(queue *q) { return q->size; } + +bool queue_full(queue *q) { return (q->size == q->maxsize); } + +int queue_push(queue *q, void *element) { + if (queue_full(q)) { + fprintf(stderr, "push error: queue full\n"); + return EXIT_FAILURE; + } + q->back = (q->back + 1) % q->maxsize; + q->data[q->back].value = element; + q->size++; + return EXIT_SUCCESS; +} + +void *queue_pop(queue *q) { + if (!queue_size(q)) { + fprintf(stderr, "pop error: queue empty\n"); + return NULL; + } + void *value = q->data[q->front].value; + q->data[q->front].value = NULL; + q->front = (q->front + 1) % q->maxsize; + q->size--; + return value; +} + +void queue_free(queue *q) { + while (q->size > 0) { + void *val = queue_pop(q); + free(val); + } + free(q->data); +} diff --git a/pa6_threaded_resolver/array.h b/pa6_threaded_resolver/array.h new file mode 100644 index 0000000..adceca8 --- /dev/null +++ b/pa6_threaded_resolver/array.h @@ -0,0 +1,62 @@ +// Jack Sangdahl +// CSCI3753 SP24 +// PA6 Threaded Resolver +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> + +typedef struct { + void *value; +} node; + +typedef struct { + node *data; + int size; + int maxsize; + int front; + int back; +} queue; + +/** + * @brief initialise the queue + * @param q + * @param size + * @return int + */ +int queue_init(queue *q, int size); + +/** + * @brief return size of queue + * @param q + * @return int + */ +int queue_size(queue *q); + +/** + * @brief return true if que size is + * greater than ARRAY_SIZE. false otherwise + * @param q + * @return bool + */ +bool queue_full(queue *q); + +/** + * @brief add element to fifo queue. block when full + * @param q + * @param val + * @return int + */ +int queue_push(queue *q, void *val); + +/** + * @brief return top element of queue in fifo order + * return null pointer if queue empty + * @param q + */ +void *queue_pop(queue *q); + +/** + * @brief free queue's resources + * @param q + */ +void queue_free(queue *q); diff --git a/pa6_threaded_resolver/multi-lookup.c b/pa6_threaded_resolver/multi-lookup.c new file mode 100644 index 0000000..cc96478 --- /dev/null +++ b/pa6_threaded_resolver/multi-lookup.c @@ -0,0 +1,172 @@ +// Jack Sangdahl +// CSCI3753 SP24 +// PA6 Threaded Resolver +#include "multi-lookup.h" +#include <sys/time.h> + +int main(int argc, char *argv[]) { + if (argc < 6) { + fprintf(stderr, + "usage: %s <# requester> <# resolver> <requester log> <resolver " + "log> [ <data file> ... ]\n", + argv[0]); + return EXIT_FAILURE; + } else if (argc > MAX_INPUT_FILES + 6) { + fprintf(stderr, "%s error: too many input files\n", argv[0]); + return EXIT_FAILURE; + } + struct timeval proc_begin, proc_end; + gettimeofday(&proc_begin, NULL); + uint8_t req_thread = atoi(argv[1]); + if (req_thread < 1) { + fprintf(stderr, "%s error: minimum 1 requester thread\n", argv[0]); + return EXIT_FAILURE; + } else if (req_thread > MAX_REQUESTER_THREADS) { + fprintf(stderr, "%s error: requester threads cannot exceed %d\n", argv[0], + MAX_REQUESTER_THREADS); + return EXIT_FAILURE; + } + uint8_t res_threads = atoi(argv[2]); + if (res_threads < 1) { + fprintf(stderr, "%s error: minimum 1 resolver thread\n", argv[0]); + return EXIT_FAILURE; + } else if (res_threads > MAX_RESOLVER_THREADS) { + fprintf(stderr, "%s error: resolver threads cannot exceed %d\n", argv[0], + MAX_RESOLVER_THREADS); + return EXIT_FAILURE; + } + queue input_files; + queue_init(&input_files, MAX_INPUT_FILES); + for (int i = 5; i < argc; i++) { + if (access(argv[i], F_OK) == -1) + fprintf(stderr, "%s error: invalid data file '%s'\n", argv[0], argv[i]); + else + queue_push(&input_files, strndup(argv[i], strlen(argv[i]))); + } + if (!queue_size(&input_files)) { + fprintf(stderr, "%s error: no valid data file given\n", argv[0]); + return EXIT_FAILURE; + } + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t c_req = PTHREAD_COND_INITIALIZER; + pthread_cond_t c_res = PTHREAD_COND_INITIALIZER; + pthread_mutex_t input_lock = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t req_log_lock = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t res_log_lock = PTHREAD_MUTEX_INITIALIZER; + bool req_done = 0; + queue buffer; + queue_init(&buffer, ARRAY_SIZE); + request_data req_data; + req_data.req_log = fopen(argv[3], "w"); + req_data.file_names = &input_files; + req_data.buffer = &buffer; + req_data.m = &m; + req_data.c_req = &c_req; + req_data.c_res = &c_res; + req_data.input_lock = &input_lock; + req_data.req_log_lock = &req_log_lock; + resolve_data res_data; + res_data.res_log = fopen(argv[4], "w"); + res_data.buffer = &buffer; + res_data.m = &m; + res_data.c_req = &c_req; + res_data.c_res = &c_res; + res_data.res_log_lock = &res_log_lock; + res_data.req_done = &req_done; + pthread_t request_tid[req_thread]; + pthread_t resolve_tid[res_threads]; + for (int i = 0; i < req_thread; i++) + pthread_create(&request_tid[i], NULL, request, &req_data); + for (int i = 0; i < res_threads; i++) + pthread_create(&resolve_tid[i], NULL, resolve, &res_data); + for (int i = 0; i < req_thread; i++) + pthread_join(request_tid[i], NULL); + pthread_mutex_lock(&m); + req_done = 1; + pthread_mutex_unlock(&m); + for (int i = 0; i < res_threads; i++) + pthread_join(resolve_tid[i], NULL); + fclose(req_data.req_log); + fclose(res_data.res_log); + queue_free(&input_files); + queue_free(&buffer); + printf("Number of Requestor Threads: %d\n", req_thread); + printf("Number of Resolver Threads: %d\n", res_threads); + gettimeofday(&proc_end, NULL); + fprintf(stdout, "%s: total time is %f seconds\n", argv[0], + ELAPSED_SECONDS(proc_begin, proc_end)); + return EXIT_SUCCESS; +} + +void *request(void *data) { + request_data *req_data = (request_data *)data; + uint8_t file_count = 0; + while (1) { + pthread_mutex_lock(req_data->input_lock); + if (queue_size(req_data->file_names) > 0) { + char *data_file = queue_pop(req_data->file_names); + file_count++; + pthread_mutex_unlock(req_data->input_lock); + FILE *file = fopen(data_file, "r"); + char line[MAX_NAME_LENGTH]; + while (fgets(line, sizeof(line), file)) { + pthread_mutex_lock(req_data->m); + while (queue_full(req_data->buffer)) + pthread_cond_wait(req_data->c_req, req_data->m); + pthread_mutex_lock(req_data->req_log_lock); + fprintf(req_data->req_log, "%s", line); + pthread_mutex_unlock(req_data->req_log_lock); + queue_push(req_data->buffer, strndup(strtok(line, "\n"), strlen(line))); + pthread_mutex_unlock(req_data->m); + pthread_cond_signal(req_data->c_res); + } + fclose(file); + free(data_file); + } else { + pthread_mutex_unlock(req_data->input_lock); + break; + } + } + fprintf(stdout, "thread %ld serviced %d files\n", syscall(SYS_gettid), + file_count); + return 0; +} + +void *resolve(void *data) { + resolve_data *res_data = (resolve_data *)data; + char *ip = (char *)malloc(MAX_IP_LENGTH); + uint16_t domain_cnt = 0; + struct timeval thread_begin, thread_end; + gettimeofday(&thread_begin, NULL); + while (1) { + pthread_mutex_lock(res_data->m); + if (!(*(res_data->req_done)) || queue_size(res_data->buffer)) { + while (!queue_size(res_data->buffer)) + pthread_cond_wait(res_data->c_res, res_data->m); + char *domain = queue_pop(res_data->buffer); + pthread_mutex_unlock(res_data->m); + pthread_cond_signal(res_data->c_req); + if (dnslookup(domain, ip, MAX_IP_LENGTH)) { + pthread_mutex_lock(res_data->res_log_lock); + fprintf(res_data->res_log, "%s, NOT_RESOLVED\n", domain); + pthread_mutex_unlock(res_data->res_log_lock); + domain_cnt++; + } else { + pthread_mutex_lock(res_data->res_log_lock); + fprintf(res_data->res_log, "%s, %s\n", domain, ip); + pthread_mutex_unlock(res_data->res_log_lock); + domain_cnt++; + } + free(domain); + } else { + pthread_mutex_unlock(res_data->m); + break; + } + } + free(ip); + gettimeofday(&thread_end, NULL); + fprintf(stdout, "thread %ld resolved %d hostnames in %f seconds\n", + syscall(SYS_gettid), domain_cnt, + ELAPSED_SECONDS(thread_begin, thread_end)); + return 0; +} diff --git a/pa6_threaded_resolver/multi-lookup.h b/pa6_threaded_resolver/multi-lookup.h new file mode 100644 index 0000000..41e74d5 --- /dev/null +++ b/pa6_threaded_resolver/multi-lookup.h @@ -0,0 +1,44 @@ +// Jack Sangdahl +// CSCI3753 SP24 +// PA6 Threaded Resolver +#include "array.h" +#include "util.h" +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <unistd.h> + +#define ARRAY_SIZE 8 +#define MAX_INPUT_FILES 100 +#define MAX_REQUESTER_THREADS 10 +#define MAX_RESOLVER_THREADS 10 +#define MAX_NAME_LENGTH 16 +#define MAX_IP_LENGTH INET6_ADDRSTRLEN +#define ELAPSED_SECONDS(a, b) \ + ((double)(b.tv_usec - a.tv_usec) / 1000000 + (double)(b.tv_sec - a.tv_sec)) + +void *request(void *data); +void *resolve(void *data); + +typedef struct { + FILE *req_log; + queue *file_names; + queue *buffer; + pthread_mutex_t *m; + pthread_cond_t *c_req; + pthread_cond_t *c_res; + pthread_mutex_t *input_lock; + pthread_mutex_t *req_log_lock; +} request_data; + +typedef struct { + FILE *res_log; + queue *buffer; + pthread_mutex_t *m; + pthread_cond_t *c_req; + pthread_cond_t *c_res; + pthread_mutex_t *res_log_lock; + bool *req_done; +} resolve_data; diff --git a/pa6_threaded_resolver/process.png b/pa6_threaded_resolver/process.png Binary files differnew file mode 100644 index 0000000..0d492ac --- /dev/null +++ b/pa6_threaded_resolver/process.png diff --git a/pa6_threaded_resolver/readme.md b/pa6_threaded_resolver/readme.md new file mode 100644 index 0000000..6cd9dc7 --- /dev/null +++ b/pa6_threaded_resolver/readme.md @@ -0,0 +1,180 @@ +## PA6 - Threaded Resolver +### overview +this assignment will develop a multi-threaded application that resolves domain names +to ip addresses. this is similar to the operation performed each time you access a new +website in your web browser. the application will utilise two types of worker threads: +**requesters** and **resolvers**. these threads will communicate with eachother using a +shared array, sometimes referred to as a bounded buffer. the diagram below outlines +the desired configuration +![image](process.png) +provided is a set of input files that containe one hostname per line. your program +will process each of these files using a single requester thread per file, where each +thread will read the file line by line, place the hostname into the shared array, and +write this hostname into the requester logfile. you will also create some number of +resolver threads, again determined by a command line argument, that will remove +hostnames from the shared array, lookup the ip address for that hostname, and write +the results to the resolver logfile. once all the input files have been parsed, the +requester threads will terminate. once all the hostnames have been looked up, the +resolver threads will terminate and the program will end. + +### mutli-lookup man page +``` +NAME +multi-lookup - resolve a set of hostnames to IP addresses + +SYNOPSIS +multi-lookup <# requester> <# resolver> <requester log> <resolver log> [ <data file> ... ] + +DESCRIPTION +The file names specified by <data file> are passed to the pool of requester threads which place +information into a shared data area. Resolver threads read the shared data area and find the +corresponding IP address. + +<# requesters> number of requestor threads to place into the thread pool +<# resolvers> number of resolver threads to place into the thread pool +<requester log> name of the file into which requested hostnames are written +<resolver log> name of the file into which hostnames and resolved IP addresses are written +<data file> filename to be processed. Each file contains a list of host names, one per line, that +are to be resolved + +SAMPLE INVOCATION +./multi-lookup 5 5 serviced.txt resolved.txt input/names*.txt + +SAMPLE CONSOLE OUTPUT +thread d2fa8700 serviced 6 files in 0.200960 seconds +thread d37a9700 serviced 6 files in 0.201183 seconds +thread d27a7700 serviced 6 files in 0.201345 seconds +thread d3faa700 serviced 6 files in 0.201562 seconds +thread d47ab700 serviced 6 files in 0.201787 seconds +thread d4fac700 resolved 177 hosts in 0.202039 seconds +thread d57ad700 resolved 89 hosts in 0.202088 seconds +thread d67af700 resolved 171 hosts in 0.202204 seconds +thread d6fb0700 resolved 32 hosts in 0.202244 seconds +thread d5fae700 resolved 137 hosts in 0.202215 seconds +./multi-lookup: total time is 0.202741 seconds +``` + +### requester threads +your application will take an argument for the number of requester threads. this pool +of threads service a set of text files as input, each of which contains a list of +hostnames. each name read should be placed on the shared array. if a requester thread +tries to write to the array but finds that it is full, it should block until a space +opens up in the array. after servicing an input file, a requester thread checks if +there are any remaining input files left to service. if so, it requests one of the +remaining files next. this process goes on until all input files have been processed. +if there are no more input files remaining, the thread writes the number of files it +serviced to stdout in the following format: +``` +thread <thread_id> serviced ### files +``` +to get the id of a thread on linux systems, use `gettid()`, or more preferably, +`pthread_self()` for a posix compliant implementation. + +### resolver threads +the second thread pool is comprised of a set of resolver threads. a resolver thread +consumers the shared array by taking a name off the array and resolving its ip +address. after the name has been mapped to an ip address, the output is written to a +line in the resolver logfile in the following format: +``` +google.com, 74.125.224.81 +``` +if the resolver is unable to find the ip address for a hostname, it should leave +`NOT_RESOLVED` instead of an ip address. if a resolver tries to read from the array +but find that it is empty, it should block until there is a new item in the array or +all names in the input files have been serviced. if there are no more hostnames +remaining, the thread writes the number of names it successfully resolved to stdout +in the following format: +``` +thread <thread_id> resolved ### hostnames +``` + +### shared array +thre thread safe shared array will require you to implement a solution to the bounded +buffer problem as discussed in lecture and textbook. the shared array must be built +on top of a single, contiguous, linear array of memory. you can organise this array +as a queue (fifo), circular queue, or stack (lifo). solutions that rely on linked +lists, trees, dictionaries, etc. will not be accepted. + +### synchronisation, deadlock, & starvation +application should synchronise access to shared resources and avoid any deadlock or +busying wait. you should use some combination of mutexes, semaphores, and/or +condition variables to meet this requirement. there are several shared resources that +must be protected: the shared array, the logfiles, stdout/stderr, and argc/argv. none +of these resources are thread safe by default. we will be measuring the runtime of +your solution to determine if it is experiencing any sort of starvation. if you +misuse a synchronisation mechanism and essentially create a serialised solution ( +where your threads run in sequence, rather than in parallel), your grade will be +reduced. + +### ending program +your program must end after all the names in each input file have been serviced by +the application. this means that all the hostnames in all the input files have +received a corresponding line in the output file. just prior to exiting, your +program will print the total runtime to stdout: +``` +./multi-lookup: total time is 2.420237 seconds +``` + +### limits +several macros should be defined to impose the following limits on your program. if +the user specifies input that violate an imposed limit, your program should alert +the user gracefully to the limit and exit with an error and appropriate return +value. you should define these macros in corresponding header files: +* `ARRAY_SIZE`: 8 - number of elements in the shared array used by the requester +and resolved threads to communicate +* `MAX_INPUT_FILES`: 100 - maximum number of hostname file arguments allowed +* `MAX_REQUESTER_THREADS`: 10 - maximum number of concurrent requester threads +allowed +* `MAX_RESOLVER_THREADS`: 10 - maximum number of concurrent resolver threads allowed +* `MAX_IP_LENGTH`: `INET6_ADDRSTRLEN` - maximum size ip address string `util.c` will +return + +### error handling +program must accept arguments as detailed in the above manual page. progam should +deal with the following conditions: +* missing arguments - terminate with a usage synopsis to stdout +* arguments that are out of range (too many input files) - terminate with an error +message to stderr +* if a log file exists and is writeable, it should overwritten +* if a log file does not exist, it should be created by program +* missing or unreadable input files - print `invalid file <filename>` to stderr, +then move onto next file + +### valgrind +to verify there are no memory leaks, valgrind will be used to test program. usage: +``` +valgrind ./multi-lookup 5 5 serviced.txt results.txt input/names1*.txt +``` +valgrind should report that you have freed all allocated memory and should produce +any additional warnings or errors: +``` +==21728== Memcheck, a memory error detector +==21728== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. +==21728== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info +==21728== Command: ./multi-lookup 5 5 serviced.txt results.txt input/names11.txt input/names12.txt input/names13.txt input/names14.txt input/names15.txt input/names1.txt +==21728== +./multi-lookup: total time is 2.420237 seconds +==21728== +==21728== HEAP SUMMARY: +==21728== in use at exit: 0 bytes in 0 blocks +==21728== total heap usage: 1,723 allocs, 1,723 frees, 9,394,035 bytes allocated +==21728== +==21728== All heap blocks were freed -- no leaks are possible +==21728== +==21728== For counts of detected and suppressed errors, rerun with: -v +==21728== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +``` +for comparison, here's output from a leaky program: +``` +==22400== HEAP SUMMARY: +==22400== in use at exit: 7,380 bytes in 618 blocks +==22400== total heap usage: 8,115 allocs, 7,497 frees, 45,674,418 bytes allocated +==22400== +==22400== LEAK SUMMARY: +==22400== definitely lost: 7,380 bytes in 618 blocks +==22400== indirectly lost: 0 bytes in 0 blocks +==22400== possibly lost: 0 bytes in 0 blocks +==22400== still reachable: 0 bytes in 0 blocks +==22400== suppressed: 0 bytes in 0 blocks +==22400== Rerun with --leak-check=full to see details of leaked memory +``` diff --git a/pa6_threaded_resolver/util.c b/pa6_threaded_resolver/util.c new file mode 100644 index 0000000..0b4a825 --- /dev/null +++ b/pa6_threaded_resolver/util.c @@ -0,0 +1,85 @@ +/* + * File: util.c + * Author: Andy Sayler + * Modified: Shiv Mishra + * Project: CSCI 3753 Programming Assignment 5 + * Create Date: 2012/02/01 + * Modify Date: 2012/02/01 + * Modify Date: 2016/09/26 + * Description: + * This file contains declarations of utility functions for + * Programming Assignment 5. + * + */ + +#include "util.h" + +int dnslookup(const char* hostname, char* firstIPstr, int maxSize){ + + /* Local vars */ + struct addrinfo* headresult = NULL; + struct addrinfo* result = NULL; + struct sockaddr_in* ipv4sock = NULL; + struct in_addr* ipv4addr = NULL; + char ipv4str[INET_ADDRSTRLEN]; + char ipstr[INET6_ADDRSTRLEN]; + int addrError = 0; + + /* DEBUG: Print Hostname*/ +#ifdef UTIL_DEBUG + fprintf(stderr, "%s\n", hostname); +#endif + + /* Lookup Hostname */ + addrError = getaddrinfo(hostname, NULL, NULL, &headresult); + if(addrError){ + fprintf(stderr, "Error looking up Address: %s\n", + gai_strerror(addrError)); + return UTIL_FAILURE; + } + /* Loop Through result Linked List */ + for(result=headresult; result != NULL; result = result->ai_next){ + /* Extract IP Address and Convert to String */ + if(result->ai_addr->sa_family == AF_INET){ + /* IPv4 Address Handling */ + ipv4sock = (struct sockaddr_in*)(result->ai_addr); + ipv4addr = &(ipv4sock->sin_addr); + if(!inet_ntop(result->ai_family, ipv4addr, + ipv4str, sizeof(ipv4str))){ + perror("Error Converting IP to String"); + return UTIL_FAILURE; + } +#ifdef UTIL_DEBUG + fprintf(stdout, "%s\n", ipv4str); +#endif + strncpy(ipstr, ipv4str, sizeof(ipstr)); + ipstr[sizeof(ipstr)-1] = '\0'; + } + else if(result->ai_addr->sa_family == AF_INET6){ + /* IPv6 Handling */ +#ifdef UTIL_DEBUG + fprintf(stdout, "IPv6 Address: Not Handled\n"); +#endif + strncpy(ipstr, "UNHANDELED", sizeof(ipstr)); + ipstr[sizeof(ipstr)-1] = '\0'; + } + else{ + /* Unhandlded Protocol Handling */ +#ifdef UTIL_DEBUG + fprintf(stdout, "Unknown Protocol: Not Handled\n"); +#endif + strncpy(ipstr, "UNHANDELED", sizeof(ipstr)); + ipstr[sizeof(ipstr)-1] = '\0'; + } + /* Save First IP Address */ + if(result==headresult){ + strncpy(firstIPstr, ipstr, maxSize); + firstIPstr[maxSize-1] = '\0'; + } + } + + /* Cleanup */ + freeaddrinfo(headresult); + + return UTIL_SUCCESS; +} diff --git a/pa6_threaded_resolver/util.h b/pa6_threaded_resolver/util.h new file mode 100644 index 0000000..d0f7559 --- /dev/null +++ b/pa6_threaded_resolver/util.h @@ -0,0 +1,42 @@ +/* + * File: util.h + * Author: Andy Sayler + * Modified: Shiv Mishra + * Project: CSCI 3753 Programming Assignment 3 + * Create Date: 2012/02/01 + * Modify Date: 2012/02/01 + * Modify Date: 2016/09/26 + * Description: + * This file contains declarations of utility functions for + * Programming Assignment 3. + * + */ + +#ifndef UTIL_H +#define UTIL_H + +/* Define the following to enable debug statments */ +// #define UTIL_DEBUG + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#define UTIL_FAILURE -1 +#define UTIL_SUCCESS 0 + +/* Fuction to return the first IP address found + * for hostname. IP address returned as string + * firstIPstr of size maxsize + */ +int dnslookup(const char* hostname, + char* firstIPstr, + int maxSize); + +#endif |