getaddrinfo connect
<!-- include (client.c lang=c) -->
# include "die.h"
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
# include <stdio.h>
# include <unistd.h>
int main() {
char *url = "www.fau.de";
char *port = "80";
struct addrinfo hints =
{
.ai_socktype = SOCK_STREAM, // Nur TCP-Sockets
.ai_family = AF_UNSPEC, // Beliebige Adressfamilie
.ai_flags = AI_ADDRCONFIG, // Nur Adresstypen für die auch ein lokales Interface existiert
}; // C: alle anderen Elemente der Struktur werden implizit genullt
struct addrinfo *head;
int res = getaddrinfo(url, port, &hints, &head);
if(res) die_m(gai_strerror(res));
// Liste der Adressen durchtesten
int sock;
struct addrinfo *curr;
for (curr = head; curr != NULL; curr = curr->ai_next) {
sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
if(sock == -1) {// Fehlerbehandlung
continue;
}
if (connect(sock, curr->ai_addr, curr->ai_addrlen) == 0) break;
close(sock);
}
freeaddrinfo(head);
if (curr == NULL) die_m("Could not connect to server");
FILE *rx, *tx;
if( (rx = fdopen(sock, "r")) == NULL) die("fdopen");
int sock_copy = dup(sock);
if(sock_copy < 0) die("dup");
if( (tx = fdopen(sock_copy, "w")) == NULL ) die("fdopen");
//test it
fprintf(tx, "GET http://www.fau.de/index.html HTTP/1.1\r\n\r\n");
fflush(tx);
char *lineptr = NULL;
size_t lineSize = 0;
ssize_t strLen = 0;
strLen = getline(&lineptr, &lineSize, rx);
if(strLen < 0) {
if(ferror(rx)) die("getline");
}
printf("%s\n", lineptr);
free(lineptr);
if(fclose(rx)) perror("fclose");
if(fclose(tx)) perror("fclose");
}
<!-- /include -->
listen accept
<!-- include (accept.c lang=c) -->
# include "die.h"
# include <netdb.h>
# include <sys/socket.h>
# include <unistd.h>
# include <signal.h>
# include <stdio.h>
# include <stdlib.h>
static void handleConnection(int clientSock, int listenSock);
static void handleRequest(FILE *rx, FILE *tx);
// Initialisiert den Server und nimmt Anfragen an
static void initServer(short unsigned int port) {
//ignore SIGPIPE
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if( sigaction(SIGPIPE, &sa, NULL) != 0 ) die("Could not set sigaction");
//init accept
int listenSock = socket(AF_INET6, SOCK_STREAM, 0);
if ( listenSock == -1 ) die("Fehler beim Aufbau des Servers");
struct sockaddr_in6 addr = {
.sin6_family = AF_INET6,
.sin6_port = htons(port),
.sin6_addr = in6addr_any,
};
if ( bind(listenSock, (struct sockaddr *) &addr, sizeof(addr)) != 0 ) die("Fehler beim Aufbau des Servers");
if ( listen(listenSock, SOMAXCONN) != 0 ) die("Fehler beim Aufbau des Servers");
while ( 1 ) {
int clientSock = accept(listenSock, NULL, NULL);
if ( clientSock == -1 ) { perror("Warnung: Client konnte nicht akzeptiert werden."); continue; }
handleConnection(clientSock, listenSock);
}
}
static void handleConnection(int clientSock, int listenSock) {
//if pthread just bbput
//fork()
pid_t pid;
if( (pid = fork()) == -1 ) die("fork");
if(pid != 0) {//parent process
close(clientSock);//only in parent process
return;
}
if( close(listenSock) ) perror("close listenSock");
//open file streams
FILE *rx, *tx;
int clientSock_Copy = dup(clientSock);
if(clientSock_Copy < 0) die("dup");
if( (rx = fdopen(clientSock, "r")) == NULL) die("fdopen");
if( (tx = fdopen(clientSock_Copy, "w")) == NULL) die("fdopen");
//handleRequest()
handleRequest(rx, tx);
//close connection
if( fclose(tx) ) die("fclose tx");
if( fclose(rx) ) die("fclose rx");
//exit
exit(EXIT_SUCCESS);//child exits
}
static void handleRequest(FILE *rx, FILE *tx) {
rx = (FILE *) rx;
fprintf(tx, "hi\n");
}
int main() {
initServer(2020);
}
<!-- /include -->
-> fork siehe server
<!-- include (exec.c lang=c) -->
# include "die.h"
# include <unistd.h>
int main() {
//fork
//v gets array of args / l gets strings
//p searches path
//execlp
execl("./threadpool", "./threadpool", "arg1");
die("execl failed");
//alternativ
char *argv[3];
argv[0] = "perl";
argv[1] = "test.pl";
argv[2] = (char*)0;
execvp("perl", argv);
die("execvp failed");
}
<!-- /include -->
<!-- include (signal.c lang=c) -->
# include "die.h"
# include <signal.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <unistd.h>
static void sigchldHandler(int sig);
static int pcount = 0;
int main() {
struct sigaction handleSIGCHLD =
{
.sa_handler = sigchldHandler,
.sa_flags = SA_RESTART,
};
if( sigaction(SIGCHLD, &handleSIGCHLD, NULL) != 0 ) die("Could not set sigaction");
//mask sigchld
sigset_t newMask;
sigset_t oldMask;
sigemptyset(&newMask);
sigaddset(&newMask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &newMask, &oldMask) == -1) die("sigprocmask");
//do critical stuff
pid_t pid = fork();
if(pid < 0) die("fork");
if(pid == 0) {
sleep(5);
exit(EXIT_SUCCESS);
}
pcount++;
//alte signal mask wiederherstellen
if (sigprocmask(SIG_SETMASK, &oldMask, NULL) == -1) die("sigprocmask");
//passives warten
if (sigprocmask(SIG_BLOCK, &newMask, &oldMask) == -1) die("sigprocmask");
while (pcount > 0) {
sigsuspend(&oldMask);
}
}
static void sigchldHandler(int sig) {
// Collect zombie processes
(void)sig; //unused param
pid_t pid;
int event;
while ((pid = waitpid(-1, &event, WNOHANG)) > 0) {
// collect all zombies (prevent zombies if signal got lost because of masking)
pcount--;
}
}
<!-- /include -->
<!-- include (threadpool.c lang=c) -->
# include "die.h"
# include <errno.h>
# include <pthread.h>
# include "jbuffer.h"
# define POISON 123456
# define BUFSIZE 32
# define THREADS 8
static BNDBUF *jbuf;
static void *workerMain(void *param){
for(int val = bbGet(jbuf); val != POISON; val = bbGet(jbuf)) {
//handle val
printf("%d\n", val);
}
return param;
}
int main() {
// init jbuf
jbuf = bbCreate(BUFSIZE);
if (jbuf == NULL) die_m("failed to create jbuffer");
// create threads
pthread_t tids[THREADS];
for (int i = 0; i < THREADS; i++) {
//pthread_t thread;
if ( (errno = pthread_create(&tids[i], NULL, workerMain, NULL)) != 0 ) die("pthread_create");
//if ( (errno = pthread_detach(thread)) != 0 ) die("pthread_detach");
}
//put work (z.B. clientSock) in the queue
bbPut(jbuf, 123);
//kill them all
for (int i = 0; i < THREADS; i++) {
bbPut(jbuf, POISON);
}
for (int i = 0; i < THREADS; i++) {
errno = pthread_join(tids[i], NULL);//void **retval
if (errno != 0) perror("pthread_join()");
}
}
<!-- /include -->
<!-- include (jbuffer.c lang=c) -->
# include <stdatomic.h>
# include "jbuffer.h"
# include "sem.h"
struct BNDBUF
{
int *buff;
int size;
int insertpos; // next insert pos
SEM *freeSpaceSem; // count of free slots
int extractpos; // next extract pos
SEM *usedSpaceSem; // count of used slots
};
BNDBUF *bbCreate(size_t size) {
if(size > __INT_MAX__) return NULL;//to big
BNDBUF *bb = calloc(1, sizeof(BNDBUF));//initialize everithing with NULL
if(bb == NULL) return NULL;//malloc failed
bb->buff = malloc(size * sizeof(int));
if(bb->buff == NULL) {//malloc failed
bbDestroy(bb);
return NULL;
}
bb->size = (int) size;
//init SEMs
bb->freeSpaceSem = semCreate((int) size);
if(bb->freeSpaceSem == NULL) {//semCreate failed
bbDestroy(bb);
return NULL;
}
bb->usedSpaceSem = semCreate(0);
if(bb->usedSpaceSem == NULL) {//semCreate failed
bbDestroy(bb);
return NULL;
}
bb->insertpos = 0;
bb->extractpos = 0;
return bb;
}
void bbDestroy(BNDBUF *bb) {
if(bb == NULL) return;
free(bb->buff);//each does nothing if NULL
semDestroy(bb->freeSpaceSem);
semDestroy(bb->usedSpaceSem);
free(bb);
}
void bbPut(BNDBUF *bb, int value) {
P(bb->freeSpaceSem);
bb->buff[bb->insertpos] = value;
bb->insertpos++;
if(bb->insertpos >= bb->size) bb->insertpos = 0;
V(bb->usedSpaceSem);
}
int bbGet(BNDBUF *bb) {
int value, extractpos, newExtractpos;
P(bb->usedSpaceSem);
do{
extractpos = bb->extractpos;
value = bb->buff[extractpos];
newExtractpos = extractpos + 1;
if(newExtractpos >= bb->size) newExtractpos = 0;
} while(! atomic_compare_exchange_strong(&(bb->extractpos), &extractpos, newExtractpos));
V(bb->freeSpaceSem);
return value;
}
<!-- /include -->
<!-- include (fopen.c lang=c) -->
# include "die.h"
# include <stdio.h>
int main() {
FILE* file = fopen("../fopen.c", "w");
if ( file == NULL ) die("fopen");
//do stuff
if (fclose(file)) perror("failed to save file");//errorhandling optional
}
<!-- /include -->
<!-- include (listFiles.c lang=c) -->
# include "die.h"
# include <dirent.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/stat.h>
# include <string.h>
# define BASEDIR "."
static int filter(const struct dirent *dir) {
if(dir->d_name[0] == '.') {
return 0;//filter out .files
}
struct stat st;
char name[strlen(BASEDIR) + strlen(dir->d_name) + 2];
sprintf(name, "%s/%s", BASEDIR, dir->d_name);
if(stat(name, &st) == -1) die("stat");//lstat don't folow symlinks
if(S_ISREG(st.st_mode)) {
return 1;
}
return 0;
}
/** list files
*/
static void listDir(){
struct dirent **namelist; //array of dirents
int n = scandir(BASEDIR, &namelist, filter, alphasort);//filter oder NULL
if (n == -1) {
die("scandir");
}
while (n--) {
printf("%s/%s\n", BASEDIR, namelist[n]->d_name);
free(namelist[n]);
}
free(namelist);
}
int main() {
listDir();
}
<!-- /include -->
printf formats
<!-- include (getline.c lang=c) -->
# include "die.h"
# include <stdio.h>
static void mygetline() {
char *lineptr = NULL;
size_t lineSize = 0;
ssize_t strLen = 0;
strLen = getline(&lineptr, &lineSize, stdin);
if(strLen < 0) {//eof
if (ferror(stdin)) die("getline");
}
free(lineptr);
}
int main() {
mygetline();
}
<!-- /include -->
fgets -> sscanf
strncmp
//TODO
<!-- include (sem.c lang=c) -->
# include <errno.h>
# include <pthread.h>
# include <stdlib.h>
# include "sem.h"
struct SEM
{
pthread_mutex_t m;
pthread_cond_t c;
int value;
};
SEM *semCreate(int initVal) {
SEM *sem = malloc(sizeof(SEM));
if(sem == NULL) return NULL;// malloc failed
int err=0;
err = pthread_mutex_init(&sem->m, NULL);
if(err) {
free(sem);
errno = err;
return NULL;
}
err = pthread_cond_init(&sem->c, NULL);
if (err) {
pthread_mutex_destroy(&sem->m);
free(sem);
errno = err;
return NULL;
}
sem->value = initVal;
return sem;
}
void semDestroy(SEM *sem) {
if(sem == NULL) return;
pthread_cond_destroy(&sem->c);//ignore returned errors
pthread_mutex_destroy(&sem->m);//ignore returned errors
free(sem);
}
void P(SEM *sem) {//fast mutex has only EINVAL error
pthread_mutex_lock(&sem->m);
while(sem->value <= 0) {
pthread_cond_wait(&sem->c, &sem->m);
}
sem->value--;
pthread_mutex_unlock(&sem->m);
}
void V(SEM *sem) {//fast mutex has only EINVAL error
pthread_mutex_lock(&sem->m);
sem->value++;
pthread_cond_signal(&sem->c);
pthread_mutex_unlock(&sem->m);
}
<!-- /include -->
<!-- include (strtoulSave.c lang=c) -->
# include <errno.h>
# include <stdlib.h>
/**
* @brief strtoul with error checks
*
* @param str String to be parsed
* @param num return param where the unsigned long gets written to (gets only changed on success)
* @return 0 on success, none zero on error
*/
static int strtoulSave(const char *str, unsigned long *num) {
char *endptr;
int eno = errno;
errno = 0;
unsigned long value = strtoul(str, &endptr, 10);
if(errno) return errno;
errno = eno; // restore errno, so we're not unintentionally loosing errors when calling this function
if (endptr == str) return EINVAL; // no digits found
if(*endptr != '\0') return EINVAL; // contains invalid character
*num = value;
return 0;
}
int main(){
unsigned long num;
strtoulSave("123", &num);
}
<!-- /include -->