mirror of
https://github.com/libretro/cpp-cheat.git
synced 2025-04-13 00:30:27 +00:00
Move posix C API form linux repo.
This commit is contained in:
parent
10b9c2e9d3
commit
99ad8ab9ae
@ -18,11 +18,11 @@ Requirement of freeglut.
|
||||
|
||||
GLUT is a higher level interface built on top of GL, and adds things like:
|
||||
|
||||
- mouse/keyboard input.
|
||||
- mouse/keyboard input.
|
||||
|
||||
This requires callback functions to be called from an event loop.
|
||||
|
||||
- higher level geometric objects like spheres, cubes and teapots.
|
||||
- higher level geometric objects like spheres, cubes and teapots.
|
||||
|
||||
The original GLUT implementation is proprietary, but open source implementations exist such as Freeglut.
|
||||
|
||||
|
1
posix/Makefile
Symbolic link
1
posix/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../Makefile_many
|
1
posix/Makefile_params
Normal file
1
posix/Makefile_params
Normal file
@ -0,0 +1 @@
|
||||
LIBS := -lm -pthread
|
1
posix/README.md
Normal file
1
posix/README.md
Normal file
@ -0,0 +1 @@
|
||||
POSIX C API.
|
3197
posix/main.c
Normal file
3197
posix/main.c
Normal file
File diff suppressed because it is too large
Load Diff
237
posix/signal.c
Normal file
237
posix/signal.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
In short:
|
||||
|
||||
- signals are a simple way for processes to communicate
|
||||
- signals are limited to passing a single byte between two processes
|
||||
|
||||
To send arbitrary signals to a process from a terminal, consider using the `kill` utility
|
||||
(it does more than killing via a SIGTERM, as in general it sends any signal to a process)
|
||||
|
||||
Also consider the convenient non POSIX stadardized VT100 control characters such as `<C-C>`
|
||||
which generate certain signals such as `SIGTERM`.
|
||||
|
||||
#ANSI
|
||||
|
||||
ANSI C supports the concept of signals, and only POSIX specific features shall be discussed here.
|
||||
|
||||
Please look for ANSI C info for any feature used but not explained here.
|
||||
|
||||
Linux extends POSIX by adding new signals, Those shall not be discussed here.
|
||||
|
||||
#POSIX
|
||||
|
||||
Docs here: <http://pubs.opengroup.org/onlinepubs/009696699/basedefs/signal.h.html>.
|
||||
|
||||
POSIX defines several signals in addition to the ANSI C signals.
|
||||
|
||||
As in ANSI C, each signal has the following attributes:
|
||||
|
||||
- general description of which conditions generate the signal
|
||||
|
||||
- the signal can or cannot be handled.
|
||||
|
||||
Most signals can be handled, but there are a few exceptions such as:
|
||||
|
||||
- `SIGKILL`: always kill processes, cannot be handled.
|
||||
- `SIGKSTOP` and `SIGCONT`
|
||||
|
||||
- default action to take
|
||||
|
||||
For signals that can be handled, you can change those behavious by creating your own handlers.
|
||||
|
||||
The possible default behaviours are:
|
||||
|
||||
- T:
|
||||
|
||||
Abnormal termination of the process.
|
||||
|
||||
The process is terminated with all the consequences of `_exit()` except that the status made available to
|
||||
`wait()` and `waitpid()` indicates abnormal termination by the specified signal.
|
||||
|
||||
Default action for most signals.
|
||||
|
||||
- A :Abnormal termination of the process.
|
||||
|
||||
[XSI] [Option Start] Additionally, implementation-defined abnormal termination actions,
|
||||
such as creation of a core file, may occur. [Option End]
|
||||
|
||||
Linux implements concept of core dumps on those cases.
|
||||
Note however that those may be turned on or off depending on the system configuration.
|
||||
|
||||
- I: Ignore the signal.
|
||||
|
||||
An important example is `SIGCHLD`, which is generated when a child terminates,
|
||||
but has no effect by default, since in general killing the parent is not what
|
||||
should happen on most programs.
|
||||
|
||||
- S: Stop the process.
|
||||
|
||||
Mainly `SIGSTOP`.
|
||||
|
||||
- C: Continue the process, if it is stopped; otherwise, ignore the signal.
|
||||
|
||||
Mainly `SIGCONT`.
|
||||
|
||||
POSIX specific signals include:
|
||||
|
||||
- SIGKILL
|
||||
|
||||
Kills program.
|
||||
|
||||
Cannot be handled unlike to `SIGINT` and `SIGTERM`.
|
||||
|
||||
- SIGQUIT
|
||||
|
||||
Quit program.
|
||||
|
||||
Used in case of abnormal termination (`A`), unlike `SIGINT` and `SIGTERM`.
|
||||
|
||||
May therefore generate a core dump on certain systems.
|
||||
|
||||
On Linux, you must first enable core dumps on the current terminal via `ulimit -c unlimited`,
|
||||
since coredumps may be turned off by default.
|
||||
|
||||
Can be generated on VT100 with `<C-\>`.
|
||||
|
||||
- SIGSTOP
|
||||
|
||||
Freezes program.
|
||||
|
||||
`ctrl+z`, in linux terminals.
|
||||
|
||||
Cannot be handle.
|
||||
|
||||
- SIGCONT
|
||||
|
||||
Continues a process that
|
||||
|
||||
- SIGHUP
|
||||
|
||||
Controlling terminal was killed.
|
||||
|
||||
This is why killing the terminal kills most process by default unless those process implement a handler.
|
||||
|
||||
- SIGPIPE
|
||||
|
||||
Process write to a pipe with no readers on other side
|
||||
|
||||
- SIGCHLD
|
||||
|
||||
Child terminated, stopped or continued.
|
||||
|
||||
Ignored by default.
|
||||
|
||||
- SIGALRM
|
||||
|
||||
Received after the alarm call after given no of secs.
|
||||
|
||||
- SIGUSR1 and SIGUSR2: left to users to do whatever they want with
|
||||
|
||||
#parent death signal
|
||||
|
||||
In POSIX, no signal needs to be sent to the child if the parent exits:
|
||||
<http://stackoverflow.com/questions/284325/how-to-make-child-process-die-after-parent-exits>
|
||||
In Linux, this can be achieved via the `prctl` syscall.
|
||||
This may seem surprising considering that:
|
||||
|
||||
- parents can wait for children
|
||||
|
||||
- children get a NOHUP when controling process is killed
|
||||
This is mentioned at: <http://pubs.opengroup.org/onlinepubs/009695399/functions/exit.html>
|
||||
|
||||
TODO what is a controlling process?
|
||||
|
||||
#sources
|
||||
|
||||
- <http://www.alexonlinux.com/signal-handling-in-linux>
|
||||
|
||||
good intro
|
||||
|
||||
- man 7 signal
|
||||
|
||||
man pages
|
||||
|
||||
# TODO
|
||||
|
||||
- determine where specification barriers betwwen ANSIC / POSIX / linux
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
void signal_handler( int sig )
|
||||
{
|
||||
//sig arg allows us to use a single function for several different signals:
|
||||
//just look at it and decide which action to take based on the signal number
|
||||
|
||||
printf( "sig: %d\n", sig );
|
||||
|
||||
//after the signal is dealt with, the handler is then changed to its default action
|
||||
//if you want to continue using this handler for future signals, you have to reregister
|
||||
//it here: TODO confirm. If I remove this it does not work.
|
||||
|
||||
signal( sig, signal_handler );
|
||||
|
||||
//you can change the action handler at any time
|
||||
//for example, if you uncomment this line, only the first signal will be ignored
|
||||
//and but the second will be dealt with the default action:
|
||||
|
||||
//(void) signal( sig, SIG_DFL );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
/*
|
||||
#signal
|
||||
|
||||
POSIX recommends `sigaction` instead of `signal`
|
||||
*/
|
||||
|
||||
signal( SIGALRM, signal_handler );
|
||||
|
||||
/*
|
||||
#send signal
|
||||
|
||||
this is done via the kill function:
|
||||
|
||||
int kill(pid_t pid, int sig);
|
||||
|
||||
returns 0 on success
|
||||
|
||||
you must have permissions to send a signal to a program
|
||||
|
||||
TODO 0 which? same uid?
|
||||
*/
|
||||
|
||||
//send a SIGINT to ourselves:
|
||||
assert( kill( getpid(), SIGALRM ) == 0 );
|
||||
|
||||
int i = 0;
|
||||
while ( i < 3 )
|
||||
{
|
||||
/*
|
||||
#alarm
|
||||
|
||||
sends a SIGALRM to ourselves in n seconds
|
||||
*/
|
||||
assert( alarm( 1 ) == 0 );
|
||||
printf( "%d\n", i );
|
||||
i++;
|
||||
sleep( 2 );
|
||||
}
|
||||
|
||||
/*
|
||||
#pause
|
||||
|
||||
Stop program until it receives a signal.
|
||||
*/
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
1
posix/socket/Makefile
Symbolic link
1
posix/socket/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../../Makefile_many
|
92
posix/socket/README.md
Normal file
92
posix/socket/README.md
Normal file
@ -0,0 +1,92 @@
|
||||
Sockets are similar to pipes but:
|
||||
|
||||
- allow communication across different systems and are thus a base for networks local sockets also exist.
|
||||
|
||||
- allow bidirection communication
|
||||
|
||||
- allow multiple clients to connet to a single server (the concepts of client and server are clearly defined)
|
||||
|
||||
#What posix sockets can do
|
||||
|
||||
POSIX sockets allows to implement any Application layer program, and thus to implement things like web browsers, crawlers or wget like utilities.
|
||||
|
||||
It seems however that POSIX does not support lower level layer control, for exapmle making an ICMP echo <http://www.microhowto.info/howto/send_an_arbitrary_ipv4_datagram_using_a_raw_socket_in_c.html>
|
||||
|
||||
For those functionalities it seems that Linux specific functionalities must be used for example raw sockets: <http://www.pdbuchan.com/rawsock/rawsock.html>
|
||||
|
||||
#Socket params
|
||||
|
||||
sockets are characterized by three parameters:
|
||||
|
||||
- domain
|
||||
- type
|
||||
- protocol
|
||||
|
||||
this are exactly the 3 parameters that the `socket` call receives.
|
||||
|
||||
##Domain
|
||||
|
||||
- `AF_UNIX`: local sockets for single machine usage
|
||||
|
||||
UNIX domain sockets are uniquelly identified on the filesystem like pipes or other special files
|
||||
|
||||
- `AF_INET`: internet IP protocol, regular local networks or the internet
|
||||
|
||||
this is one of the few stream like resources that are not put into the filesystem because TODO
|
||||
|
||||
- `AF_INET6`: IPv6
|
||||
|
||||
##Type
|
||||
|
||||
- `SOCK_STREAM`: connexion works like a file stream to the program
|
||||
|
||||
in `AF_INET` this is automatically done via TCP/IP
|
||||
|
||||
delivery and ordering is guaranteed by TCP/IP
|
||||
|
||||
a connection is maintained while data is being sent
|
||||
|
||||
- `SOCK_DGRAM`: datagram
|
||||
|
||||
lower level protocol
|
||||
|
||||
does not establish connection
|
||||
|
||||
no automatic delivery guarantee
|
||||
|
||||
data must be manually split into packages of a maximum width
|
||||
|
||||
in `AF_INET` this is UDP
|
||||
|
||||
certain domains may have differnt types
|
||||
|
||||
`AF_UNIX` has a single type: `SOCK_STREAM`
|
||||
|
||||
`AF_INET` has the following types:
|
||||
|
||||
##Protocol
|
||||
|
||||
sometimes it is possible to choose different protocols for a given type
|
||||
|
||||
`0` uses the default protocol
|
||||
|
||||
#Testing
|
||||
|
||||
- run the server:
|
||||
|
||||
./server &
|
||||
|
||||
- run as many clients as you want:
|
||||
|
||||
./client && ./client
|
||||
./client
|
||||
|
||||
- kill the server:
|
||||
|
||||
fg
|
||||
|
||||
and then hit Ctrl-C
|
||||
|
||||
#Local socket
|
||||
|
||||
Is inserted into the filesystem.
|
34
posix/socket/inet/Makefile
Normal file
34
posix/socket/inet/Makefile
Normal file
@ -0,0 +1,34 @@
|
||||
# make all files with one of the given extensions by IN_EXTS
|
||||
# separatelly, possibly using a different rule per extension
|
||||
|
||||
IN_DIR ?= ./
|
||||
IN_EXTS ?= .c
|
||||
OUT_DIR ?= _out/
|
||||
OUT_EXT ?=
|
||||
RUN ?= main
|
||||
|
||||
INS := $(foreach IN_EXT, $(IN_EXTS), $(wildcard $(IN_DIR)*$(IN_EXT)) )
|
||||
INS_NODIR := $(notdir $(INS))
|
||||
OUTS_NODIR := $(basename $(INS_NODIR))
|
||||
OUTS_NODIR := $(addsuffix $(OUT_EXT), $(OUTS_NODIR))
|
||||
OUTS := $(addprefix $(OUT_DIR), $(OUTS_NODIR))
|
||||
|
||||
.PHONY: all clean mkdir run
|
||||
|
||||
all: mkdir $(OUTS)
|
||||
|
||||
# rule to make the c files
|
||||
$(OUT_DIR)%$(OUT_EXT): %.c
|
||||
gcc -Wall -std=c99 -pedantic-errors -o "$@" "$<"
|
||||
|
||||
clean:
|
||||
rm -rf $(OUT_DIR)
|
||||
|
||||
mkdir:
|
||||
mkdir -p $(OUT_DIR)
|
||||
|
||||
run: all
|
||||
cd $(OUT_DIR) && ./server$(OUT_EXT) &
|
||||
cd $(OUT_DIR) && ./client$(OUT_EXT) &
|
||||
cd $(OUT_DIR) && ./client$(OUT_EXT) &
|
||||
cd $(OUT_DIR) && ./client$(OUT_EXT) &
|
6
posix/socket/inet/README.md
Normal file
6
posix/socket/inet/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
inet sockets, can be used across different computers for networking
|
||||
|
||||
will only comment on differences from the unix sockets
|
||||
|
||||
once a connection has been made to a port, the port stays blocked,
|
||||
so be sure to take a port that is not being used
|
106
posix/socket/inet/client.c
Normal file
106
posix/socket/inet/client.c
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
@file
|
||||
|
||||
Inet server example
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include "assert.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h> //getprotobyname
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include "unistd.h"
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
char server_ip[] = "127.0.0.1";
|
||||
unsigned short server_port = 12345;
|
||||
in_addr_t server_addr;
|
||||
int sockfd;
|
||||
//this is the struct used by INet addresses:
|
||||
struct sockaddr_in address;
|
||||
char ch_init = 'a';
|
||||
char ch = ch_init;
|
||||
struct protoent *protoent;
|
||||
char protoname[] = "tcp";
|
||||
//char protoname[] = "udp";
|
||||
|
||||
protoent = getprotobyname( protoname );
|
||||
if ( protoent == NULL ) {
|
||||
perror( "getprotobyname" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sockfd = socket( AF_INET, SOCK_STREAM, protoent->p_proto );
|
||||
if ( sockfd == -1 ) {
|
||||
perror( "socket" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
#inet_addr
|
||||
|
||||
converts the text representation to a representation that can be used on the network
|
||||
|
||||
#s_addr
|
||||
|
||||
server address
|
||||
*/
|
||||
server_addr = inet_addr( server_ip );
|
||||
if ( server_addr == (in_addr_t)-1 ) {
|
||||
fprintf( stderr, "inet_addr(\"%s\") failed\n", server_ip );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
address.sin_addr.s_addr = server_addr;
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
|
||||
/*
|
||||
#htons
|
||||
|
||||
Host TO Network Short
|
||||
|
||||
takes a short (2 bytes), and converts it to the correct byte ordering expected by the network
|
||||
|
||||
you must do this, or else the network won't look at the right port
|
||||
|
||||
versions:
|
||||
|
||||
- htons
|
||||
- htonl (long, 4 bytes)
|
||||
- ntohs (inverse)
|
||||
- ntohl
|
||||
|
||||
#sin_port
|
||||
|
||||
port at which to contact server
|
||||
*/
|
||||
|
||||
address.sin_port = htons( server_port );
|
||||
|
||||
if ( connect( sockfd, ( struct sockaddr* )&address, sizeof( address ) ) == -1 ) {
|
||||
perror( "connect" );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if ( write( sockfd, &ch, 1 ) == -1 ) {
|
||||
perror( "write" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* according to wireshark, the response is received from some random port that the OS assigns to us */
|
||||
|
||||
if ( read( sockfd, &ch, 1 ) == -1 ) {
|
||||
perror( "read" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close( sockfd );
|
||||
assert( ch == ch_init + 1 );
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
81
posix/socket/inet/server.c
Normal file
81
posix/socket/inet/server.c
Normal file
@ -0,0 +1,81 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h> //getprotobyname
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include "unistd.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
unsigned short server_port = 12345;
|
||||
char ch;
|
||||
size_t client_len;
|
||||
int server_sockfd, client_sockfd;
|
||||
struct sockaddr_in client_address, server_address;
|
||||
struct protoent *protoent;
|
||||
char protoname[] = "tcp";
|
||||
//char protoname[] = "udp";
|
||||
|
||||
protoent = getprotobyname(protoname);
|
||||
if (protoent == NULL) {
|
||||
perror("getprotobyname");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server_sockfd = socket(
|
||||
AF_INET,
|
||||
SOCK_STREAM,
|
||||
protoent->p_proto
|
||||
//0
|
||||
);
|
||||
if (server_sockfd == -1) {
|
||||
perror("socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
#s_addr server
|
||||
|
||||
on server, this is which addresses it will accept connections from
|
||||
|
||||
#INADDR_ANY
|
||||
|
||||
special value that tells server to accept connections from anyone
|
||||
*/
|
||||
server_address.sin_family = AF_INET;
|
||||
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
server_address.sin_port = htons(server_port);
|
||||
if (bind(
|
||||
server_sockfd,
|
||||
(struct sockaddr*)&server_address,
|
||||
sizeof(server_address)
|
||||
) == -1
|
||||
) {
|
||||
perror("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (listen(server_sockfd, 5) == -1) {
|
||||
perror("listen");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
client_len = sizeof(client_address);
|
||||
client_sockfd = accept(
|
||||
server_sockfd,
|
||||
(struct sockaddr*)&client_address,
|
||||
&client_len
|
||||
);
|
||||
read(client_sockfd, &ch, 1);
|
||||
ch++;
|
||||
write(client_sockfd, &ch, 1);
|
||||
close(client_sockfd);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
34
posix/socket/unix/Makefile
Normal file
34
posix/socket/unix/Makefile
Normal file
@ -0,0 +1,34 @@
|
||||
# make all files with one of the given extensions by IN_EXTS
|
||||
# separatelly, possibly using a different rule per extension
|
||||
|
||||
IN_DIR ?= ./
|
||||
IN_EXTS ?= .c
|
||||
OUT_DIR ?= _out/
|
||||
OUT_EXT ?=
|
||||
RUN ?= main
|
||||
|
||||
INS := $(foreach IN_EXT, $(IN_EXTS), $(wildcard $(IN_DIR)*$(IN_EXT)) )
|
||||
INS_NODIR := $(notdir $(INS))
|
||||
OUTS_NODIR := $(basename $(INS_NODIR))
|
||||
OUTS_NODIR := $(addsuffix $(OUT_EXT), $(OUTS_NODIR))
|
||||
OUTS := $(addprefix $(OUT_DIR), $(OUTS_NODIR))
|
||||
|
||||
.PHONY: all clean mkdir run
|
||||
|
||||
all: mkdir $(OUTS)
|
||||
|
||||
# rule to make the c files
|
||||
$(OUT_DIR)%$(OUT_EXT): %.c
|
||||
gcc -Wall -std=c99 -pedantic-errors -o "$@" "$<"
|
||||
|
||||
clean:
|
||||
rm -rf $(OUT_DIR)
|
||||
|
||||
mkdir:
|
||||
mkdir -p $(OUT_DIR)
|
||||
|
||||
run: all
|
||||
cd $(OUT_DIR) && ./server$(OUT_EXT) &
|
||||
cd $(OUT_DIR) && ./client$(OUT_EXT) &
|
||||
cd $(OUT_DIR) && ./client$(OUT_EXT) &
|
||||
cd $(OUT_DIR) && ./client$(OUT_EXT) &
|
1
posix/socket/unix/README.md
Normal file
1
posix/socket/unix/README.md
Normal file
@ -0,0 +1 @@
|
||||
unix sockets, meant to be used locally on a single computer
|
95
posix/socket/unix/client.c
Normal file
95
posix/socket/unix/client.c
Normal file
@ -0,0 +1,95 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include "assert.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h> //sockaddr_un
|
||||
#include "unistd.h"
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
//name of the socket file
|
||||
//server and client must agree on it
|
||||
char name[] = "server_socket";
|
||||
|
||||
//sockets are accessible via file descriptors
|
||||
int sockfd;
|
||||
int len;
|
||||
|
||||
//this is the struct used by UNix addresses
|
||||
struct sockaddr_un address;
|
||||
char ch_init = 'a';
|
||||
char ch = ch_init;
|
||||
|
||||
/*
|
||||
#socket
|
||||
|
||||
Create the socket, and get a file descrpitor to it.
|
||||
|
||||
This must be done by both clients and servers.
|
||||
|
||||
int socket(int domain, int type, int protocol);
|
||||
|
||||
- protocol:
|
||||
|
||||
For a given domain, select which protocol id to use.
|
||||
|
||||
`0` uses a default protocol for the domain.
|
||||
|
||||
Many domains have a single protocol.
|
||||
|
||||
Other do not, for example `AF_INET` has both `tcp` adn `udp`.
|
||||
|
||||
To get a protocol id, use `struct protoent *protoent = getprotobyname('tcp')`,
|
||||
and then extract `protoent->p_proto`.
|
||||
*/
|
||||
|
||||
sockfd = socket( AF_UNIX, SOCK_STREAM, 0 );
|
||||
if ( sockfd == -1 ) {
|
||||
perror( "socket" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
#connect
|
||||
|
||||
request connection to the socket on the given address
|
||||
|
||||
if the socket file does not exist fails
|
||||
*/
|
||||
|
||||
//type of socket
|
||||
address.sun_family = AF_UNIX;
|
||||
|
||||
//give a name to the socket
|
||||
strcpy( address.sun_path, name );
|
||||
|
||||
len = sizeof( address );
|
||||
|
||||
if ( connect( sockfd, ( struct sockaddr* )&address, len ) == -1 ) {
|
||||
perror( "connect" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
if ( write( sockfd, &ch, 1 ) == -1 ) {
|
||||
perror( "write" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ( read( sockfd, &ch, 1 ) == -1 ) {
|
||||
perror( "read" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//you should close the connection on both client and server
|
||||
|
||||
close( sockfd );
|
||||
|
||||
//assert that the server did its job of increasing the char we gave it
|
||||
assert( ch == ch_init + 1 );
|
||||
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
170
posix/socket/unix/server.c
Normal file
170
posix/socket/unix/server.c
Normal file
@ -0,0 +1,170 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include "assert.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h> //sockaddr_un
|
||||
#include "unistd.h"
|
||||
|
||||
/**
|
||||
Simple server that takes one char per connection,
|
||||
increases it, and returns it to the client.
|
||||
*/
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
//name of the socket file
|
||||
//server and client must agree on it
|
||||
char ch;
|
||||
char name[] = "server_socket";
|
||||
size_t client_len;
|
||||
int server_sockfd, client_sockfd;
|
||||
struct sockaddr_un client_address, server_address;
|
||||
|
||||
//remove any existing socket file and create a new one
|
||||
if ( unlink( name ) == -1 && errno != ENOENT ) {
|
||||
perror( "unlink" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
#setsockopt
|
||||
|
||||
Set several socket options
|
||||
|
||||
int setsockopt(int sockfd, int level, int optname,
|
||||
const void *optval, socklen_t optlen)
|
||||
|
||||
TODO it seems that setting SO_REUSEADDR allows to immediately reuse this socket.
|
||||
Otherwise, bind fails because the address is already used.
|
||||
|
||||
Discussion on the python interface: <http://www.gossamer-threads.com/lists/python/bugs/714277>
|
||||
*/
|
||||
|
||||
/*
|
||||
if ( setsockopt(
|
||||
int sockfd,
|
||||
int level,
|
||||
int optname,
|
||||
const void *optval,
|
||||
socklen_t optlen
|
||||
) == -1 )
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
server_sockfd = socket( AF_UNIX, SOCK_STREAM, 0 );
|
||||
if ( server_sockfd == -1 ) {
|
||||
perror( "socket" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
#bind
|
||||
|
||||
Bind an address to the socket file.
|
||||
|
||||
May take different address formats depending on the socket parameters.
|
||||
|
||||
#AF_INET
|
||||
|
||||
In the AF_INET domain, the address is specified using a structure called sockaddr_in, defined in
|
||||
netinet/in.h, which contains at least these members:
|
||||
|
||||
struct sockaddr_in {
|
||||
short int; //AF_INET
|
||||
unsigned short int; //port number
|
||||
struct in_addr; //IP address
|
||||
};
|
||||
|
||||
The IP address structure, in_addr, is defined as follows:
|
||||
|
||||
struct in_addr {
|
||||
unsigned long int
|
||||
};
|
||||
|
||||
The four bytes of an IP address constitute a single 32-bit value
|
||||
*/
|
||||
server_address.sun_family = AF_UNIX;
|
||||
strcpy( server_address.sun_path, name );
|
||||
if ( bind(
|
||||
server_sockfd,
|
||||
(struct sockaddr*)&server_address,
|
||||
sizeof( server_address )
|
||||
) == -1 )
|
||||
{
|
||||
perror( "bind" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
#listen
|
||||
|
||||
Create a connection queue
|
||||
|
||||
int listen(int socket, int backlog);
|
||||
|
||||
Backlog is the max queue size.
|
||||
|
||||
If overflows TODO.
|
||||
*/
|
||||
|
||||
if ( listen( server_sockfd, 5 ) == -1 ) {
|
||||
perror( "listen" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//run server
|
||||
while ( 1 )
|
||||
{
|
||||
/*
|
||||
#accept
|
||||
|
||||
Accept connect from client.
|
||||
|
||||
For each accept a new file descriptor is created to communicate with the client.
|
||||
|
||||
Blocks until a connexion is requested by a client via `connect`
|
||||
*/
|
||||
client_len = sizeof( client_address );
|
||||
client_sockfd = accept(
|
||||
server_sockfd,
|
||||
(struct sockaddr*)&client_address,
|
||||
&client_len
|
||||
);
|
||||
if ( client_sockfd == -1 ) {
|
||||
perror( "accept" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ( read( client_sockfd, &ch, 1 ) == -1 ) {
|
||||
perror( "read" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ch++;
|
||||
|
||||
if ( write( client_sockfd, &ch, 1 ) == -1 ) {
|
||||
perror( "write" );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
#send
|
||||
|
||||
Could be used instead of write for sockets.
|
||||
|
||||
`write` is the same as a send without flags, so send has more options.
|
||||
*/
|
||||
|
||||
//you should close the connection on both client and server
|
||||
|
||||
close( client_sockfd );
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
90
posix/socket/wget.c
Normal file
90
posix/socket/wget.c
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
@file
|
||||
|
||||
Minimalistic error checked program that fetches a web page and prints it to stdout.
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include "assert.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h> //getprotobyname
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include "unistd.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char hostname[] = "www.google.com";
|
||||
unsigned short server_port = 80;
|
||||
char protoname[] = "tcp";
|
||||
char request[] = "GET / HTTP/1.0\n\n";
|
||||
int request_len = strlen(request);
|
||||
in_addr_t server_addr;
|
||||
int sockfd;
|
||||
struct sockaddr_in address;
|
||||
struct protoent *protoent;
|
||||
char buff[BUFSIZ];
|
||||
struct hostent* hostent;
|
||||
int nbytes_total, nbytes_last;
|
||||
|
||||
// Build the socket.
|
||||
protoent = getprotobyname(protoname);
|
||||
if (protoent == NULL) {
|
||||
perror("getprotobyname");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, protoent->p_proto);
|
||||
if (sockfd == -1) {
|
||||
perror("socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Build the address.
|
||||
hostent = gethostbyname(hostname);
|
||||
if (hostent == NULL) {
|
||||
fprintf(stderr, "error: gethostbyname(\"%s\")\n", hostname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server_addr = inet_addr(inet_ntoa(*(struct in_addr*)*(hostent->h_addr_list)));
|
||||
if (server_addr == (in_addr_t)-1) {
|
||||
fprintf(stderr, "error: inet_addr(\"%s\")\n", *(hostent->h_addr_list));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
address.sin_addr.s_addr = server_addr;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(server_port);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr*)&address, sizeof(address)) == -1) {
|
||||
perror("connect");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
nbytes_total = 0;
|
||||
while (nbytes_total < request_len) {
|
||||
nbytes_last = write(sockfd, request + nbytes_total, request_len - nbytes_total);
|
||||
if (nbytes_last == -1) {
|
||||
perror("write");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
nbytes_total += nbytes_last;
|
||||
}
|
||||
|
||||
while ((nbytes_total = read(sockfd, buff, BUFSIZ)) > 0) {
|
||||
write(STDOUT_FILENO, buff, nbytes_total);
|
||||
}
|
||||
|
||||
if (nbytes_total == -1) {
|
||||
perror("read");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user