Architecture/Lecture/tcpsrv0.1
From Apache OpenOffice Wiki
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ /* * tcpsrv.c Vers. 0.1 * Copyright (C) Stefan Zimmermann 2008 <sz@sun.com> * * tcqpsrv.c is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * tcpsrv.c is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. * * The server waits on TCP Port PORT for connection requests from * telnet clients. The client sends ASCII messages to the server. * This messages will be sent from the server then to all other connected clients. * * start server with: * ./tcpsrv & * * start client with: * telnet _serverIPadresse_ PORT */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <syslog.h> #include <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/select.h> #include <arpa/inet.h> /* the makros exit_if() and return_if() realize the error handling * of the application. If exit_if() condition is TRUE, the program will * be terminated with the information of: file, line, function and errno. * * If the return_if() condition is TRUE, the program returns from the * current function. The second parameter will be used as return value */ #define exit_if(expr)\ if(expr) {\ syslog(LOG_WARNING, "exit_if() %s: %d: %s: Error %s\n",\ __FILE__, __LINE__, __PRETTY_FUNCTION__, strerror(errno));\ exit(1);\ } #define return_if(expr, retvalue)\ if(expr) {\ syslog(LOG_WARNING, "return_if() %s: %d: %s: Error %s\n\n",\ __FILE__, __LINE__, __PRETTY_FUNCTION__, strerror(errno));\ return(retvalue);\ } #define MAXLEN 1024 #define PORT 61412 #define OKAY 0 #define ERROR (-1) int listen_socket(int port) /* open server (listen) port - called only once * in port: port number where TCP server is supposed to listen * return: server socket file descriptor to connect from client(s) */ { int srv_sockfd; int ret; struct sockaddr_in sockadr; int yes = 1; /* create the socket */ srv_sockfd = socket(PF_INET, SOCK_STREAM, 0); exit_if(srv_sockfd < 0); /* prevent "error address already in use" message */ ret = setsockopt(srv_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); exit_if(ret < 0); memset((char *) &sockadr, 0, sizeof(sockadr)); sockadr.sin_family = AF_INET; sockadr.sin_addr.s_addr = htonl(INADDR_ANY); sockadr.sin_port = htons(port); /* bind created socket to port */ ret = bind(srv_sockfd, (struct sockaddr *) &sockadr, sizeof(sockadr)); exit_if(ret != 0); ret = listen(srv_sockfd, 5); exit_if(ret < 0); return srv_sockfd; } int accept_socket(int srv_sockfd) /* open communication (connection) - execute for every new client * in srv_sockfd: socket file descriptor to connect from client * return: if okay socket file descriptor to read from client, ERROR otherwise */ { int client_fd; struct sockaddr_in sockadr; socklen_t socklen = sizeof(sockadr); socklen = sizeof(sockadr); client_fd = accept(srv_sockfd, (struct sockaddr *) &sockadr, &socklen); return_if(client_fd < 0, ERROR); printf("Connected %s:%d\n", (char*)inet_ntoa(sockadr.sin_addr), ntohs(sockadr.sin_port)); return client_fd; } int socket_write(int client_fd, char buf[], int buflen) /* write to the client socket interface * in fd: socket file descriptor to write to client * in buf: message to write * in buflen: length of message * return: OKAY if write was completed, ERROR otherwise */ { int ret; ret = send(client_fd, buf, buflen, 0); return_if(ret != buflen, ERROR); return OKAY; } int socket_read(int client_fd, char buf[], int *buflen) /* read from client socket interface * in fd: socket file descriptor to read from client * out buf: message which was read * inout buflen: in = max length of message, out = length of message read * return: OKAY when read was completed, ERROR otherwise */ { /* read message */ *buflen = recv(client_fd, buf, *buflen, 0); if (*buflen <= 0 || strncmp("quit\r", buf,5) == 0) { /* end of TCP connection */ close(client_fd); return ERROR; /* means fd is not valid anymore */ } return OKAY; } void srv_loop(int srv_sockfd) /* server loop * in listen_fd: socket file descriptor to connect from client */ { fd_set sock_fdset; /* socket file descriptor set */ int maxfd; /* max num of socket file descriptor in set */ /* zero the file descriptor set to get rid of random values then copy server listen socket fd to file descriptor set */ FD_ZERO(&sock_fdset); FD_SET(srv_sockfd, &sock_fdset); maxfd = srv_sockfd; for (;;) { /* begin loop */ fd_set readfds; /* file descriptor set for reading */ int ret; /* return value for error handling in macros */ int client_rfd = 0; /* client file descriptor to read from */ readfds = sock_fdset; /* select() nchanges readfds, backup state */ /* wait for activity */ ret = select(maxfd + 1, &readfds, NULL, NULL, NULL); if ((ret == -1) && (errno == EINTR)) { /* a signal occurred - ignore */ continue; } exit_if(ret < 0); /* check TCP server LISTEN Port for client connect request if, then accept the connect request and add new client to our socket file descriptor set */ if (FD_ISSET(srv_sockfd, &readfds)) { client_rfd = accept_socket(srv_sockfd); if (client_rfd >= 0) { FD_SET(client_rfd, &sock_fdset); /* add new client rfd */ if (client_rfd > maxfd) { /* re-adjust max fd num */ maxfd = client_rfd; } } } /* check TCP server CONNECT ports for clients communication */ for (client_rfd = srv_sockfd + 1; client_rfd <= maxfd; ++client_rfd) { if (FD_ISSET(client_rfd, &readfds)) { char msgbuf[MAXLEN]; int msgbuflen; /* read message from client */ msgbuflen = sizeof(msgbuf); ret = socket_read(client_rfd, msgbuf, &msgbuflen); if (ERROR == ret) { FD_CLR(client_rfd, &sock_fdset); /* remove client rfd if error*/ } else { /* write message to all other clients */ int client_wfd; for (client_wfd = srv_sockfd+1; client_wfd <= maxfd; ++client_wfd) { if (FD_ISSET(client_wfd, &sock_fdset)&&(client_rfd != client_wfd)) { socket_write(client_wfd, msgbuf, msgbuflen); } /* if */ } /* for */ } /* else */ } /* if */ } /* for */ } /* end of for loop */ } /* end of srv_loop function */ int main(int argc, char *argv[]) { /* enable error logging */ openlog(NULL, LOG_PERROR, LOG_WARNING); /* open tcpsrv */ srv_loop(listen_socket(PORT)); return OKAY; }