/* Copyright (C) 2022 Gentoo-libre Install License: GPLv3+ A poor tcp server that works somewhat Note: Due to the usage of sockets and pipes in a single thread, this application will block at each read/write. (e.g. until output.pipe is cleared, the next read() won't commence) */ #include #include #include #include //plently of port utils and also defines open() #include #include #include #include #include #include //for open() and open()'s values (e.g. O_RDONLY) #include //for ioctl #include //for ioctl #define READCHAR 80 //amount of bytes to read at once //#define PORT 2525 #define PORT 53 #define SA struct sockaddr #define INPUTPIPE "/tmp/input.pipe" #define OUTPUTPIPE "/tmp/output.pipe" //function designed for client <--> server void tcpSession(int sockfd) { char input[READCHAR]; int n; int result, inputPipe, outputPipe, bytesRead, bytesWritten; //Note: reading or writing to pipes blocks until the pipe is closed while(1) { inputPipe = open(INPUTPIPE, O_RDONLY);//open input pipe read only if (!inputPipe){printf("Opening input pipe failed!\n"); exit(1);} //read the message to send from the input pipe moreInputPipe: bytesRead = read(inputPipe, input, READCHAR); if (bytesRead == -1){printf("Reading from pipe failed!\n"); exit(1);} //if message from input pipe starts with 221, print that message then exit if (memcmp("221", input, 3) == 0) { input[bytesRead] = '\0'; int result = write(sockfd, input,strlen(input));//announce that server is exiting. if (!result){printf("Broken pipe.\n"); exit(1);} printf("Server Exit\n"); break; } //if message from input pipe is ">.<", don't send anything to client if (memcmp(">.<", input, 3) == 0){goto moreInput;} //send anything in the input pipe to the client result = write(sockfd, input,bytesRead); if (!result){printf("Broken pipe.\n"); break;} ioctl(inputPipe, SIOCINQ, &result);//ioctl SIOCINQ returns the amounts of bytes available to read without blocking if (result){goto moreInputPipe;}//if ioctl returns a number above 0, there are more bytes to read close(inputPipe);//close the input pipe moreInput: result = read(sockfd, input, READCHAR); if (!result){printf("Broken pipe.\n"); break;} outputPipe = open(OUTPUTPIPE, O_WRONLY);//open output pipe write only if (!outputPipe){printf("Opening output pipe failed!\n"); exit(1);} //write the clients input to the output pipe bytesWritten = write(outputPipe, input, result); if (bytesWritten == -1){printf("Writing to output pipe failed!\n"); exit(1);} close(outputPipe);//close the output pipe ioctl(sockfd, SIOCINQ, &result);//ioctl SIOCINQ returns the amounts of bytes available to read without blocking if (result){goto moreInput;}//if ioctl returns a number above 0, there are more bytes to read } close(inputPipe); close(outputPipe); } //driver function int main(void) { int sockfd, connfd, len; struct sockaddr_in servaddr, cli; //socket create and verification sockfd = socket(AF_INET, SOCK_STREAM, 0); //if (sockfd == -1){printf("Socket creation failed!\n"); exit(1);} if (!sockfd){printf("Socket creation failed!\n"); exit(1);} printf("Socket created\n"); bzero(&servaddr, sizeof(servaddr)); //assign IP, PORT servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //servaddr.sin_addr.s_addr = inet_addr("0.0.0.0"); servaddr.sin_port = htons(PORT); //With Linux, by default, even after a socket is closed properly, it can't be used again for a minute or two. Using setsockopt() with SO_REUSEADDR can be used to stop this though. There is one drawback: there is no longer anything preventing multiple processes binding to the same socket. (Only one can actually use the socket, the rest are binded and any reads and writes will fail. int reuse = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0){printf("setsockopt(SO_REUSEADDR) failed!\n");} //bind socket if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0){printf("Socket bind failed!\n"); exit(1);} printf("Socket binded\n"); //create the named pipes if they don't already exist // mkfifo(, ) if ((access(INPUTPIPE, 0)) != 0){ if ( (mkfifo(INPUTPIPE, 0666)) == -1) {printf("Making input pipe failed!\n"); exit(1);} } if ((access(OUTPUTPIPE, 0)) != 0){ if ( (mkfifo(OUTPUTPIPE, 0666)) == -1) {printf("Making input pipe failed!\n"); exit(1);} } //server is ready to listen and verify now if ((listen(sockfd, 5)) != 0){printf("Listen failed!\n"); exit(1);} printf("Server listening.\n"); len = sizeof(cli); //Accept a packet from a client and verify it connfd = accept(sockfd, (SA*)&cli, &len); if (connfd < 0){printf("Server accept failed!\n"); exit(1);} printf("Server accepted the client.\n"); //undertake tcp session (e.g. io) tcpSession(connfd); //be a good boy and close the socket close(sockfd); remove(INPUTPIPE); remove(OUTPUTPIPE); return 0; }