#define _POSIX_C_SOURCE 200809L #include /* assert */ #include /* errno */ #include /* read, write, fork, close */ #include /* send */ #include /* htonl, ntohl */ #include /* V této přípravě je Vaším úkolem naprogramovat datagramový server, * který od každého z ⟦N⟧ klientů obdrží jedno číslo, nalezne mezi * nimi minimum a toto vrátí. Čísla v rozsahu 0 až 2³¹ - 1 budou * klienty posílána jako čtyřbajtové pakety, nejvýznamnější bajt * první (tzn. big endian). * * Naprogramujte proceduru ‹min_server›, která jako parametry * dostane popisovač socketu, na kterém bude přijímat pakety, a * kladné číslo ‹n›. * * Po ukončení protokolu (tzn. potom, co obdrží všech ‹n› čísel od * klientů) uklidí případné lokálně alokované zdroje a výsledné * minimum vrátí volajícímu. * * Nastane-li chyba protokolu (některý klient pošle paket * v nesprávném formátu), vrátí -2, ale až po přijetí paketů od * všech klientů. Nastane-li nějaká systémová chyba, vrátí -1 a * nastaví hodnotu ‹errno› odpovídajícím způsobem. */ int min_server( int fd, int n ); /* ┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄┄┄┄ následují testy ┄┄┄┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄ */ #include #include static void close_or_warn( int fd, const char *name ) { if ( close( fd ) == -1 ) warn( "closing %s", name ); } static void send_or_die( int fd, const void *buffer, int nbytes ) { int bytes_sent = send( fd, buffer, nbytes, 0 ); if ( bytes_sent == -1 ) err( 1, "sending %d bytes", nbytes ); if ( bytes_sent != nbytes ) errx( 1, "unexpected short send: %d/%d sent", bytes_sent, nbytes ); } static int reap( pid_t pid ) { int status; if ( waitpid( pid, &status, 0 ) == -1 ) err( 2, "wait" ); if ( WIFEXITED( status ) ) return WEXITSTATUS( status ); else return -1; } static void sender( int fd ) { uint32_t v1 = htonl( 1 ); uint32_t v5 = htonl( 5 ); uint32_t idlecode = htonl( 0x1d1ec0de ); uint32_t big = htonl( 0x7fff0000 ); uint32_t toobig = htonl( 0xfffffff0 ); /* case 1 */ send_or_die( fd, &v1, 4 ); send_or_die( fd, &v1, 4 ); send_or_die( fd, &v5, 4 ); /* case 2 */ send_or_die( fd, &v5, 4 ); send_or_die( fd, &v5, 4 ); send_or_die( fd, &v5, 4 ); /* case 3 */ send_or_die( fd, &big, 4 ); send_or_die( fd, &idlecode, 4 ); /* case 4 */ send_or_die( fd, &big, 2 ); send_or_die( fd, &idlecode, 4 ); /* case 5 */ send_or_die( fd, &big, 4 ); send_or_die( fd, &idlecode, 4 ); send_or_die( fd, &toobig, 4 ); close( fd ); } int main() { int fds[ 2 ]; if ( socketpair( AF_UNIX, SOCK_DGRAM, 0, fds ) == -1 ) err( 1, "pipe" ); int server_fd = fds[ 0 ], client_fd = fds[ 1 ]; int client_pid = fork(); if ( client_pid == -1 ) err( 1, "fork" ); if ( client_pid == 0 ) { close_or_warn( server_fd, "server end of a socket" ); sender( client_fd ); return 0; } close_or_warn( client_fd, "client end of a socket" ); assert( min_server( server_fd, 3 ) == 1 ); assert( min_server( server_fd, 3 ) == 5 ); assert( min_server( server_fd, 2 ) == 0x1d1ec0de ); assert( min_server( server_fd, 2 ) == -2 ); assert( min_server( server_fd, 3 ) == -2 ); assert( reap( client_pid ) == 0 ); close_or_warn( server_fd, "server end of a socket" ); return 0; }