├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── container_A ├── Dockerfile ├── first.c ├── relay.h └── script.sh ├── container_B ├── Dockerfile ├── next-pass.c ├── next-wait.c ├── relay.h └── script.sh ├── docker-compose.yml └── src ├── first.c ├── next-pass.c ├── next-wait.c └── relay.h /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [jasonsychau] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | next-pass 2 | next-wait 3 | first -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## RelayAndContainers 2 | 3 | _Please give a star :star: if you have my programs in your projects_ 4 | 5 | This is a small template for a project run on Docker Containers. 6 | 7 | Queuing containers is flexible by different orders of the programs in src directory. 8 | 9 | The programs are given name by the order that is given to your container orchestration. 10 | 11 | 12 | ### Programs Description 13 | 14 | #### first 15 | 16 | The first program is called to declare when your other services are supposed to wait for the container running first to finish the earlier portions of the container script. 17 | 18 | If first is reused, the effect is same as above statement. However, the ports are of importance to not confuse the sought containers. 19 | 20 | #### next-wait 21 | 22 | The next-wait program is for only holding a queue. The container that is running next-wait is held behind and until the other program is ready to permiss these next-wait containers to go onwards with their computations. The other programs are named first (the above program) and next-pass. These two programs (first and next-pass) are given the purpose of telling other containers to go when these programs are ready to let them. The waiting programs are (this) next-wait and the next-pass. 23 | 24 | #### next-pass 25 | 26 | The next-pass program is to allow a queued container to go. It is called to take over the position of allowing the passing of other containers that are waiting for this next-pass. The position is taken from containers running first or next-pass with the `REQUEST_PORT` that's given to this call of next-pass. 27 | 28 | 29 | ### Example 30 | 31 | #### Most basic example 32 | 33 | One container is waiting for another. 34 | 35 | | Container 1 (l:3528) | Container 2 (s:3528) | 36 | |:---:|:---:| 37 | | (running) | next-wait | 38 | | (running) | (waiting for Container 1) | 39 | | first | (receiving permission from Container 1) | 40 | | (queued and granting permissions) | (running) | 41 | -------------------------------------------------------------------------------- /container_A/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM : 2 | 3 | # install gcc 4 | 5 | RUN mkdir /usr/src 6 | 7 | RUN mkdir /usr/src/app 8 | 9 | COPY relay.h /usr/src/app 10 | COPY first.c /usr/src/app 11 | COPY script.sh /usr/src/app 12 | 13 | WORKDIR /usr/src/app 14 | 15 | RUN gcc -o first first.c 16 | 17 | RUN chmod +x first 18 | RUN chmod +x script.sh 19 | 20 | CMD ["./script.sh"] 21 | -------------------------------------------------------------------------------- /container_A/first.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "relay.h" 12 | 13 | void log_msg(char* msg) { 14 | printf("first:\t%s\n", msg); 15 | fflush(stdout); 16 | } 17 | void log_warning(char* msg) { 18 | printf("first [WARNING]:\t%s\n", msg); 19 | fflush(stdout); 20 | } 21 | void log_error(char* msg, int signal) { 22 | fprintf(stderr, "first [ERROR]:\t%s\n", msg); 23 | exit(signal); 24 | } 25 | void find_net_error() { 26 | switch (errno) { 27 | case EWOULDBLOCK: 28 | log_error("Timeout error", 1); 29 | break; 30 | case EBADF: 31 | log_error("Invalid file descriptor for socket", 1); 32 | break; 33 | case ECONNREFUSED: 34 | log_error("Remote host refused network connection.", 1); 35 | break; 36 | case EFAULT: 37 | log_error("Buffer pointers are not own.", 1); 38 | break; 39 | case EINTR: 40 | log_error("Receive is interrupted by signal.", 1); 41 | break; 42 | case EINVAL: 43 | log_error("Invalid argument", 1); 44 | break; 45 | case ENOMEM: 46 | log_error("Could not allocate memory", 1); 47 | break; 48 | default: 49 | log_error("Other error", 1); 50 | break; 51 | } 52 | } 53 | 54 | int main(int argc, char* argv[]) { 55 | uint8_t verbose = 0, 56 | debug = 0, 57 | closing = 0; 58 | uint16_t l_port, s_port; 59 | struct sockaddr_in server_addr, client_addr; 60 | struct hostent *he; 61 | int n, sockfd, len = sizeof(server_addr); 62 | relayItemType buffer, msg; 63 | while((n=getopt(argc, argv, "vdh")) != -1) { 64 | if (n=='v') { 65 | verbose = 1; 66 | } else if (n=='d') { 67 | debug = 1; 68 | } else if (n=='h') { 69 | printf("\t%s\n", ""); 70 | printf("\t%s\n", "./first [-v] [-d] [-h] MY_PORT [NEXT_HOST NEXT_PORT]"); 71 | printf("\t%s\n", "==========================================================="); 72 | printf("\t%s\n", ""); 73 | printf("\t%s\n", "OPTIONS:"); 74 | printf("\t%s\n", "-v (Verbose)\t- to print actions"); 75 | printf("\t%s\n", "-d (Debug)\t- to print warnings"); 76 | printf("\t%s\n", "-h (Help)\t- to print help page"); 77 | printf("\t%s\n", ""); 78 | printf("\t%s\n", "ARGUMENTS:"); 79 | printf("\t%s\n", "MY_PORT\t\t- this container or program port"); 80 | printf("\t%s\n", "NEXT_HOST\t- service name or network host name from which this program is expecting a close request"); 81 | printf("\t%s\n", "NEXT_PORT\t- port from which this program is expecting a close request"); 82 | printf("\t%s\n", ""); 83 | exit(0); 84 | } else { 85 | exit(1); 86 | } 87 | } 88 | if (argc-optind!=1&&argc-optind!=3) { 89 | log_error("usage: ./first [-v] [-d] [-h] MY_PORT [NEXT_HOST NEXT_PORT]", 1); 90 | } 91 | if ((n=atoi(argv[optind]))==0) { 92 | log_error("First argument is not readable port number.", 1); 93 | } else if (n<0||n>25535) { 94 | log_error("First argument is invalid listening port.", 1); 95 | } else { 96 | l_port = (uint16_t)n; 97 | } 98 | if (argc-optind==3) { 99 | closing = 1; 100 | if ((n = atoi(argv[optind+2])) == 0) { 101 | log_error("Third argument is not readable port number.", 1); 102 | } else if (n<0||n>25535) { 103 | log_error("Third argument is invalid sending port.", 1); 104 | } else { 105 | s_port = (uint16_t)n; 106 | } 107 | } 108 | 109 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) { 110 | log_error("Cannot create listening socket", EXIT_FAILURE); 111 | } 112 | memset(&server_addr, 0, sizeof(server_addr)); 113 | server_addr.sin_family = AF_INET; 114 | server_addr.sin_addr.s_addr = INADDR_ANY; 115 | server_addr.sin_port = htons(l_port); 116 | if (bind(sockfd, (const struct sockaddr*)&server_addr, sizeof(server_addr))<0) { 117 | log_error("Cannot bind socket to network address", EXIT_FAILURE); 118 | } 119 | if (closing==1&&(he = gethostbyname(argv[optind+1]))==NULL) { 120 | log_error("Cannot resolve hostname", EXIT_FAILURE); 121 | } 122 | 123 | if (verbose||debug) log_msg("Preparing to pass ready signal."); 124 | while (1) { 125 | memset(&client_addr, 0, sizeof(client_addr)); 126 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 127 | if (n<0) { 128 | find_net_error(); 129 | } else if (n==0) { 130 | if (debug) log_warning("No data read"); 131 | } else if (buffer==FIND_MSG) { 132 | msg = READY_MSG; 133 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, len); 134 | if (verbose||debug) log_msg("Sent ready signal"); 135 | } else if (buffer==CLOSE_MSG&&closing==1&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 136 | struct timeval timeout; 137 | timeout.tv_sec = 5; 138 | timeout.tv_usec = 0; 139 | if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 140 | log_error("Cannot set socket options", EXIT_FAILURE); 141 | } 142 | 143 | memset(&server_addr, 0, sizeof(server_addr)); 144 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 145 | server_addr.sin_family = AF_INET; 146 | server_addr.sin_port = htons(s_port); 147 | 148 | uint8_t attempts = 0; 149 | if (verbose||debug) log_msg("Preparing pass"); 150 | while (1) { 151 | memset(&client_addr, 0, sizeof(client_addr)); 152 | msg = CLOSING_MSG; 153 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 154 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 155 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 156 | attempts += 1; 157 | if (attempts==MAX_REQUESTS) { 158 | log_error("Max closing messages reached", 1); 159 | } else if (debug) { 160 | log_warning("Timed-out waiting for close confirm"); 161 | } 162 | } else { 163 | attempts = 0; 164 | if (n < 0) { 165 | find_net_error(); 166 | } else if (n == 0) { 167 | if (debug) log_warning("No data read"); 168 | } else if (buffer==FIND_MSG) { 169 | msg = READY_MSG; 170 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, len); 171 | if (verbose||debug) log_msg("Sent ready signal"); 172 | } else if (buffer==CONFIRM_MSG&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 173 | if (verbose||debug) log_msg("Closing"); 174 | break; 175 | } else if (buffer==CONFIRM_MSG) { 176 | if (debug) log_warning("Received unexpected close confirm"); 177 | } else if (debug) { 178 | log_warning("Data unknown"); 179 | } 180 | } 181 | } 182 | break; 183 | } else if (buffer==CLOSE_MSG) { 184 | if (debug) log_warning("Received unexpected close request"); 185 | } else if (debug) { 186 | if (debug) log_warning("Data unknown"); 187 | } 188 | } 189 | 190 | close(sockfd); 191 | 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /container_A/relay.h: -------------------------------------------------------------------------------- 1 | #ifndef RELAY_h 2 | #define RELAY_h 1 3 | 4 | #define MAX_REQUESTS 10 5 | 6 | enum relayMessage{ 7 | FIND_MSG = 100, 8 | READY_MSG, 9 | CLOSE_MSG, 10 | CLOSING_MSG, 11 | CONFIRM_MSG 12 | }; 13 | typedef enum relayMessage relayItemType; 14 | 15 | #endif -------------------------------------------------------------------------------- /container_A/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # run your setup 4 | 5 | ./first $MY_PORT "container-b" $NEXT_PORT 6 | 7 | # run others 8 | 9 | -------------------------------------------------------------------------------- /container_B/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM : 2 | 3 | # install gcc 4 | 5 | RUN mkdir /usr/src/app 6 | 7 | COPY relay.h /usr/src/app 8 | COPY next-wait.c /usr/src/app 9 | COPY next-pass.c /usr/src/app 10 | 11 | WORKDIR /usr/src/app 12 | 13 | RUN gcc -o next-wait next-wait.c 14 | RUN gcc -o next-pass next-pass.c 15 | 16 | RUN chmod +x ./next-wait 17 | RUN chmod +x ./next-pass 18 | 19 | CMD ["./script.sh"] 20 | -------------------------------------------------------------------------------- /container_B/next-pass.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "relay.h" 12 | 13 | void log_msg(char* msg) { 14 | printf("next-pass:\t%s\n", msg); 15 | fflush(stdout); 16 | } 17 | void log_warning(char* msg) { 18 | printf("next-pass [WARNING]:\t%s\n", msg); 19 | fflush(stdout); 20 | } 21 | void log_error(char* msg, int signal) { 22 | fprintf(stderr, "next-pass [ERROR]:\t%s\n", msg); 23 | exit(signal); 24 | } 25 | void find_net_error() { 26 | switch (errno) { 27 | case EWOULDBLOCK: 28 | log_error("Timeout error", 1); 29 | break; 30 | case EBADF: 31 | log_error("Invalid file descriptor for socket", 1); 32 | break; 33 | case ECONNREFUSED: 34 | log_error("Remote host refused network connection.", 1); 35 | break; 36 | case EFAULT: 37 | log_error("Buffer pointers are not own.", 1); 38 | break; 39 | case EINTR: 40 | log_error("Receive is interrupted by signal.", 1); 41 | break; 42 | case EINVAL: 43 | log_error("Invalid argument", 1); 44 | break; 45 | case ENOMEM: 46 | log_error("Could not allocate memory", 1); 47 | break; 48 | default: 49 | log_error("Other error", 1); 50 | break; 51 | } 52 | } 53 | int main(int argc, char* argv[]) { 54 | uint8_t verbose = 0, 55 | debug = 0, 56 | closing = 0, 57 | attempts = 0; 58 | uint16_t c_port, l_port, s_port; 59 | relayItemType buffer, msg; 60 | struct sockaddr_in server_addr, client_addr; 61 | struct hostent *he; 62 | struct in_addr close_host; 63 | int sockfd, n, len = sizeof(server_addr); 64 | while((n = getopt(argc, argv, "vdh")) != -1) { 65 | if (n=='v') { 66 | verbose = 1; 67 | } else if (n=='d') { 68 | debug = 1; 69 | } else if (n=='h') { 70 | printf("\t%s\n", ""); 71 | printf("\t%s\n", "./next-pass [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT MY_PORT [NEXT_HOST NEXT_PORT]"); 72 | printf("\t%s\n", "==========================================================="); 73 | printf("\t%s\n", ""); 74 | printf("\t%s\n", "OPTIONS:"); 75 | printf("\t%s\n", "-v (Verbose)\t- to print actions"); 76 | printf("\t%s\n", "-d (Debug)\t- to print warnings"); 77 | printf("\t%s\n", "-h (Help)\t- to print help page"); 78 | printf("\t%s\n", ""); 79 | printf("\t%s\n", "ARGUMENTS:"); 80 | printf("\t%s\n", "REQUEST_HOST\t- service name (or network host) to which this program is requesting a shut down"); 81 | printf("\t%s\n", "REQUEST_PORT\t- port to which this program is requesting a shut down"); 82 | printf("\t%s\n", "MY_PORT\t\t- this container or program port"); 83 | printf("\t%s\n", "NEXT_HOST\t- service name (or network host) from which this program is expecting a close request"); 84 | printf("\t%s\n", "NEXT_PORT\t- port from which this program is expecting a close request"); 85 | printf("\t%s\n", ""); 86 | exit(0); 87 | } else { 88 | exit(1); 89 | } 90 | } 91 | if (argc-optind!=3&&argc-optind!=5) { 92 | log_error("usage: ./next-pass [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT MY_PORT [NEXT_HOST NEXT_PORT]", 1); 93 | } 94 | if ((n = atoi(argv[optind+1])) == 0) { 95 | log_error("Second argument is not readable port number.", 1); 96 | } else if (n<0 || n>25535) { 97 | log_error("Second argument is invalid sending port.", 1); 98 | } else { 99 | c_port = (uint16_t)n; 100 | } 101 | if ((n = atoi(argv[optind+2])) == 0) { 102 | log_error("Third argument is not readable port number.", 1); 103 | } else if (n<0 || n>25535) { 104 | log_error("Third argument is invalid sending port.", 1); 105 | } else { 106 | l_port = (uint16_t)n; 107 | } 108 | if (argc-optind==5) { 109 | closing = 1; 110 | if ((n = atoi(argv[optind+4])) == 0) { 111 | log_error("Fifth argument is not readable port number.", 1); 112 | } else if (n<0 || n>25535) { 113 | log_error("Fifth argument is invalid sending port.", 1); 114 | } else { 115 | s_port = (uint16_t)n; 116 | } 117 | } 118 | 119 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) { 120 | log_error("Cannot create sending socket", EXIT_FAILURE); 121 | } 122 | struct timeval timeout; 123 | timeout.tv_sec = 5; 124 | timeout.tv_usec = 0; 125 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 126 | log_error("Cannot set socket options", EXIT_FAILURE); 127 | } 128 | memset(&client_addr, 0, sizeof(client_addr)); 129 | client_addr.sin_family = AF_INET; 130 | client_addr.sin_port = htons(l_port); 131 | client_addr.sin_addr.s_addr = INADDR_ANY; 132 | if (bind(sockfd, (const struct sockaddr*)&client_addr, sizeof(client_addr))<0) { 133 | log_error("Cannot bind socket to network address", EXIT_FAILURE); 134 | } 135 | 136 | if ((he = gethostbyname(argv[optind]))==NULL) { 137 | log_error("Cannot resolve hostname", EXIT_FAILURE); 138 | } 139 | memset(&server_addr, 0, sizeof(server_addr)); 140 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 141 | server_addr.sin_family = AF_INET; 142 | server_addr.sin_port = htons(c_port); 143 | memcpy(&close_host, he->h_addr_list[0], he->h_length); 144 | if (closing==1&&(he = gethostbyname(argv[optind+3]))==NULL) { 145 | log_error("Cannot resolve hostname", EXIT_FAILURE); 146 | } 147 | 148 | if (verbose||debug) log_msg("Sending request to close"); 149 | while (1) { 150 | memset(&client_addr, 0, sizeof(client_addr)); 151 | msg = CLOSE_MSG; 152 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 153 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 154 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 155 | attempts += 1; 156 | if (attempts==MAX_REQUESTS) { 157 | log_error("Max requests reached", 1); 158 | } else if (debug) { 159 | log_warning("Timed-out waiting for closing message"); 160 | } 161 | } else { 162 | attempts = 0; 163 | if (n < 0) { 164 | find_net_error(); 165 | } else if (n == 0) { 166 | if (debug) log_warning("No data read"); 167 | } else if (buffer==CLOSING_MSG&&memcmp(&client_addr.sin_addr, &close_host, sizeof(close_host))==0&&ntohs(client_addr.sin_port)==c_port) { 168 | log_msg("Got closing msg"); 169 | msg = CONFIRM_MSG; 170 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, sizeof(client_addr)); 171 | 172 | timeout.tv_sec = 0; 173 | timeout.tv_usec = 0; 174 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 175 | log_error("Cannot set socket options", EXIT_FAILURE); 176 | } 177 | 178 | if (verbose||debug) log_msg("Now am holding queue"); 179 | while (1) { 180 | memset(&client_addr, 0, sizeof(client_addr)); 181 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 182 | if (n<0) { 183 | find_net_error(); 184 | } else if (n==0) { 185 | if (debug) log_warning("No data read"); 186 | } else if (buffer==FIND_MSG) { 187 | msg = READY_MSG; 188 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, len); 189 | if (verbose||debug) log_msg("Sent ready signal"); 190 | } else if (buffer==CLOSING_MSG&&memcmp(&client_addr.sin_addr, &close_host, sizeof(close_host))==0&&ntohs(client_addr.sin_port)==c_port) { 191 | msg = CONFIRM_MSG; 192 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, sizeof(client_addr)); 193 | } else if (buffer==CLOSING_MSG) { 194 | if (debug) log_warning("Received unexpected closing message"); 195 | } else if (buffer==CLOSE_MSG&&closing==1&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], sizeof(he->h_length))==0&&ntohs(client_addr.sin_port)==s_port) { 196 | 197 | timeout.tv_sec = 5; 198 | timeout.tv_usec = 0; 199 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 200 | log_error("Cannot set socket options", EXIT_FAILURE); 201 | } 202 | 203 | memset(&server_addr, 0, sizeof(server_addr)); 204 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 205 | server_addr.sin_family = AF_INET; 206 | server_addr.sin_port = htons(s_port); 207 | 208 | if (verbose||debug) log_msg("Preparing pass"); 209 | while (1) { 210 | memset(&client_addr, 0, sizeof(client_addr)); 211 | msg = CLOSING_MSG; 212 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 213 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 214 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 215 | attempts += 1; 216 | if (attempts==MAX_REQUESTS) { 217 | log_error("Max close confirm requests reached", 1); 218 | } else if (debug) { 219 | log_warning("Timed-out waiting for close confirm"); 220 | } 221 | } else { 222 | attempts = 0; 223 | if (n < 0) { 224 | find_net_error(); 225 | } else if (n == 0) { 226 | if (debug) log_warning("No data read"); 227 | } else if (buffer==CONFIRM_MSG&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 228 | if (verbose||debug) log_msg("Closing"); 229 | break; 230 | } else if (buffer==CONFIRM_MSG) { 231 | if (debug) log_warning("Received unexpected close confirm"); 232 | } else if (debug) { 233 | log_warning("Data unknown"); 234 | } 235 | } 236 | } 237 | break; 238 | } else if (debug) { 239 | log_warning("Data unknown"); 240 | } 241 | } 242 | break; 243 | } else if (buffer==CLOSING_MSG) { 244 | if (debug) log_warning("Received unexpected closing message"); 245 | } else if (debug) { 246 | log_warning("Data unknown"); 247 | } 248 | } 249 | } 250 | 251 | close(sockfd); 252 | return 0; 253 | } -------------------------------------------------------------------------------- /container_B/next-wait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "relay.h" 12 | 13 | void log_msg(char* msg) { 14 | printf("next-wait:\t%s\n", msg); 15 | fflush(stdout); 16 | } 17 | void log_warning(char* msg) { 18 | printf("next-wait [WARNING]:\t%s\n", msg); 19 | fflush(stdout); 20 | } 21 | void log_error(char* msg, int signal) { 22 | fprintf(stderr, "next-wait [ERROR]:\t%s\n", msg); 23 | exit(signal); 24 | } 25 | void find_net_error() { 26 | switch (errno) { 27 | case EWOULDBLOCK: 28 | log_error("Timeout error", 1); 29 | break; 30 | case EBADF: 31 | log_error("Invalid file descriptor for socket", 1); 32 | break; 33 | case ECONNREFUSED: 34 | log_error("Remote host refused network connection.", 1); 35 | break; 36 | case EFAULT: 37 | log_error("Buffer pointers are not own.", 1); 38 | break; 39 | case EINTR: 40 | log_error("Receive is interrupted by signal.", 1); 41 | break; 42 | case EINVAL: 43 | log_error("Invalid argument", 1); 44 | break; 45 | case ENOMEM: 46 | log_error("Could not allocate memory", 1); 47 | break; 48 | default: 49 | log_error("Other error", 1); 50 | break; 51 | } 52 | } 53 | int main(int argc, char* argv[]) { 54 | uint8_t verbose = 0, 55 | debug = 0; 56 | uint16_t s_port; 57 | struct sockaddr_in server_addr, client_addr; 58 | struct hostent *he; 59 | struct timeval timeout; 60 | int sockfd, n, len = sizeof(server_addr); 61 | while((n = getopt(argc, argv, "vdh")) != -1) { 62 | if (n=='v') { 63 | verbose = 1; 64 | } else if (n=='d') { 65 | debug = 1; 66 | } else if (n=='h') { 67 | printf("\t%s\n", ""); 68 | printf("\t%s\n", "./next-wait [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT"); 69 | printf("\t%s\n", "==========================================================="); 70 | printf("\t%s\n", ""); 71 | printf("\t%s\n", "OPTIONS:"); 72 | printf("\t%s\n", "-v (Verbose)\t- to print actions"); 73 | printf("\t%s\n", "-d (Debug)\t- to print warnings"); 74 | printf("\t%s\n", "-h (Help)\t- to print help page"); 75 | printf("\t%s\n", ""); 76 | printf("\t%s\n", "ARGUMENTS:"); 77 | printf("\t%s\n", "REQUEST_HOST\t- service name or network host for the container for which this one is waiting"); 78 | printf("\t%s\n", "REQUEST_PORT\t- port for the container for which this one is waiting"); 79 | printf("\t%s\n", ""); 80 | exit(0); 81 | } else { 82 | exit(1); 83 | } 84 | } 85 | if (argc-optind!=2) { 86 | log_error("usage: ./next-wait [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT", 1); 87 | } 88 | if ((n = atoi(argv[optind+1])) == 0) { 89 | log_error("Second argument is not readable port number.", 1); 90 | } else if (n<0 || n>25535) { 91 | log_error("Second argument is invalid sending port.", 1); 92 | } else { 93 | s_port = (uint16_t)n; 94 | } 95 | 96 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) { 97 | log_error("Cannot create sending socket", EXIT_FAILURE); 98 | } 99 | timeout.tv_sec = 60; 100 | timeout.tv_usec = 0; 101 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 102 | log_error("Cannot set socket options", EXIT_FAILURE); 103 | } 104 | 105 | if ((he = gethostbyname(argv[optind]))==NULL) { 106 | log_error("Cannot resolve hostname", EXIT_FAILURE); 107 | } 108 | memset(&server_addr, 0, sizeof(server_addr)); 109 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 110 | server_addr.sin_family = AF_INET; 111 | server_addr.sin_port = htons(s_port); 112 | 113 | relayItemType buffer, msg; 114 | if (verbose||debug) log_msg("Waiting for ready reply"); 115 | while (1) { 116 | memset(&client_addr, 0, sizeof(client_addr)); 117 | msg = FIND_MSG; 118 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 119 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 120 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 121 | if (debug) log_warning("Timed-out waiting for ready"); 122 | } else if (n < 0) { 123 | find_net_error(); 124 | } else if (n == 0) { 125 | if (debug) log_warning("No data read"); 126 | } else if (buffer==READY_MSG&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 127 | if (verbose||debug) log_msg("Wait is done."); 128 | break; 129 | } else if (debug) { 130 | log_warning("Data unknown"); 131 | } 132 | } 133 | 134 | close(sockfd); 135 | return 0; 136 | } -------------------------------------------------------------------------------- /container_B/relay.h: -------------------------------------------------------------------------------- 1 | #ifndef RELAY_h 2 | #define RELAY_h 1 3 | 4 | #define MAX_REQUESTS 10 5 | 6 | enum relayMessage{ 7 | FIND_MSG = 100, 8 | READY_MSG, 9 | CLOSE_MSG, 10 | CLOSING_MSG, 11 | CONFIRM_MSG 12 | }; 13 | typedef enum relayMessage relayItemType; 14 | 15 | #endif -------------------------------------------------------------------------------- /container_B/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./next-wait "container-a" $OTHER_PORT 4 | 5 | # run commands 6 | 7 | ./next-pass "container-a" $OTHER_PORT $MY_PORT 8 | 9 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | services: 3 | container-a: 4 | build: container_A/. 5 | container-b: 6 | depends_on: 7 | - container-a 8 | build: container_B/. 9 | -------------------------------------------------------------------------------- /src/first.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "relay.h" 12 | 13 | void log_msg(char* msg) { 14 | printf("first:\t%s\n", msg); 15 | fflush(stdout); 16 | } 17 | void log_warning(char* msg) { 18 | printf("first [WARNING]:\t%s\n", msg); 19 | fflush(stdout); 20 | } 21 | void log_error(char* msg, int signal) { 22 | fprintf(stderr, "first [ERROR]:\t%s\n", msg); 23 | exit(signal); 24 | } 25 | void find_net_error() { 26 | switch (errno) { 27 | case EWOULDBLOCK: 28 | log_error("Timeout error", 1); 29 | break; 30 | case EBADF: 31 | log_error("Invalid file descriptor for socket", 1); 32 | break; 33 | case ECONNREFUSED: 34 | log_error("Remote host refused network connection.", 1); 35 | break; 36 | case EFAULT: 37 | log_error("Buffer pointers are not own.", 1); 38 | break; 39 | case EINTR: 40 | log_error("Receive is interrupted by signal.", 1); 41 | break; 42 | case EINVAL: 43 | log_error("Invalid argument", 1); 44 | break; 45 | case ENOMEM: 46 | log_error("Could not allocate memory", 1); 47 | break; 48 | default: 49 | log_error("Other error", 1); 50 | break; 51 | } 52 | } 53 | 54 | int main(int argc, char* argv[]) { 55 | uint8_t verbose = 0, 56 | debug = 0, 57 | closing = 0; 58 | uint16_t l_port, s_port; 59 | struct sockaddr_in server_addr, client_addr; 60 | struct hostent *he; 61 | int n, sockfd, len = sizeof(server_addr); 62 | relayItemType buffer, msg; 63 | while((n=getopt(argc, argv, "vdh")) != -1) { 64 | if (n=='v') { 65 | verbose = 1; 66 | } else if (n=='d') { 67 | debug = 1; 68 | } else if (n=='h') { 69 | printf("\t%s\n", ""); 70 | printf("\t%s\n", "./first [-v] [-d] [-h] MY_PORT [NEXT_HOST NEXT_PORT]"); 71 | printf("\t%s\n", "==========================================================="); 72 | printf("\t%s\n", ""); 73 | printf("\t%s\n", "OPTIONS:"); 74 | printf("\t%s\n", "-v (Verbose)\t- to print actions"); 75 | printf("\t%s\n", "-d (Debug)\t- to print warnings"); 76 | printf("\t%s\n", "-h (Help)\t- to print help page"); 77 | printf("\t%s\n", ""); 78 | printf("\t%s\n", "ARGUMENTS:"); 79 | printf("\t%s\n", "MY_PORT\t\t- this container or program port"); 80 | printf("\t%s\n", "NEXT_HOST\t- service name or network host name from which this program is expecting a close request"); 81 | printf("\t%s\n", "NEXT_PORT\t- port from which this program is expecting a close request"); 82 | printf("\t%s\n", ""); 83 | exit(0); 84 | } else { 85 | exit(1); 86 | } 87 | } 88 | if (argc-optind!=1&&argc-optind!=3) { 89 | log_error("usage: ./first [-v] [-d] [-h] MY_PORT [NEXT_HOST NEXT_PORT]", 1); 90 | } 91 | if ((n=atoi(argv[optind]))==0) { 92 | log_error("First argument is not readable port number.", 1); 93 | } else if (n<0||n>25535) { 94 | log_error("First argument is invalid listening port.", 1); 95 | } else { 96 | l_port = (uint16_t)n; 97 | } 98 | if (argc-optind==3) { 99 | closing = 1; 100 | if ((n = atoi(argv[optind+2])) == 0) { 101 | log_error("Third argument is not readable port number.", 1); 102 | } else if (n<0||n>25535) { 103 | log_error("Third argument is invalid sending port.", 1); 104 | } else { 105 | s_port = (uint16_t)n; 106 | } 107 | } 108 | 109 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) { 110 | log_error("Cannot create listening socket", EXIT_FAILURE); 111 | } 112 | memset(&server_addr, 0, sizeof(server_addr)); 113 | server_addr.sin_family = AF_INET; 114 | server_addr.sin_addr.s_addr = INADDR_ANY; 115 | server_addr.sin_port = htons(l_port); 116 | if (bind(sockfd, (const struct sockaddr*)&server_addr, sizeof(server_addr))<0) { 117 | log_error("Cannot bind socket to network address", EXIT_FAILURE); 118 | } 119 | if (closing==1&&(he = gethostbyname(argv[optind+1]))==NULL) { 120 | log_error("Cannot resolve hostname", EXIT_FAILURE); 121 | } 122 | 123 | if (verbose||debug) log_msg("Preparing to pass ready signal."); 124 | while (1) { 125 | memset(&client_addr, 0, sizeof(client_addr)); 126 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 127 | if (n<0) { 128 | find_net_error(); 129 | } else if (n==0) { 130 | if (debug) log_warning("No data read"); 131 | } else if (buffer==FIND_MSG) { 132 | msg = READY_MSG; 133 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, len); 134 | if (verbose||debug) log_msg("Sent ready signal"); 135 | } else if (buffer==CLOSE_MSG&&closing==1&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 136 | struct timeval timeout; 137 | timeout.tv_sec = 5; 138 | timeout.tv_usec = 0; 139 | if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 140 | log_error("Cannot set socket options", EXIT_FAILURE); 141 | } 142 | 143 | memset(&server_addr, 0, sizeof(server_addr)); 144 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 145 | server_addr.sin_family = AF_INET; 146 | server_addr.sin_port = htons(s_port); 147 | 148 | uint8_t attempts = 0; 149 | if (verbose||debug) log_msg("Preparing pass"); 150 | while (1) { 151 | memset(&client_addr, 0, sizeof(client_addr)); 152 | msg = CLOSING_MSG; 153 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 154 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 155 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 156 | attempts += 1; 157 | if (attempts==MAX_REQUESTS) { 158 | log_error("Max closing messages reached", 1); 159 | } else if (debug) { 160 | log_warning("Timed-out waiting for close confirm"); 161 | } 162 | } else { 163 | attempts = 0; 164 | if (n < 0) { 165 | find_net_error(); 166 | } else if (n == 0) { 167 | if (debug) log_warning("No data read"); 168 | } else if (buffer==FIND_MSG) { 169 | msg = READY_MSG; 170 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, len); 171 | if (verbose||debug) log_msg("Sent ready signal"); 172 | } else if (buffer==CONFIRM_MSG&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 173 | if (verbose||debug) log_msg("Closing"); 174 | break; 175 | } else if (buffer==CONFIRM_MSG) { 176 | if (debug) log_warning("Received unexpected close confirm"); 177 | } else if (debug) { 178 | log_warning("Data unknown"); 179 | } 180 | } 181 | } 182 | break; 183 | } else if (buffer==CLOSE_MSG) { 184 | if (debug) log_warning("Received unexpected close request"); 185 | } else if (debug) { 186 | if (debug) log_warning("Data unknown"); 187 | } 188 | } 189 | 190 | close(sockfd); 191 | 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /src/next-pass.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "relay.h" 12 | 13 | void log_msg(char* msg) { 14 | printf("next-pass:\t%s\n", msg); 15 | fflush(stdout); 16 | } 17 | void log_warning(char* msg) { 18 | printf("next-pass [WARNING]:\t%s\n", msg); 19 | fflush(stdout); 20 | } 21 | void log_error(char* msg, int signal) { 22 | fprintf(stderr, "next-pass [ERROR]:\t%s\n", msg); 23 | exit(signal); 24 | } 25 | void find_net_error() { 26 | switch (errno) { 27 | case EWOULDBLOCK: 28 | log_error("Timeout error", 1); 29 | break; 30 | case EBADF: 31 | log_error("Invalid file descriptor for socket", 1); 32 | break; 33 | case ECONNREFUSED: 34 | log_error("Remote host refused network connection.", 1); 35 | break; 36 | case EFAULT: 37 | log_error("Buffer pointers are not own.", 1); 38 | break; 39 | case EINTR: 40 | log_error("Receive is interrupted by signal.", 1); 41 | break; 42 | case EINVAL: 43 | log_error("Invalid argument", 1); 44 | break; 45 | case ENOMEM: 46 | log_error("Could not allocate memory", 1); 47 | break; 48 | default: 49 | log_error("Other error", 1); 50 | break; 51 | } 52 | } 53 | int main(int argc, char* argv[]) { 54 | uint8_t verbose = 0, 55 | debug = 0, 56 | closing = 0, 57 | attempts = 0; 58 | uint16_t c_port, l_port, s_port; 59 | relayItemType buffer, msg; 60 | struct sockaddr_in server_addr, client_addr; 61 | struct hostent *he; 62 | struct in_addr close_host; 63 | int sockfd, n, len = sizeof(server_addr); 64 | while((n = getopt(argc, argv, "vdh")) != -1) { 65 | if (n=='v') { 66 | verbose = 1; 67 | } else if (n=='d') { 68 | debug = 1; 69 | } else if (n=='h') { 70 | printf("\t%s\n", ""); 71 | printf("\t%s\n", "./next-pass [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT MY_PORT [NEXT_HOST NEXT_PORT]"); 72 | printf("\t%s\n", "==========================================================="); 73 | printf("\t%s\n", ""); 74 | printf("\t%s\n", "OPTIONS:"); 75 | printf("\t%s\n", "-v (Verbose)\t- to print actions"); 76 | printf("\t%s\n", "-d (Debug)\t- to print warnings"); 77 | printf("\t%s\n", "-h (Help)\t- to print help page"); 78 | printf("\t%s\n", ""); 79 | printf("\t%s\n", "ARGUMENTS:"); 80 | printf("\t%s\n", "REQUEST_HOST\t- service name (or network host) to which this program is requesting a shut down"); 81 | printf("\t%s\n", "REQUEST_PORT\t- port to which this program is requesting a shut down"); 82 | printf("\t%s\n", "MY_PORT\t\t- this container or program port"); 83 | printf("\t%s\n", "NEXT_HOST\t- service name (or network host) from which this program is expecting a close request"); 84 | printf("\t%s\n", "NEXT_PORT\t- port from which this program is expecting a close request"); 85 | printf("\t%s\n", ""); 86 | exit(0); 87 | } else { 88 | exit(1); 89 | } 90 | } 91 | if (argc-optind!=3&&argc-optind!=5) { 92 | log_error("usage: ./next-pass [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT MY_PORT [NEXT_HOST NEXT_PORT]", 1); 93 | } 94 | if ((n = atoi(argv[optind+1])) == 0) { 95 | log_error("Second argument is not readable port number.", 1); 96 | } else if (n<0 || n>25535) { 97 | log_error("Second argument is invalid sending port.", 1); 98 | } else { 99 | c_port = (uint16_t)n; 100 | } 101 | if ((n = atoi(argv[optind+2])) == 0) { 102 | log_error("Third argument is not readable port number.", 1); 103 | } else if (n<0 || n>25535) { 104 | log_error("Third argument is invalid sending port.", 1); 105 | } else { 106 | l_port = (uint16_t)n; 107 | } 108 | if (argc-optind==5) { 109 | closing = 1; 110 | if ((n = atoi(argv[optind+4])) == 0) { 111 | log_error("Fifth argument is not readable port number.", 1); 112 | } else if (n<0 || n>25535) { 113 | log_error("Fifth argument is invalid sending port.", 1); 114 | } else { 115 | s_port = (uint16_t)n; 116 | } 117 | } 118 | 119 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) { 120 | log_error("Cannot create sending socket", EXIT_FAILURE); 121 | } 122 | struct timeval timeout; 123 | timeout.tv_sec = 5; 124 | timeout.tv_usec = 0; 125 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 126 | log_error("Cannot set socket options", EXIT_FAILURE); 127 | } 128 | memset(&client_addr, 0, sizeof(client_addr)); 129 | client_addr.sin_family = AF_INET; 130 | client_addr.sin_port = htons(l_port); 131 | client_addr.sin_addr.s_addr = INADDR_ANY; 132 | if (bind(sockfd, (const struct sockaddr*)&client_addr, sizeof(client_addr))<0) { 133 | log_error("Cannot bind socket to network address", EXIT_FAILURE); 134 | } 135 | 136 | if ((he = gethostbyname(argv[optind]))==NULL) { 137 | log_error("Cannot resolve hostname", EXIT_FAILURE); 138 | } 139 | memset(&server_addr, 0, sizeof(server_addr)); 140 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 141 | server_addr.sin_family = AF_INET; 142 | server_addr.sin_port = htons(c_port); 143 | memcpy(&close_host, he->h_addr_list[0], he->h_length); 144 | if (closing==1&&(he = gethostbyname(argv[optind+3]))==NULL) { 145 | log_error("Cannot resolve hostname", EXIT_FAILURE); 146 | } 147 | 148 | if (verbose||debug) log_msg("Sending request to close"); 149 | while (1) { 150 | memset(&client_addr, 0, sizeof(client_addr)); 151 | msg = CLOSE_MSG; 152 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 153 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 154 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 155 | attempts += 1; 156 | if (attempts==MAX_REQUESTS) { 157 | log_error("Max requests reached", 1); 158 | } else if (debug) { 159 | log_warning("Timed-out waiting for closing message"); 160 | } 161 | } else { 162 | attempts = 0; 163 | if (n < 0) { 164 | find_net_error(); 165 | } else if (n == 0) { 166 | if (debug) log_warning("No data read"); 167 | } else if (buffer==CLOSING_MSG&&memcmp(&client_addr.sin_addr, &close_host, sizeof(close_host))==0&&ntohs(client_addr.sin_port)==c_port) { 168 | log_msg("Got closing msg"); 169 | msg = CONFIRM_MSG; 170 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, sizeof(client_addr)); 171 | 172 | timeout.tv_sec = 0; 173 | timeout.tv_usec = 0; 174 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 175 | log_error("Cannot set socket options", EXIT_FAILURE); 176 | } 177 | 178 | if (verbose||debug) log_msg("Now am holding queue"); 179 | while (1) { 180 | memset(&client_addr, 0, sizeof(client_addr)); 181 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 182 | if (n<0) { 183 | find_net_error(); 184 | } else if (n==0) { 185 | if (debug) log_warning("No data read"); 186 | } else if (buffer==FIND_MSG) { 187 | msg = READY_MSG; 188 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, len); 189 | if (verbose||debug) log_msg("Sent ready signal"); 190 | } else if (buffer==CLOSING_MSG&&memcmp(&client_addr.sin_addr, &close_host, sizeof(close_host))==0&&ntohs(client_addr.sin_port)==c_port) { 191 | msg = CONFIRM_MSG; 192 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&client_addr, sizeof(client_addr)); 193 | } else if (buffer==CLOSING_MSG) { 194 | if (debug) log_warning("Received unexpected closing message"); 195 | } else if (buffer==CLOSE_MSG&&closing==1&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], sizeof(he->h_length))==0&&ntohs(client_addr.sin_port)==s_port) { 196 | 197 | timeout.tv_sec = 5; 198 | timeout.tv_usec = 0; 199 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 200 | log_error("Cannot set socket options", EXIT_FAILURE); 201 | } 202 | 203 | memset(&server_addr, 0, sizeof(server_addr)); 204 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 205 | server_addr.sin_family = AF_INET; 206 | server_addr.sin_port = htons(s_port); 207 | 208 | if (verbose||debug) log_msg("Preparing pass"); 209 | while (1) { 210 | memset(&client_addr, 0, sizeof(client_addr)); 211 | msg = CLOSING_MSG; 212 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 213 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 214 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 215 | attempts += 1; 216 | if (attempts==MAX_REQUESTS) { 217 | log_error("Max close confirm requests reached", 1); 218 | } else if (debug) { 219 | log_warning("Timed-out waiting for close confirm"); 220 | } 221 | } else { 222 | attempts = 0; 223 | if (n < 0) { 224 | find_net_error(); 225 | } else if (n == 0) { 226 | if (debug) log_warning("No data read"); 227 | } else if (buffer==CONFIRM_MSG&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 228 | if (verbose||debug) log_msg("Closing"); 229 | break; 230 | } else if (buffer==CONFIRM_MSG) { 231 | if (debug) log_warning("Received unexpected close confirm"); 232 | } else if (debug) { 233 | log_warning("Data unknown"); 234 | } 235 | } 236 | } 237 | break; 238 | } else if (debug) { 239 | log_warning("Data unknown"); 240 | } 241 | } 242 | break; 243 | } else if (buffer==CLOSING_MSG) { 244 | if (debug) log_warning("Received unexpected closing message"); 245 | } else if (debug) { 246 | log_warning("Data unknown"); 247 | } 248 | } 249 | } 250 | 251 | close(sockfd); 252 | return 0; 253 | } -------------------------------------------------------------------------------- /src/next-wait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "relay.h" 12 | 13 | void log_msg(char* msg) { 14 | printf("next-wait:\t%s\n", msg); 15 | fflush(stdout); 16 | } 17 | void log_warning(char* msg) { 18 | printf("next-wait [WARNING]:\t%s\n", msg); 19 | fflush(stdout); 20 | } 21 | void log_error(char* msg, int signal) { 22 | fprintf(stderr, "next-wait [ERROR]:\t%s\n", msg); 23 | exit(signal); 24 | } 25 | void find_net_error() { 26 | switch (errno) { 27 | case EWOULDBLOCK: 28 | log_error("Timeout error", 1); 29 | break; 30 | case EBADF: 31 | log_error("Invalid file descriptor for socket", 1); 32 | break; 33 | case ECONNREFUSED: 34 | log_error("Remote host refused network connection.", 1); 35 | break; 36 | case EFAULT: 37 | log_error("Buffer pointers are not own.", 1); 38 | break; 39 | case EINTR: 40 | log_error("Receive is interrupted by signal.", 1); 41 | break; 42 | case EINVAL: 43 | log_error("Invalid argument", 1); 44 | break; 45 | case ENOMEM: 46 | log_error("Could not allocate memory", 1); 47 | break; 48 | default: 49 | log_error("Other error", 1); 50 | break; 51 | } 52 | } 53 | int main(int argc, char* argv[]) { 54 | uint8_t verbose = 0, 55 | debug = 0; 56 | uint16_t s_port; 57 | struct sockaddr_in server_addr, client_addr; 58 | struct hostent *he; 59 | struct timeval timeout; 60 | int sockfd, n, len = sizeof(server_addr); 61 | while((n = getopt(argc, argv, "vdh")) != -1) { 62 | if (n=='v') { 63 | verbose = 1; 64 | } else if (n=='d') { 65 | debug = 1; 66 | } else if (n=='h') { 67 | printf("\t%s\n", ""); 68 | printf("\t%s\n", "./next-wait [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT"); 69 | printf("\t%s\n", "==========================================================="); 70 | printf("\t%s\n", ""); 71 | printf("\t%s\n", "OPTIONS:"); 72 | printf("\t%s\n", "-v (Verbose)\t- to print actions"); 73 | printf("\t%s\n", "-d (Debug)\t- to print warnings"); 74 | printf("\t%s\n", "-h (Help)\t- to print help page"); 75 | printf("\t%s\n", ""); 76 | printf("\t%s\n", "ARGUMENTS:"); 77 | printf("\t%s\n", "REQUEST_HOST\t- service name or network host for the container for which this one is waiting"); 78 | printf("\t%s\n", "REQUEST_PORT\t- port for the container for which this one is waiting"); 79 | printf("\t%s\n", ""); 80 | exit(0); 81 | } else { 82 | exit(1); 83 | } 84 | } 85 | if (argc-optind!=2) { 86 | log_error("usage: ./next-wait [-v] [-d] [-h] REQUEST_HOST REQUEST_PORT", 1); 87 | } 88 | if ((n = atoi(argv[optind+1])) == 0) { 89 | log_error("Second argument is not readable port number.", 1); 90 | } else if (n<0 || n>25535) { 91 | log_error("Second argument is invalid sending port.", 1); 92 | } else { 93 | s_port = (uint16_t)n; 94 | } 95 | 96 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) { 97 | log_error("Cannot create sending socket", EXIT_FAILURE); 98 | } 99 | timeout.tv_sec = 60; 100 | timeout.tv_usec = 0; 101 | if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))<0) { 102 | log_error("Cannot set socket options", EXIT_FAILURE); 103 | } 104 | 105 | if ((he = gethostbyname(argv[optind]))==NULL) { 106 | log_error("Cannot resolve hostname", EXIT_FAILURE); 107 | } 108 | memset(&server_addr, 0, sizeof(server_addr)); 109 | memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length); 110 | server_addr.sin_family = AF_INET; 111 | server_addr.sin_port = htons(s_port); 112 | 113 | relayItemType buffer, msg; 114 | if (verbose||debug) log_msg("Waiting for ready reply"); 115 | while (1) { 116 | memset(&client_addr, 0, sizeof(client_addr)); 117 | msg = FIND_MSG; 118 | sendto(sockfd, &msg, sizeof(msg), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); 119 | n = recvfrom(sockfd, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr*)&client_addr, &len); 120 | if (n==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { 121 | if (debug) log_warning("Timed-out waiting for ready"); 122 | } else if (n < 0) { 123 | find_net_error(); 124 | } else if (n == 0) { 125 | if (debug) log_warning("No data read"); 126 | } else if (buffer==READY_MSG&&memcmp(&client_addr.sin_addr, he->h_addr_list[0], he->h_length)==0&&ntohs(client_addr.sin_port)==s_port) { 127 | if (verbose||debug) log_msg("Wait is done."); 128 | break; 129 | } else if (debug) { 130 | log_warning("Data unknown"); 131 | } 132 | } 133 | 134 | close(sockfd); 135 | return 0; 136 | } -------------------------------------------------------------------------------- /src/relay.h: -------------------------------------------------------------------------------- 1 | #ifndef RELAY_h 2 | #define RELAY_h 1 3 | 4 | #define MAX_REQUESTS 10 5 | 6 | enum relayMessage{ 7 | FIND_MSG = 100, 8 | READY_MSG, 9 | CLOSE_MSG, 10 | CLOSING_MSG, 11 | CONFIRM_MSG 12 | }; 13 | typedef enum relayMessage relayItemType; 14 | 15 | #endif --------------------------------------------------------------------------------