58a3a3d276a8310bd95b8ec7475046d2610a372a
[ric-plt/lib/rmr.git] / src / rmr / si / src / si95 / siaddress.c
1 // vim: noet sw=4 ts=4:
2 /*
3 ==================================================================================
4     Copyright (c) 2020 Nokia
5     Copyright (c) 2020 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 **************************************************************************
23 *
24 *  Mnemonic: SIaddress
25 *  Abstract: This routine will convert a sockaddr_in structure to a
26 *            dotted decimal address, or visa versa.
27 *            If type == AC_TOADDR the src string may be: 
28 *            xxx.xxx.xxx.xxx.portnumber or host-name.portnumber
29 *            xxx.xxx.xxx.xxx.service[.protocol] or hostname;service[;protocol]
30 *            if protocol is not supplied then tcp is assumed.
31 *            hostname may be something like godzilla.moviemania.com
32 *  Parms:    src - Pointer to source buffer
33 *            dest- Pointer to dest buffer pointer 
34 *            type- Type of conversion AC_TODOT converts sockaddr to human readable. AC_TOADDR 
35 *                               converts character buffer to sockaddr.
36 *  Returns:  Nothing.
37 *  Date:     19 January 1995
38 *  Author:   E. Scott Daniels
39 *
40 *  Modified: 22 Mar 1995 - To add support for ipx addresses.
41 *                       18 Oct 2020 - drop old port separator (;)
42 *
43 *  CAUTION: The netdb.h header file is a bit off when it sets up the 
44 *           hostent structure. It claims that h_addr_list is a pointer 
45 *           to character pointers, but it is really a pointer to a list 
46 *           of pointers to integers!!!
47 *       
48 ***************************************************************************
49 */
50 #include "sisetup.h"      //  get necessary defs and other stuff 
51 #include <netdb.h>
52 #include <stdio.h>
53 #include <ctype.h>
54
55 /* 
56         target: buffer with address  e.g.  192.168.0.1:4444  :4444 (listen) [::1]4444
57         family: PF_INET[6]  (let it be 0 to select based on addr in buffer 
58         proto: IPPROTO_TCP IPPROTO_UDP
59         type:   SOCK_STREAM SOCK_DGRAM
60
61         returns length of struct pointed to by rap (return addr blockpointer)
62 */
63 extern int SIgenaddr( char *target, int proto, int family, int socktype, struct sockaddr **rap ) {
64         struct addrinfo hint;                           //  hints to give getaddrinfo 
65         struct addrinfo *list = NULL;           //  list of what comes back 
66         int     ga_flags = 0;                                   //  flags to pass to getaddrinfo in hints 
67         int     error = 0;
68         int     rlen = 0;                                               //  length of the addr that rap points to on return 
69         char    *pstr;                                          //  port string 
70         char    *dstr;                                          //  a copy of the users target that we can destroy 
71         char*   fptr;                                           // ptr we allocated and need to free (we may adjust dstr)
72
73     fptr = dstr = strdup( (char *) target );    //  copy so we can destroy it with strtok 
74         *rap = NULL;                                            //  ensure null incase something breaks 
75
76         while( isspace( *dstr ) ) {
77                 dstr++;
78         }
79
80         if( *dstr == ':' ) {            //  user passed in :port -- so we assume this is for bind 
81                 pstr = dstr;
82                 *(pstr++) = 0;
83
84                 ga_flags = AI_PASSIVE;
85         } else {
86                 if( *dstr == '[' ) {                            // strip [ and ] from v6 and point pstring if port there
87                         dstr++;
88                         pstr = strchr( dstr, ']' );
89                         if( *pstr != ']' ) {
90                                 return -1;
91                         }
92
93                         *(pstr++) = 0;
94                         if( *pstr == ':' ) {
95                                 *(pstr++) = 0;
96                         } else {
97                                 pstr = NULL;
98                         }
99                 } else {                                                        // assume name or v4; point at port if there
100                         pstr = strchr( dstr, ':' );
101                         if( pstr != NULL ) {
102                                 *(pstr++) = 0;
103                         }
104                 }
105                 ga_flags = AI_ADDRCONFIG;                       // don't return IPVx addresses unless one such address is configured
106         }
107
108         memset( &hint, 0, sizeof( hint  ) );
109         hint.ai_family = family;                        //  AF_INET AF_INET6...  let this be 0 to select best based on addr 
110         hint.ai_socktype = socktype;            //  SOCK_DGRAM SOCK_STREAM 
111         hint.ai_protocol = proto;                       //  IPPORTO_TCP IPPROTO_UDP 
112         hint.ai_flags = ga_flags;
113
114         if( DEBUG ) 
115                 rmr_vlog( RMR_VL_DEBUG, "siaddress: calling getaddrinfo flags=%x proto=%d family=%d target=%s host=%s port=%s\n", 
116                                 ga_flags, proto, family, target, dstr, pstr );
117
118         if( (error = getaddrinfo( dstr, pstr, &hint, &list )) ) {
119                 fprintf( stderr, "error from getaddrinfo: target=%s host=%s port=%s(port): error=(%d) %s\n", target, dstr, pstr, error, gai_strerror( error ) );
120         } else {
121                 *rap = (struct sockaddr *) malloc(  list->ai_addrlen );         //  alloc a buffer and give address to caller 
122                 memcpy( *rap, list->ai_addr, list->ai_addrlen  );
123
124                 rlen = list->ai_addrlen;
125                 
126                 freeaddrinfo( list );           //  ditch system allocated memory 
127         }
128
129         free( dstr );
130         return rlen;
131 }
132
133
134 /* 
135         Given a source address convert from one form to another based on type constant.
136         Type const == AC_TODOT   Convert source address structure to human readable string.
137         Type const == AC_TOADDR6 Convert source string (host:port or ipv6 address [n:n...:n]:port) to an address struct
138         Type const == AC_TOADDR  Convert source string (host:port or ipv4 dotted decimal address) to an address struct
139 */
140 extern int SIaddress( void *src, void **dest, int type ) {
141         struct sockaddr_in *addr;       //  pointer to the address 
142         unsigned char *num;             //  pointer at the address number 
143         char wbuf[256];                 //  work buffer 
144         int i;         
145         int     rlen = 0;                                       //  return len - len of address struct or string
146
147         switch( type ) {
148                 case AC_TODOT:                                  //  convert from a struct to human readable "dotted decimal"
149                         addr = (struct sockaddr_in *) src;
150                         num = (char *) &addr->sin_addr.s_addr;    //  point at the long 
151
152                         if( addr->sin_family == AF_INET6 ) {
153                                 sprintf( wbuf, "[%u:%u:%u:%u:%u:%u]:%d", 
154                                                 *(num+0), *(num+1), *(num+2), 
155                                                 *(num+3), *(num+4), *(num+5) , 
156                                                 (int) ntohs( addr->sin_port ) );
157                         } else {
158                                 sprintf( wbuf, "%u.%u.%u.%u;%d", *(num+0), *(num+1), *(num+2), *(num+3), (int) ntohs(addr->sin_port) );
159                         }
160
161                         *dest = (void *) strdup( wbuf );
162                         rlen = strlen( *dest );
163                         break;
164
165                 case AC_TOADDR6:                        //  from hostname;port string to address for send etc 
166                         return SIgenaddr( src, PF_INET6, IPPROTO_TCP, SOCK_STREAM, (struct sockaddr **) dest );
167                         break; 
168
169                 case AC_TOADDR:                         //  from dotted decimal to address struct ip4 
170                         return SIgenaddr( src, PF_INET, IPPROTO_TCP, SOCK_STREAM, (struct sockaddr **) dest );
171                         break;
172         }
173
174         return rlen;
175 }
176