From 7b55d84171f45c5fcb4907536cb695a236cbd621 Mon Sep 17 00:00:00 2001 From: Rockingcool Date: Mon, 3 Apr 2023 09:48:02 -0500 Subject: [PATCH] Added socket library files --- easysock.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++ easysock.h | 75 ++++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 easysock.c create mode 100644 easysock.h diff --git a/easysock.c b/easysock.c new file mode 100644 index 0000000..342da70 --- /dev/null +++ b/easysock.c @@ -0,0 +1,169 @@ +#include "easysock.h" + +int create_socket(int network, char transport) { + int domain; + int type; + + if (network == 4) { + domain = AF_INET; + } else if (network == 6) { + domain = AF_INET6; + } else { + return -1; + } + + if (transport == 'T') { + type = SOCK_STREAM; + } else if (transport == 'U') { + type = SOCK_DGRAM; + } else { + return -1; + } + + int newSock = socket(domain,type,0); + return newSock; +} + + +void create_addr(int network, char* address, int port,struct sockaddr* dest) { + if (network == 4) { + struct sockaddr_in listen_address; + + listen_address.sin_family = AF_INET; + listen_address.sin_port = htons(port); + inet_pton(AF_INET,address,&listen_address.sin_addr); + memcpy(dest,&listen_address,sizeof(listen_address)); + return; + + } else if (network == 6) { + struct sockaddr_in6 listen_ipv6; + listen_ipv6.sin6_family = AF_INET6; + listen_ipv6.sin6_port = htons(port); + inet_pton(AF_INET6,address,&listen_ipv6.sin6_addr); + memcpy(dest,&listen_ipv6,sizeof(listen_ipv6)); + return; + + } else { + exit(202); + } + +} + +int create_local (int network, char transport, char* address, int port,struct sockaddr* addr_struct) { + int socket = create_socket(network,transport); + if (socket < 0) { + exit(errno); + } + create_addr(network,address,port,addr_struct); + int addrlen; + if (network == 4) { + addrlen = sizeof(struct sockaddr_in); + } else if (network == 6) { + addrlen = sizeof(struct sockaddr_in6); + } else { + exit(207); + } + + /* The value of addrlen should be the size of the 'sockaddr'. + This should be set to the size of 'sockaddr_in' for IPv4, and 'sockaddr_in6' for IPv6. + See https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos */ + + int i = bind (socket,addr_struct,(socklen_t)addrlen); + if (i < 0) { + exit(errno); + } + return socket; +} + +int create_remote (int network,char transport,char* address,int port,struct sockaddr* remote_addr_struct) { + + struct addrinfo hints; /* Used to tell getaddrinfo what kind of address we want */ + struct addrinfo* results; /* Used by getaddrinfo to store the addresses */ + + + if (check_ip_ver(address) < 0) { /* If the address is a domain name */ + int err_code; + char* port_str = malloc(10 * sizeof(char)); + + sprintf(port_str,"%d",port); /* getaddrinfo expects a string for its port */ + + + memset(&hints,'\0',sizeof(hints)); + hints.ai_socktype = char_to_socktype(transport); + + err_code = getaddrinfo(address,port_str,&hints,&results); + if (err_code != 0) { + exit(err_code); + } + remote_addr_struct = results->ai_addr; + network = inet_to_int(results->ai_family); + } else { + create_addr(network,address,port,remote_addr_struct); + } + + int socket = create_socket(network,transport); + if (socket < 0) { + exit(errno); + } + + int addrlen; + if (network == 4) { + addrlen = sizeof(struct sockaddr_in); + } else if (network == 6) { + addrlen = sizeof(struct sockaddr_in6); + } else { + exit(207); + } + + /* The value of addrlen should be the size of the 'sockaddr'. + This should be set to the size of 'sockaddr_in' for IPv4, and 'sockaddr_in6' for IPv6. + See https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos */ + + int i = connect(socket,remote_addr_struct,(socklen_t)addrlen); + if (i < 0) { + exit(errno); + } + return socket; +} + + +int check_ip_ver(char* address) { + char buffer[16]; /* 16 chars - 128 bits - is enough to hold an ipv6 address */ + if (inet_pton(AF_INET,address,buffer) == 1) { + return 4; + } else if (inet_pton(AF_INET6,address,buffer) == 1) { + return 6; + } else { + return -1; + } +} + +int int_to_inet(int network) { + if (network == 4) { + return AF_INET; + } else if (network == 6) { + return AF_INET6; + } else { + exit(207); + } +} + +int inet_to_int(int af_type) { + if (af_type == AF_INET) { + return 4; + } else if (af_type == AF_INET6) { + return 6; + } else { + exit(207); + } +} + +int char_to_socktype(char transport) { + if (transport == 'T') { + return SOCK_STREAM; + } else if (transport == 'U') { + return SOCK_DGRAM; + } else { + exit(250); + } +} diff --git a/easysock.h b/easysock.h new file mode 100644 index 0000000..f274174 --- /dev/null +++ b/easysock.h @@ -0,0 +1,75 @@ +#ifndef EASYSOCK_H_ +#define EASYSOCK_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* This function takes: +a layer 3 - network layer - integer, which must be '4' for IPv4 +and 6 for IPv6; and +a layer 4 - transport layer - character, which must be 'T' for +TCP or 'U' for UDP. + +It returns the created socket, or -1 if the socket creation failed.*/ + +int create_socket(int network, char transport); + + +/* This function fills in the sockaddr struct 'dest' based on the given information. +'network' is an integer that contains '4' for IPv4 or '6' for IPv6; +'address' is the address that is filled into the struct; +port is self-explanatory; +and dest is a pointer to the sockaddr struct that will be filled in. + +The function exits with error code 202 if the network parameter contained neither '4' +nor '6'. */ + +void create_addr(int network, char* address, int port,struct sockaddr* dest); + + + +/* This function utilizes the above two functions; it creates the socket and +_binds_ the addresses. It is used for local sockets (server sockets). Parameters are +same as above. + +It prints the error returned by 'bind' if something went wrong, and exits with errno.*/ + +int create_local (int network, char transport, char* address, int port,struct sockaddr* addr_struct); + + +/* This function utilizes the same functions as 'create_local' but _connects_ to the +requested address. It is used for remote sockets (client sockets). The paramters are same +as above. This function needs an empty 'sockaddr *' structure passed to it, which it will fill. + +It prints the error returned by 'connect' if something went wrong, and exits with errno.*/ + +int create_remote (int network,char transport,char* address,int port,struct sockaddr* remote_addr_struct); + +/* check_ip_ver - This function checks if the given string is an IPv4 address (returns 4), +IPv6 address (returns 6) or neither (returns -1). */ + +int check_ip_ver(char* address); + +/* int_to_inet - Takes an int value (4 for IPv4, 6 for IPv6) and returns AF_INET or +AF_INET6 respectively. */ + +int int_to_inet(int network); + +/* char_to_socktype - Takes a character that represents a transport-layer protocol +(currently only supports 'T' for TCP or 'U' for UDP - exits with error code 250 if +the given characters is neither of these) and return the appropriate SOCKTYPE value. */ + +int char_to_socktype(char transport); + +/* inet_to_int - Takes an int value that corresponds to AF_INET or AF_INET6, +and returns the appropriate int value. */ +int inet_to_int(int af_type); + +#endif