IPv6 Daytime Server
Author: Eva M. Castro eva arroba gsyc.es |
The TCP and UDP versions of the daytime server program use a common function to create the server socket, the listen_server function. This function generates a server socket from a hostname, the service, socket family (IPv4 or IPv6) and socket type (TCP or UDP) parameters.
File "listen_server.h"
File "listen_server.cpp"#ifndef listen__server__h__ #define listen__server__h__ /* listen_server creates a server server socket listening at a hostname:service using the family and socket type specified in the function arguments. */ int listen_server(const char *hostname, const char *service, int family, int socktype); #endif
The TCP daytime server uses listen_server with SOCK_STREAM and PF_UNSPEC parameters to obtain a server socket, which will accept connections to all of the interfaces. When clients connect to the server, it will answer with the daytime information and close the client connection.#include <types.h> #include <socket.h> #include <netdb.h> #include <stdio.h> #include "listen_server.h" const int LISTEN_QUEUE=128; int listen_server(const char *hostname, const char *service, int family, int socktype) { struct addrinfo hints, *res, *ressave; int error, sockfd; memset(&hints, 0, sizeof(struct addrinfo)); /* AI_PASSIVE flag: the resulting address is used to bind to a socket for accepting incoming connections. So, when the hostname==NULL, getaddrinfo function will return one entry per allowed protocol family containing the unspecified address for that family. */ hints.ai_flags = AI_PASSIVE; hints.ai_family = family; hints.ai_socktype = socktype; error = getaddrinfo(hostname, service, &hints, &res); if (error != 0) { fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(error)); return -1; } ressave=res; /* Try open socket with each address getaddrinfo returned, until getting a valid listening socket. */ sockfd=-1; while (res) { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd >= 0) { if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) break; close(sockfd); sockfd=-1; } res = res->ai_next; } freeaddrinfo(ressave); if (sockfd < 0) { fprintf(stderr, "socket error:: could not open socket\n"); return -1; } listen(sockfd, LISTEN_QUEUE); return sockfd; }
File "tcp_daytime_server.cpp"
The UDP daytime server uses listen_server with SOCK_DGRAM and PF_UNSPEC parameters to obtain a server socket, which will receive connections to all of the interfaces. When clients connect to the server, it will answer with the daytime information and close the client connection.#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <time.h> #include <unistd.h> #include "listen_server.h" const char *DAYTIME_PORT="13"; int main(int argc, char *argv[]) { int listenfd, connfd, error; socklen_t addrlen; char timeStr[256]; struct sockaddr_storage clientaddr; time_t now; char clienthost[NI_MAXHOST]; char clientservice[NI_MAXSERV]; /* local server socket listening at daytime port=13 */ listenfd = listen_server( NULL, DAYTIME_PORT, AF_UNSPEC, SOCK_STREAM); if (listenfd < 0) { fprintf(stderr, "listen_socket error:: could not create listening " "socket\n"); return -1; } for ( ; ;) { addrlen = sizeof(clientaddr); /* accept daytime client connections */ connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &addrlen); if (connfd < 0) continue; memset(clienthost, 0, sizeof(clienthost)); memset(clientservice, 0, sizeof(clientservice)); error = getnameinfo((struct sockaddr *)&clientaddr, addrlen, clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST); if (error != 0) { fprintf(stderr, "getnameinfo error:: can not print the received" "request \n"); } else { printf("Received request from host=[%s] port=[%s]\n", clienthost, clientservice); } /* process daytime request from a client */ memset(timeStr, 0, sizeof(timeStr)); time(&now); sprintf(timeStr, "%s", ctime(&now)); write(connfd, timeStr, strlen(timeStr)); close(connfd); } return 0; }
File "udp_daytime_server.cpp"
Migration process is simple because all main changes are grouped inside listen_server function. If application is not correctly structured porting effort increases. Sometimes, it is much better to review the program structure that only to change functions calls to make the adaptation.#include <types.h> #include <socket.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <time.h> #include "listen_server.h" const char *DAYTIME_PORT="13"; int main(int argc, char *argv[]) { int listenfd, error; socklen_t addrlen; char *myhost; char timeStr[256]; struct sockaddr_storage clientaddr; time_t now; char b[256]; char clienthost[NI_MAXHOST]; char clientservice[NI_MAXSERV]; myhost=NULL; if (argc > 1) myhost=argv[1]; listenfd= listen_server(myhost, DAYTIME_PORT, AF_UNSPEC, SOCK_DGRAM); if (listenfd < 0) { fprintf(stderr, "listen_server error:: could not create listening " "socket\n"); return -1; } addrlen = sizeof(clientaddr); for ( ; ;) { error = recvfrom(listenfd, b, sizeof(b), 0, (struct sockaddr *)&clientaddr, &addrlen); if (error < 0) continue; memset(clienthost, 0, sizeof(clienthost)); memset(clientservice, 0, sizeof(clientservice)); error = getnameinfo((struct sockaddr *)&clientaddr, addrlen, clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST); if (error != 0) { fprintf(stderr, "getnameinfo error:: can not print the received" "request \n"); } else { printf("Received request from host=[%s] port=[%s]\n", clienthost, clientservice); } memset(timeStr, 0, sizeof(timeStr)); time(&now); sprintf(timeStr, "%s", ctime(&now)); error = sendto(listenfd, timeStr, sizeof(timeStr), 0, (struct sockaddr *)&clientaddr, addrlen); if (error < 0) { ; } } return 0; }
This is the reason why scripts to change code automatically are not recommended. Automatic scripts look for concrete functions and change them by new function version however, program structure is not analyzed and many times the result is very poor.
Author: Eva M. Castro eva arroba gsyc.es |