// A select()-based TCP multiplexer. It will accept connections// on the specified port and send its stdin to connected clients.// This has nothing to do with the tcpmux service.// // $ cc -Wall -W -pedantic -std=c99 -o tcpmux tcpmux.c// // TODO: select() sucks, use something better// TODO: turn this into a netcat patch// TODO: _XOPEN_SOURCE should be in Makefile// TODO: RESEND should be a command line option// TODO: are all error conditions checked ?//// Copyright (c) 2006 Adrien Kunysz//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the "Software"),// to deal in the Software without restriction, including without limitation// the rights to use, copy, modify, merge, publish, distribute, sublicense,// and/or sell copies of the Software, and to permit persons to whom the// Software is furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER// DEALINGS IN THE SOFTWARE.#define _XOPEN_SOURCE 500//#define RESEND // data sent by clients are resent to other clients//#define NDEBUG // less verbosity#include<stdio.h> // stderr, fprintf()#include<stdlib.h> // exit(), EXIT_*, atoi(), NULL#include<string.h> // memset()#include<errno.h> // errno#include<sys/types.h> // size_t, ssize_t#include<sys/socket.h> // socket(), bind(), listen(), accept(), send(),...#include<sys/time.h> // select(), FD_*, fd_set#include<arpa/inet.h> // htons()#include<netinet/in.h> // INADDR_ANY, sockaddr_in#include<unistd.h> // STDIN_FILENO, STDERR_FILENO, close(), read()#include<fcntl.h> // fcntl(), F_SETFL, O_NONBLOCK#define MAX_UNACCEPTED_CONNS 5 // listen()'s second argument#define MAX_CLIENTS 32#define BUFSZ 1024#if MAX_CLIENTS + 2 > FD_SETSIZE# error MAX_CLIENTS is too high#endif#ifdef NDEBUG# define debug(...)# define wdebug(buf, len)#else# define debug(...) fprintf(stderr, __VA_ARGS__)# define wdebug(buf, len) write(STDERR_FILENO, buf, len)#endif#define err(...) do { \ fprintf(stderr, __VA_ARGS__); \ exit(EXIT_FAILURE); \ } while (0)intsetup_socket(intportnum){intres=-1;if(-1==(res=socket(AF_INET,SOCK_STREAM,0)))err("Unable to create socket.\n");intyes=1;if(-1==setsockopt(res,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)))fprintf(stderr,"Unable to set SO_REUSEADDR option.\n");structsockaddr_inmyaddr={.sin_family=AF_INET,.sin_addr.s_addr=INADDR_ANY,.sin_port=htons(portnum)};memset(&(myaddr.sin_zero),'0円',8);if(-1==bind(res,(structsockaddr*)&myaddr,sizeof(myaddr)))err("Unable to bind address to socket.\n");if(-1==listen(res,MAX_UNACCEPTED_CONNS))err("Unable to listen on socket.\n");returnres;}intaccept_client(intserverfd){structsockaddr_inclientaddr;socklen_taddrlen=sizeof(clientaddr);intres=accept(serverfd,(structsockaddr*)&clientaddr,&addrlen);if(-1==res)err("accept() failure\n");if(-1==fcntl(res,F_SETFL,O_NONBLOCK))fprintf(stderr,"Unable to set non blocking mode on fd.\n");returnres;}size_tsendall(intfd,char*buf,size_tlen){size_tsent=0;while(sent<len){errno=0;ssize_tthis_block=send(fd,&buf[sent],len-sent,0);if(0>this_block){if(EAGAIN==errno||EWOULDBLOCK==errno)fprintf(stderr,"Output buffer is full ?\n");break;}sent+=(size_t)this_block;}returnsent;}intmain(intargc,char**argv){if(2!=argc)err("Usage: %s PORT\n",argv[0]);constintport=atoi(argv[1]);constintinputfd=STDIN_FILENO;constintserverfd=setup_socket(port);staticintclientsfds[MAX_CLIENTS];for(unsignedinti=0;i<MAX_CLIENTS;i++)clientsfds[i]=-1;staticfd_setallfds;FD_ZERO(&allfds);FD_SET(serverfd,&allfds);FD_SET(inputfd,&allfds);while(1){staticfd_setselectfds;selectfds=allfds;if(-1==select(FD_SETSIZE,&selectfds,NULL,NULL,NULL))err("select() failure\n");if(FD_ISSET(serverfd,&selectfds)){// client connectiondebug("Got new client.\n");unsignedintfdidx;for(fdidx=1;fdidx<MAX_CLIENTS;fdidx++)if(-1==clientsfds[fdidx])break;if(MAX_CLIENTS+1==fdidx)fprintf(stderr,"Too many clients.\n");clientsfds[fdidx]=accept_client(serverfd);FD_SET(clientsfds[fdidx],&allfds);continue;}staticcharbuf[BUFSZ];if(FD_ISSET(inputfd,&selectfds)){// input is readablessize_tlen=read(inputfd,buf,sizeof(buf));if(0>len)err("mysterious read failure\n");if(0==len)// EOFexit(EXIT_SUCCESS);size_tulen=(size_t)len;for(unsignedinti=0;i<MAX_CLIENTS;i++){if(-1==clientsfds[i])continue;if(ulen!=sendall(clientsfds[i],buf,ulen))fprintf(stderr,"send() failure\n");}continue;}// a client sent somethingunsignedintfdidx;for(fdidx=0;fdidx<MAX_CLIENTS;fdidx++){if(clientsfds[fdidx]==-1)continue;if(FD_ISSET(clientsfds[fdidx],&selectfds))break;}if(MAX_CLIENTS==fdidx){// wtf ? no readable client foundfprintf(stderr,"select() lied ?\n");continue;}ssize_tlen=read(clientsfds[fdidx],buf,sizeof(buf));if(0>len)fprintf(stderr,"failed to read from client\n");if(0==len){// client closed connectionFD_CLR(clientsfds[fdidx],&allfds);close(clientsfds[fdidx]);clientsfds[fdidx]=-1;debug("Client disconnected.\n");continue;}wdebug(buf,(size_t)len);#ifdef RESENDfor(unsignedinti=0;i<MAX_CLIENTS;i++)if(-1!=clientsfds[i]&&i!=fdidx)sendall(clientsfds[i],buf,(size_t)len);#endif}}
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
# alternative
Posté par Krunch (courriel, site web personnel) . En réponse au journal Editer en parallèle les paramètres BIOS de plusieurs machines grâce à tmux. Évalué à 4.
J'ai écrit ça il y a quelques temps qui fait un truc similaire pour les gens qui ont pas tmux (comme c'était le cas de tout le monde en 2006) : http://cretonnerre.krunch.be/~krunch/src/tcpmux.c
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.