Skip to content

Instantly share code, notes, and snippets.

@n1chre
Last active May 6, 2017 18:14
Show Gist options
  • Save n1chre/8ce697b9c3359ac5008e to your computer and use it in GitHub Desktop.
Save n1chre/8ce697b9c3359ac5008e to your computer and use it in GitHub Desktop.
Network programming wrappers for functions and misc
#include "mrepro.h"
void Getaddrinfo(const char* hostname, const char* servicename,
const struct addrinfo* hints, struct addrinfo** result)
{
int error;
error = getaddrinfo(hostname, servicename, hints, result);
if (error) Errx(MP_ADDR_ERR, "getaddrinfo: %s", gai_strerror(error));
}
void Getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen,
char* host, size_t hostlen, char* serv, size_t servlen,
int flags)
{
int error;
error = getnameinfo(sockaddr, addrlen, host, hostlen, serv, servlen, flags);
if (error) Errx(MP_ADDR_ERR, "getnameinfo: %s", gai_strerror(error));
}
int Getpeername(int socket, struct sockaddr* addr, socklen_t* addrlen){
int error;
error = getpeername(socket, addr, addrlen);
if (error) Errx(MP_ADDR_ERR, "getpeername: %s", gai_strerror(error));
return error;
}
void* In_addr(const struct sockaddr *sa){
u_short family = sa->sa_family;
if (family == AF_INET)
return &(( (struct sockaddr_in*) sa)->sin_addr);
return &(( (struct sockaddr_in6*) sa)->sin6_addr);
}
u_short In_port(const struct sockaddr *sa){
u_short family = sa->sa_family;
if (family == AF_INET)
return ( (struct sockaddr_in*) sa)->sin_port;
return (u_short)( (struct sockaddr_in6*) sa)->sin6_port;
}
/*****************************************************************************
* *
* Wrappers *
* *
*****************************************************************************/
void* Malloc(size_t size){
void* ptr;
if ((ptr = malloc(size)) == NULL)
Errx(MP_RUNT_ERR, "malloc: %s", strerror(errno));
return ptr;
}
void* Calloc(size_t size){
void* ptr;
if ((ptr = calloc(1, size)) == NULL)
Errx(MP_RUNT_ERR, "calloc: %s", strerror(errno));
return ptr;
}
pid_t Fork(){
pid_t pid;
if ((pid=fork()) == -1)
Errx(MP_RUNT_ERR, "fork: %s", strerror(errno));
return pid;
}
void Daemon(int nochdir, int noclose){
if (Fork()) _exit(0);
umask(0);
if (setsid() < 0)
Errx(MP_RUNT_ERR, "%s", strerror(errno));
//Signal(SIGCHLD, SIG_IGN); /* ignore child death */
Signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */
if (Fork()) _exit(0);
if (!nochdir){
if (chdir("/") < 0)
Warnx("%s", strerror(errno));
}
if (!noclose){
close(0); // stdin
close(1); // stdout
close(2); // stderr
open("/dev/null", O_RDONLY); /* stdin > /dev/null */
open("/dev/null", O_RDWR); /* stdout > /dev/null */
open("/dev/null", O_RDWR); /* stderr > /dev/null */
}
is_daemon = 1;
}
Sigfunc* signal(int signo, Sigfunc* func){
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
}
Sigfunc* Signal(int signo, Sigfunc* func){
Sigfunc *sigfunc;
if ((sigfunc = signal(signo, func)) == SIG_ERR)
Errx(MP_RUNT_ERR, "signal: %s", strerror(errno));
return sigfunc;
}
void Errx(int status, const char* fmt, ...){
va_list args;
va_start(args, fmt);
if (is_daemon) {
vsyslog(LOG_ALERT, fmt, args);
pthread_exit(&status);
//_exit(status);
} else
verrx(status, fmt, args);
va_end(args);
}
void Warnx(const char* fmt, ...){
va_list args;
va_start(args, fmt);
if (is_daemon)
vsyslog(LOG_INFO, fmt, args);
else
vwarnx(fmt, args);
va_end(args);
}
void Error(const char* function){
Errx(MP_RUNT_ERR, "%s: %s\n", function, strerror(errno));
}
/*****************************************************************************
* *
* Connection *
* *
*****************************************************************************/
// icmp = socket(AF_UNSPEC, SOCK_RAW, IPPROTO_RAW / IPPROTO_ICMP)
int Socket(int family, int type, int protocol){
int sfd = socket(family, type, protocol);
if (sfd < 0) Errx(MP_SOCK_ERR, "socket: %s", strerror(errno));
return sfd;
}
void Bind(int socket, const struct sockaddr* sockaddr, socklen_t addrlen){
int error = bind(socket, sockaddr, addrlen);
if (error < 0) {
Close(socket);
Errx(MP_SOCK_ERR, "bind: %s", strerror(errno));
}
}
void Close(int socket){
int error;
error = shutdown(socket, SHUT_RDWR);
// if (error < 0) Warnx("shutdown: %s", strerror(errno));
error = close(socket);
// if (error < 0) Warnx("close: %s", strerror(errno));
}
/*****************************************************************************
* *
* UDP *
* *
*****************************************************************************/
int UDPserver(const char* port){
struct addrinfo hints, *res;
int socket;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_DGRAM;
// create socket
Getaddrinfo(NULL, port, &hints, &res);
socket = Socket(res->ai_family, res->ai_socktype, res->ai_protocol);
Bind(socket, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
return socket;
}
/*****************************************************************************
* *
* TCP *
* *
*****************************************************************************/
void Listen(int socket, int backlog){
if (listen(socket, backlog)) {
Close(socket);
Errx(MP_COMM_ERR, "listen: %s", strerror(errno));
}
}
int Accept(int socket, struct sockaddr* restrict cliaddr, socklen_t* restrict addrlen){
int client = accept(socket, cliaddr, addrlen);
if (client==-1) Errx(MP_COMM_ERR, "accept: %s", strerror(errno));
return client;
}
void Connect(int socket, const struct sockaddr* server, socklen_t addrlen){
if (connect(socket,server,addrlen)) {
Close(socket);
Errx(MP_COMM_ERR, "connect: %s", strerror(errno));
}
}
char* GetIP(const struct sockaddr* addr){
char* ip = MLC(char, IP_LEN);
inet_ntop(addr->sa_family, In_addr(addr), ip, IP_LEN);
return ip;
}
char* GetClientInfo(int socket, u_short* port){
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
Getpeername(socket, &addr, &addrlen);
if (port != NULL)
*port = ntohs(In_port(&addr));
return GetIP(&addr);
}
void ReadStringUntil(int socket, char* ptr, int size, char end){
ssize_t readBytes = 1;
int i, idx=0;
while (readBytes > 0){
readBytes = Recv(socket, ptr + idx, size-idx, 0);
for (i = 0; i < readBytes; i++) {
if (*(ptr + idx + i) == end) {
ptr[idx+i+1] = 0;
break;
}
}
if (i != readBytes) break;
idx += readBytes;
}
}
void WriteString(int socket, const char* fmt, ...){
char* buff = MLC(char, BUFFER_LEN);
va_list args;
va_start(args, fmt);
vsprintf(buff, fmt, args);
Writen(socket, buff, strlen(buff));
va_end(args);
free(buff);
}
void ReadFileFrom(int socket, const char* path, const char* fopen_mode){
FILE* file;
int len;
byte* buffer;
file = fopen(path, fopen_mode);
buffer = MLC(byte, BUFFER_LEN);
while( ( len = Readn(socket, buffer, BUFFER_LEN) ) > 0 )
fwrite(buffer, sizeof(byte), len, file);
fclose(file);
free(buffer);
}
void TransferFile(int socket, const char* path, uint32_t offset){
FILE* file = fopen(path, "rb");
byte* buffer = MLC(byte, BUFFER_LEN);
int len;
fseek(file, offset, SEEK_SET);
while( (len = fread(buffer, sizeof(byte), BUFFER_LEN, file)) > 0 ){
Writen(socket, buffer, len);
}
fclose(file);
free(buffer);
}
int TCPserver(const char* port, int backlog){
struct addrinfo hints, *res;
int socket;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
Getaddrinfo(NULL, port, &hints, &res);
socket = Socket(res->ai_family, res->ai_socktype, res->ai_protocol);
Bind(socket, res->ai_addr, res->ai_addrlen);
Listen(socket, backlog);
SetReuseAddr(socket);
SetReusePort(socket);
freeaddrinfo(res);
return socket;
}
int TCPclient(const char* host, const char* port){
int socket;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
Getaddrinfo(host, port, &hints, &res);
socket = Socket(res->ai_family, res->ai_socktype, res->ai_protocol);
Connect(socket, res->ai_addr, sizeof(struct sockaddr));
freeaddrinfo(res);
return socket;
}
void TCPserverUsage(const char* name){
Errx(MP_PARAM_ERR, "Usage: %s [-p port]", name);
}
void* ClientThread(void* thread_args){
tcp_client_args* args = (tcp_client_args*) thread_args;
args->func(args->socket);
Close(args->socket);
free(args);
pthread_exit(0);
}
int RunTCPserver(int argc, char** argv, const char* port_default,
TCPFunc* process, const char* pname, int facility){
// options
char* port = MLC(char, PORT_LEN);
char ch;
// connection
int server_sock, client_sock;
struct sockaddr client;
socklen_t client_len;
// threads
tcp_client_args* args;
pthread_t tid;
// init options
strcpy(port, port_default);
while ( (ch=getopt(argc, argv, "p:")) != -1 ){
if (ch == 'p') strcpy(port, optarg);
else TCPserverUsage(argv[0]);
}
if (argc - optind != 0) TCPserverUsage(argv[0]);
server_sock = TCPserver(port, BACKLOG);
free(port);
if (pname != NULL){
Daemon(1,0);
openlog(pname, LOG_PID, facility);
}
while(1){
client_sock = Accept(server_sock, &client, &client_len);
args = MLC(tcp_client_args, 1);
args->socket = client_sock;
args->func = process;
pthread_create(&tid, NULL, ClientThread, (void*) args);
}
// release resources
Close(server_sock);
return 0;
}
/*****************************************************************************
* *
* Send/Recieve *
* *
*****************************************************************************/
ssize_t Send(int socket, const void *buffer, size_t length, int flags){
int status = send(socket, buffer, length, flags);
if (status<0) Warnx("send: %s", strerror(errno));
return status;
}
ssize_t Recv(int socket, void *buffer, size_t length, int flags){
int status = recv(socket, buffer, length, flags);
if (status<0) Warnx("recv: %s", strerror(errno));
return status;
}
ssize_t Sendto(int sockfd, const void* buff, size_t nbytes, int flags, const struct sockaddr* to, socklen_t addrlen){
int status = sendto(sockfd, buff, nbytes, flags, to, addrlen);
if (status == -1) Warnx("sendto: %s", strerror(errno));
return status;
}
ssize_t Recvfrom(int sockfd, void* buff, size_t nbytes, int flags, struct sockaddr* from, socklen_t* addrlen){
int status = recvfrom(sockfd, buff, nbytes, flags, from, addrlen);
if (status == -1) Warnx("recvfrom: %s", strerror(errno));
return status;
}
ssize_t Writen(int fd, const void *vptr, size_t n){
size_t nleft = n;
ssize_t nwritten;
const char *ptr = vptr;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
ssize_t Readn(int fd, void *vptr, size_t n){
size_t nleft = n;
ssize_t nread;
char *ptr = vptr;
while (nleft > 0) {
if ( (nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0) break;
nleft -= nread;
ptr += nread;
}
return (n - nleft);
}
/*****************************************************************************
* *
* Socket options *
* *
*****************************************************************************/
void Setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen){
if (setsockopt(s, level, optname, optval, optlen) == -1)
Warnx("setsockopt %s:", strerror(errno));
}
void SetTimeout(int sfd, int seconds, int microseconds){
struct timeval waiting = {seconds, microseconds};
Setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &waiting, sizeof(waiting));
// istek => errno = EWOULDBLOCK
}
void SetReuseAddr(int sfd){
int on=1;
Setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
}
void SetReusePort(int sfd){
int on=1;
Setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
}
void SetBroadcast(int sfd){
int on = 1;
Setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
}
void SetTTL(int sfd, int ttl){
Setsockopt(sfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
}
/*****************************************************************************
* *
* ICMP *
* *
*****************************************************************************/
// icmp
u_short in_cksum(u_short* addr, int len){
int nleft = len;
int sum = 0;
u_short *w = addr;
u_short answer = 0;
/* U 32 bitni akumulator sum dodajemo 16 bitne rijeci
* Na kraju premjestimo sve carry bitove na donjih 16 bitova
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* ako je neparni broj okteta ... */
if (nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
/* dodaj carry bitove (gornjih 16) na donjih 16 bitova */
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16); /* jos jednom dodaj carry ako se pojavio*/
answer = ~sum; /* treba mi 1-komplement donjih 16 bitova */
return (answer);
}
void* GetICMPData(const void* ptr, size_t len, u_short id){
int hlen1, icmplen;
struct ip *ip;
struct icmp *icmp;
ip = (struct ip *)ptr; /* pocetak IP zaglavlja */
hlen1 = ip->ip_hl << 2; /* duzina IP zaglavlja */
icmp = (struct icmp *)(ptr + hlen1); /* pocetak ICMP zaglavlja */
if ((icmplen = len - hlen1) < 16)
Errx(MP_RUNT_ERR, "icmplen (%d) < 16", icmplen);
if (icmp->icmp_type == ICMP_ECHOREPLY) {
if (icmp->icmp_id != id)
return NULL; /* nije odgovor na nass ECHO_REQUEST */
}
return icmp->icmp_data;
}
struct icmp* FillICMP(void* data, u_short datalen, u_short id, u_short* nsent){
int len;
struct icmp *icmp;
len = 8 + datalen;
icmp = (struct icmp*) Calloc(len);
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_id = id;
icmp->icmp_seq = (*nsent)++;
memcpy(icmp->icmp_data, data, datalen);
icmp->icmp_cksum = 0;
icmp->icmp_cksum = in_cksum((u_short *) icmp, len);
return icmp;
}
#ifndef MREPRO_FH
#define MREPRO_FH
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h> /* chmod, stat */
#include <sys/uio.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <err.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h> /* network types */
#include <netinet/ip.h> /* struct ip */
#include <netinet/ip_icmp.h> /* struct icmp, icmphdr */
#include <poll.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
// ===========================================================================
int is_daemon;
typedef unsigned char byte;
typedef void Sigfunc(int);
typedef void TCPFunc(int);
#define TRY(f,s) if (f != NULL) f(s);
// MACROS
#define FOR(n) for ( i=0; i<(n); ++i )
#define MLC(t,n) ((t*) malloc(n * sizeof(t)))
#define CLC(t,n) ((t*) calloc(n * sizeof(t)))
// arithmetic
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define ABS(a) ((a) > 0 ? (a) : -(a))
#define SIGN(x) (((x) > 0) - ((x) < 0))
// bit manipulation
#define SET_BIT(mask, bit) ((mask) |= (1<<(bit)))
#define CLEAR_BIT(mask, bit) ((mask) &= ~(1<<(bit)))
#define TOGGLE_BIT(mask, bit) ((mask) ^= (1<<(bit)))
#define ISSET_BIT(mask, bit) !!((mask) & (1<<(bit)))
// errors
#define MP_PARAM_ERR 1
#define MP_ADDR_ERR 2
#define MP_SOCK_ERR 3
#define MP_COMM_ERR 4
#define MP_RUNT_ERR 5
#define BUFFER_LEN 8096
#define BUFFER_LEN_SMALL 1024
#define IP_LEN 50
#define PORT_LEN 10
#define BACKLOG 10
void Getaddrinfo(const char*, const char*, const struct addrinfo*, struct addrinfo**);
void Getnameinfo(const struct sockaddr*, socklen_t, char*, size_t, char*, size_t, int);
int Getpeername(int, struct sockaddr*, socklen_t*);
void* In_addr(const struct sockaddr*);
in_port_t In_port(const struct sockaddr*);
/*****************************************************************************
* *
* Wrappers *
* *
*****************************************************************************/
void* Malloc(size_t);
void* Calloc(size_t);
pid_t Fork();
void Daemon(int,int);
Sigfunc* signal(int, Sigfunc*);
Sigfunc* Signal(int, Sigfunc*);
void Errx(int, const char*, ...);
void Warnx(const char*, ...);
void Error(const char*);
/*****************************************************************************
* *
* Connection *
* *
*****************************************************************************/
int Socket(int, int, int);
void Bind(int, const struct sockaddr*, socklen_t);
void Close(int);
/*****************************************************************************
* *
* UDP *
* *
*****************************************************************************/
int UDPserver(const char*);
/*****************************************************************************
* *
* TCP *
* *
*****************************************************************************/
typedef struct {
int socket;
TCPFunc* func;
} tcp_client_args;
void Listen(int, int);
int Accept(int, struct sockaddr* restrict, socklen_t* restrict);
void Connect(int, const struct sockaddr*, socklen_t);
char* GetIP(const struct sockaddr*);
char* GetClientInfo(int, u_short*);
void ReadStringUntil(int, char*, int, char);
void WriteString(int, const char*, ...);
void ReadFileFrom(int, const char*, const char*);
void SendFile(int, int);
void TransferFile(int, const char*, uint32_t);
int TCPserver(const char*, int);
int TCPclient(const char*, const char*);
void TCPserverUsage(const char*);
int RunTCPserver(int, char**, const char*,
TCPFunc*, const char*, int);
/*****************************************************************************
* *
* Send/Recieve *
* *
*****************************************************************************/
ssize_t Send(int, const void*, size_t, int);
ssize_t Recv(int, void*, size_t, int);
ssize_t Sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t);
ssize_t Recvfrom(int, void*, size_t, int, struct sockaddr*, socklen_t*);
ssize_t Writen(int, const void*, size_t);
ssize_t Readn(int, void*, size_t);
/*****************************************************************************
* *
* Socket options *
* *
*****************************************************************************/
void Setsockopt(int, int, int, const void *, socklen_t);
void SetTimeout(int, int, int);
void SetReuseAddr(int);
void SetReusePort(int);
void SetBroadcast(int);
void SetTTL(int,int);
/*****************************************************************************
* *
* ICMP *
* *
*****************************************************************************/
u_short in_cksum(u_short*, int);
void* GetICMPData(const void*, size_t, u_short);
struct icmp* FillICMP(void*, u_short, u_short, u_short*);
#endif // MREPRO_FH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment