6533f339d735a53ff80bea55dfc271f9da7c056e
[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 || *pstr != ']' ) {
90                                 free( fptr );
91                                 return -1;
92                         }
93
94                         *(pstr++) = 0;
95                         if( *pstr == ':' ) {
96                                 *(pstr++) = 0;
97                         } else {
98                                 pstr = NULL;
99                         }
100                 } else {                                                        // assume name or v4; point at port if there
101                         pstr = strchr( dstr, ':' );
102                         if( pstr != NULL ) {
103                                 *(pstr++) = 0;
104                         }
105                 }
106                 ga_flags = AI_ADDRCONFIG;                       // don't return IPVx addresses unless one such address is configured
107         }
108
109         memset( &hint, 0, sizeof( hint  ) );
110         hint.ai_family = family;                        //  AF_INET AF_INET6...  let this be 0 to select best based on addr
111         hint.ai_socktype = socktype;            //  SOCK_DGRAM SOCK_STREAM
112         hint.ai_protocol = proto;                       //  IPPROTO_TCP IPPROTO_UDP
113         hint.ai_flags = ga_flags;
114
115         if( DEBUG )
116                 rmr_vlog( RMR_VL_DEBUG, "siaddress: calling getaddrinfo flags=%x sockty=%d proto=%d family=%d target=%s host=%s port=%s\n",
117                                 ga_flags, socktype, proto, family, target, dstr, pstr );
118
119         if( (error = getaddrinfo( dstr, pstr, &hint, &list )) ) {
120                 fprintf( stderr, "sigenaddr: error from getaddrinfo: target=%s host=%s port=%s(port): error=(%d) %s\n",
121                         target, dstr, pstr, error, gai_strerror( error ) );
122         } else {
123                 *rap = (struct sockaddr *) malloc(  list->ai_addrlen );         //  alloc a buffer and give address to caller
124                 memcpy( *rap, list->ai_addr, list->ai_addrlen  );
125
126                 rlen = list->ai_addrlen;
127
128                 freeaddrinfo( list );           //  ditch system allocated memory
129         }
130
131         free( fptr );
132         return rlen;
133 }
134
135
136 /*
137         Given a source address convert from one form to another based on type constant.
138         Type const == AC_TODOT   Convert source address structure to human readable string.
139         Type const == AC_TOADDR6 Convert source string (host:port or ipv6 address [n:n...:n]:port) to an address struct
140         Type const == AC_TOADDR  Convert source string (host:port or ipv4 dotted decimal address) to an address struct
141 */
142 extern int SIaddress( void *src, void **dest, int type ) {
143         struct sockaddr_in *addr;       //  pointer to the address
144         struct sockaddr_in6 *addr6;             // ip6 has a different layout
145         unsigned char *num;             //  pointer at the address number
146         uint8_t*        byte;                           //  pointer at the ipv6 address byte values
147         char wbuf[256];                 //  work buffer
148         int i;
149         int     rlen = 0;                                       //  return len - len of address struct or string
150
151         if( src == NULL || dest == NULL ) {
152                 return rlen;
153         }
154
155         switch( type ) {
156                 case AC_TODOT:                                  //  convert from a struct to human readable "dotted decimal"
157                         addr = (struct sockaddr_in *) src;
158
159                         if( addr->sin_family == AF_INET6 ) {
160                                 addr6 = (struct sockaddr_in6 *) src;                            // really an ip6 struct
161                                 byte = (uint8_t *) &addr6->sin6_addr;
162                         snprintf( wbuf, sizeof( wbuf ),  "[%u:%u:%u:%u:%u:%u]:%d",
163                                                 *(byte+0), *(byte+1), *(byte+2),
164                                                 *(byte+3), *(byte+4), *(byte+5) ,
165                                                 (int) ntohs( addr6->sin6_port ) );
166                         } else {
167                                 num = (char *) &addr->sin_addr.s_addr;    //  point at the long
168                                 snprintf( wbuf, sizeof( wbuf ),  "%u.%u.%u.%u;%d", *(num+0), *(num+1), *(num+2), *(num+3), (int) ntohs(addr->sin_port) );
169                         }
170
171                         *dest = (void *) strdup( wbuf );
172                         rlen = strlen( *dest );
173                         break;
174
175                 case AC_TOADDR6:                        //  from hostname:port string to address for send etc
176                         return SIgenaddr( src, IPPROTO_TCP, AF_INET6, SOCK_STREAM, (struct sockaddr **) dest );
177
178                 case AC_TOADDR:                         //  from dotted decimal to address struct ip4
179                         return SIgenaddr( src, IPPROTO_TCP, AF_INET, SOCK_STREAM, (struct sockaddr **) dest );
180         }
181
182         return rlen;
183 }
184