E. Scott Daniels | 8761b5d | 2019-08-09 15:37:48 -0400 | [diff] [blame] | 1 | // :vim ts=4 sw=4 noet: |
| 2 | /* |
| 3 | ================================================================================== |
| 4 | Copyright (c) 2019 Nokia |
| 5 | Copyright (c) 2018-2019 AT&T Intellectual Property. |
| 6 | |
| 7 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | you may not use this file except in compliance with the License. |
| 9 | You may obtain a copy of the License at |
| 10 | |
| 11 | http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | |
| 13 | Unless required by applicable law or agreed to in writing, software |
| 14 | distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | See the License for the specific language governing permissions and |
| 17 | limitations under the License. |
| 18 | ================================================================================== |
| 19 | */ |
| 20 | |
| 21 | /* |
| 22 | Mnemonic: msg_echo.c |
| 23 | Abstract: This is a simple message receiver which will echo the received |
| 24 | message back to the sender using an RMR return to sender call. |
| 25 | All of the message will be left unchanged, though the message type |
| 26 | may be changed by supplying it on the command line as the first |
| 27 | positional parameter. |
| 28 | |
| 29 | Because this process uses the rts call in RMR, it does not need |
| 30 | a route table. However, RMR needs to have at least an empty table |
| 31 | in order to work properly. To avoid having the user make a dummy |
| 32 | table, we will create an empty one in /tmp and set the needed |
| 33 | environment var so the RMR initialisation process finds it. |
| 34 | |
| 35 | Date: 9 August 2019 |
| 36 | Author: E. Scott Daniels |
| 37 | */ |
| 38 | |
| 39 | #include <unistd.h> |
| 40 | #include <errno.h> |
| 41 | #include <stdio.h> |
| 42 | #include <stdlib.h> |
| 43 | #include <time.h> |
| 44 | #include <string.h> |
| 45 | #include <fcntl.h> |
| 46 | |
| 47 | #include <rmr/rmr.h> |
| 48 | |
| 49 | /* |
| 50 | Create an empty route table and set an environment var for RMR to find. |
| 51 | This must be called before initialising RMR. |
| 52 | */ |
| 53 | static void mk_rt( ) { |
| 54 | int fd; |
| 55 | char fnb[128]; |
| 56 | char* contents = "newrt|start\nnewrt|end\n"; |
| 57 | |
| 58 | snprintf( fnb, sizeof( fnb ), "/tmp/msg_echo.rt" ); |
| 59 | fd = open( fnb, O_CREAT | O_WRONLY, 0664 ); |
| 60 | if( fd < 0 ) { |
| 61 | fprintf( stderr, "[FAIL] could not create dummy route table: %s %s\n", fnb, strerror( errno ) ); |
| 62 | return; |
| 63 | } |
| 64 | |
| 65 | write( fd, contents, strlen( contents ) ); |
| 66 | if( (close( fd ) < 0 ) ) { |
| 67 | fprintf( stderr, "[FAIL] couldn't close dummy route table: %s: %s\n", fnb, strerror( errno ) ); |
| 68 | return; |
| 69 | } |
| 70 | |
| 71 | setenv( "RMR_SEED_RT", fnb, 0 ); // set it, but don't overwrite it |
| 72 | } |
| 73 | |
| 74 | int main( int argc, char** argv ) { |
| 75 | void* mrc; // msg router context |
| 76 | rmr_mbuf_t* msg = NULL; // message received |
| 77 | int i; |
| 78 | int state; |
| 79 | int errors = 0; |
| 80 | char* listen_port = "4560"; |
| 81 | long timeout = 0; |
| 82 | char* data; // pointer at env data we sussed out |
| 83 | char wbuf[1024]; // we'll pull trace data into here, and use as general working buffer |
| 84 | char sbuf[128]; // short buffer |
| 85 | int mtype = -1; // if set on command line, we'll add to msg before rts |
| 86 | int ai = 1; // argument index |
| 87 | |
| 88 | data = getenv( "RMR_RTG_SVC" ); |
| 89 | if( data == NULL ) { |
| 90 | setenv( "RMR_RTG_SVC", "19289", 1 ); // set one that won't collide with the sender if on same host |
| 91 | } |
| 92 | |
| 93 | // ---- simple arg parsing ------ |
| 94 | while( ai < argc ) { |
| 95 | if( *argv[ai] == '-' ) { |
| 96 | switch( argv[ai][1] ) { |
| 97 | case 'p': // timeout |
| 98 | ai++; |
| 99 | listen_port = argv[ai]; |
| 100 | break; |
| 101 | |
| 102 | case 't': // rts message type |
| 103 | ai++; |
| 104 | mtype = atoi( argv[ai] ); |
| 105 | break; |
| 106 | |
| 107 | default: |
| 108 | fprintf( stderr, "[FAIL] unrecognised option: %s\n", argv[ai] ); |
| 109 | fprintf( stderr, "\nusage: %s [-p port] [-t msg-type]\n", argv[0] ); |
| 110 | exit( 1 ); |
| 111 | } |
| 112 | |
| 113 | ai++; |
| 114 | } else { |
| 115 | break; // not an option, leave with a1 @ first positional parm |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | fprintf( stderr, "<ECHO> listening on port: %s will return messages with type: %d\n", listen_port, mtype ); |
| 120 | |
| 121 | mk_rt(); // make an empty rt |
| 122 | |
| 123 | mrc = rmr_init( listen_port, RMR_MAX_RCV_BYTES, RMRFL_NONE ); // start your engines! |
| 124 | if( mrc == NULL ) { |
| 125 | fprintf( stderr, "<ECHO> ABORT: unable to initialise RMr\n" ); |
| 126 | exit( 1 ); |
| 127 | } |
| 128 | |
| 129 | timeout = time( NULL ) + 20; |
| 130 | while( ! rmr_ready( mrc ) ) { // wait for RMr to configure the route table |
| 131 | fprintf( stderr, "<ECHO> waiting for RMr to show ready\n" ); |
| 132 | sleep( 1 ); |
| 133 | |
| 134 | if( time( NULL ) > timeout ) { |
| 135 | fprintf( stderr, "<ECHO> giving up\n" ); |
| 136 | exit( 1 ); |
| 137 | } |
| 138 | } |
| 139 | fprintf( stderr, "<ECHO> rmr now shows ready, listening begins\n" ); |
| 140 | |
| 141 | while( 1 ) { // listen until the cows come home, pigs fly... |
| 142 | msg = rmr_rcv_msg( mrc, msg ); |
| 143 | |
| 144 | if( msg && msg->state == RMR_OK ) { |
| 145 | if( mtype >= 0 ) { |
| 146 | msg->mtype = mtype; |
| 147 | msg->sub_id = RMR_VOID_SUBID; |
| 148 | } |
| 149 | |
| 150 | msg = rmr_rts_msg( mrc, msg ); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | return 0; // unreachable, but some compilers swak if this isn't here. |
| 155 | } |
| 156 | |