bignag change -- lot of things primarily added in relationship with
[sip-router] / modules / tm / uac.c
1 /*
2  * $Id$
3  *
4  * simple UAC for things such as SUBSCRIBE or SMS gateway;
5  * no authentication and other UAC features -- just send
6  * a message, retransmit and await a reply; forking is not
7  * supported during client generation, in all other places
8  * it is -- adding it should be simple
9  */
10
11 #include <stdlib.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <signal.h>
20 #include "../../dprint.h"
21 #include "../../ut.h"
22 #include "../../hash_func.h"
23 #include "../../md5utils.h"
24 #include "../../mem/mem.h"
25 #include "../../fifo_server.h"
26 #include "../../error.h"
27 #include "t_funcs.h"
28 #include "config.h"
29 #include "sip_msg.h"
30 #include "ut.h"
31 #include "t_msgbuilder.h"
32 #include "uac.h"
33
34 /* Call-ID has the following form: call_id_rand-pid-seq */
35
36 char call_id[RAND_DIGITS+1+MAX_PID_LEN+1+MAX_SEQ_LEN+1];
37 static unsigned long callid_seq;
38
39 char *uac_from="\"UAC Account\" <sip:uac@dev.null:9>";
40
41 char from_tag[ MD5_LEN +1];
42
43 void uac_init() {
44         unsigned long init_nr;
45         char *c;
46         int len;
47
48         str src[3];
49
50         init_nr=random() % (1<<(RAND_DIGITS*4));
51         c=call_id;
52         len=RAND_DIGITS;
53         int2reverse_hex( &c, &len, init_nr );
54         while (len) { *c='z'; len--; c++; }
55         *c='-';
56
57         src[0].s="Long live SER server";
58         src[0].len=strlen(src[0].s);
59         src[1].s=sock_info[0].address_str.s;
60         src[1].len=strlen(src[1].s);
61         src[2].s=sock_info[0].port_no_str.s;
62         src[2].len=strlen(src[2].s);
63
64         MDStringArray( from_tag, src, 3 );
65         from_tag[MD5_LEN]=0;
66 }
67
68
69 void uac_child_init( int rank ) {
70         int pid_nr;
71         char *c;
72         int len;
73
74         pid_nr=getpid() % (1<<(MAX_PID_LEN*4));
75         c=call_id+RAND_DIGITS+1;
76         len=MAX_PID_LEN;
77         int2reverse_hex( &c, &len, pid_nr );
78         while (len) { *c='z'; len--; c++; }
79         *c='-';
80
81         callid_seq=random() % TABLE_ENTRIES;
82
83 }
84
85 void generate_callid() {
86         char *c;
87         int len;
88
89         /* HACK: not long enough */
90         callid_seq = (callid_seq+1) % TABLE_ENTRIES;
91         c=call_id+RAND_DIGITS+1+MAX_PID_LEN+1;
92         len=MAX_SEQ_LEN;
93         int2reverse_hex( &c, &len, callid_seq );
94         while (len) { *c='z'; len--; c++; }
95 }
96
97
98
99 int t_uac( str *msg_type, str *dst, 
100         str *headers, str *body, transaction_cb completion_cb,
101         void *cbp, struct dialog *dlg)
102 {
103
104         struct cell *new_cell;
105         struct proxy_l *proxy;
106         int branch;
107         int ret;
108         int req_len;
109         char *buf;
110         union sockaddr_union to;
111         struct socket_info* send_sock;
112         struct retr_buf *request;
113
114         /* be optimist -- assume success for return value */
115         ret=1;
116
117         proxy=uri2proxy( dst );
118         if (proxy==0) {
119                 ser_error=ret=E_BAD_ADDRESS;
120                 LOG(L_ERR, "ERROR: t_uac: can't create a dst proxy\n");
121                 goto done;
122         }
123         branch=0;
124         /* might go away -- we ignore it in send_pr_buffer anyway */
125         /* T->uac[branch].request.to_len=sizeof(union sockaddr_union); */
126         hostent2su(&to, &proxy->host, proxy->addr_idx, 
127                 (proxy->port)?htons(proxy->port):htons(SIP_PORT));
128         send_sock=get_send_socket( &to );
129         if (send_sock==0) {
130                 LOG(L_ERR, "ERROR: t_uac: no corresponding listening socket "
131                         "for af %d\n", to.s.sa_family );
132                 ret=E_NO_SOCKET;
133                 goto error00;
134         }
135         generate_callid();
136
137         new_cell = build_cell( NULL ) ; 
138         if (!new_cell) {
139                 ret=E_OUT_OF_MEM;
140                 LOG(L_ERR, "ERROR: t_uac: short of cell shmem\n");
141                 goto error00;
142         }
143         new_cell->completion_cb=completion_cb;
144         new_cell->cbp=cbp;
145         /* cbp is installed -- tell error handling bellow not to free it */
146         cbp=0;
147         new_cell->is_invite=msg_type->len==INVITE_LEN 
148                 && memcmp(msg_type->s, INVITE, INVITE_LEN)==0;
149         new_cell->local=1;
150         LOCK_HASH(new_cell->hash_index);
151         insert_into_hash_table_unsafe( hash_table , new_cell );
152         UNLOCK_HASH(new_cell->hash_index);
153
154         request=&new_cell->uac[branch].request;
155         request->to=to;
156         request->send_sock=send_sock;
157
158         buf=build_uac_request(  *msg_type, *dst, *headers, *body, branch,
159                 new_cell /* t carries hash_index, label, md5, uac[].send_sock and
160                      other pieces of information needed to print a message*/
161                 , &req_len );
162     if (!buf) {
163         ret=E_OUT_OF_MEM;
164         LOG(L_ERR, "ERROR: t_uac: short of req shmem\n");
165         goto error01;
166     }      
167         new_cell->method.s=buf;new_cell->method.len=msg_type->len;
168
169         request->buffer = buf;
170         request->buffer_len = req_len;
171         new_cell->nr_of_outgoings++;
172
173         proxy->tx++;
174         proxy->tx_bytes+=req_len;
175
176         if (SEND_BUFFER( request)==-1) {
177                 LOG(L_ERR, "ERROR: t_uac: UAC sending to %.*s failed\n",
178                         dst->len, dst->s );
179                 proxy->errors++;
180                 proxy->ok=0;
181                 ser_error=ret=E_SEND;
182                 goto error01;
183         }
184         start_retr( request );
185
186         /* success */
187         goto done;
188
189 error01: 
190         /* this is the safest way (though not the cheapest) to
191            make a transaction disappear; we may appreciate the
192            safety later when we add more complexity
193         */
194         cleanup_uac_timers(new_cell);
195         put_on_wait(new_cell);
196 error00:
197         free_proxy( proxy );
198         free( proxy );
199 done: 
200         /* if we did not install cbp, release it now */
201         if (cbp) shm_free(cbp);
202         return ser_error=ret;
203 }
204
205 static void fifo_callback( struct cell *t, struct sip_msg *msg,
206         int code, void *param)
207 {
208
209         char *filename;
210         int file;
211         int r;
212         str text;
213
214         DBG("DEBUG: fifo UAC completed with status %d\n", code);
215         if (t->cbp) {
216                 filename=(char *)(t->cbp);
217                 file=open(filename, O_WRONLY);
218                 if (file<0) {
219                         LOG(L_ERR, "ERROR: fifo_callback: can't open file %s: %s\n",
220                                 filename, strerror(errno));
221                         return;
222                 }
223                 get_reply_status(&text,msg,code);
224                 if (text.s==0) {
225                         LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
226                         return;
227                 }
228                 r=write(file, text.s , text.len );
229                 close(file);
230                 pkg_free(text.s);
231                 if (r<0) {
232                         LOG(L_ERR, "ERROR: fifo_callback: write error: %s\n",
233                                 strerror(errno));
234                         return; 
235                 }
236         } else {
237                 LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
238         }
239 }       
240
241 int fifo_uac( FILE *stream, char *response_file ) 
242 {
243         char method[MAX_METHOD];
244         char header[MAX_HEADER];
245         char body[MAX_BODY];
246         char dst[MAX_DST];
247         str sm, sh, sb, sd;
248         char *shmem_file;
249         int fn_len;
250
251         sm.s=method; sh.s=header; sb.s=body; sd.s=dst;
252         while(1) {
253                 if (!read_line(method, MAX_METHOD, stream,&sm.len)||sm.len==0) {
254                         /* line breaking must have failed -- consume the rest
255                            and proceed to a new request
256                         */
257                         LOG(L_ERR, "ERROR: fifo_uac: method expected\n");
258                         return -1;
259                 }
260                 DBG("DEBUG: fifo_uac: method: %.*s\n", sm.len, method );
261                 if (!read_line(dst, MAX_DST, stream, &sd.len)||sd.len==0) {
262                         LOG(L_ERR, "ERROR: fifo_uac: destination expected\n");
263                         return -1;
264                 }
265                 DBG("DEBUG: fifo_uac:  dst: %.*s\n", sd.len, dst );
266                 /* now read header fields line by line */
267                 if (!read_line_set(header, MAX_HEADER, stream, &sh.len)) {
268                         LOG(L_ERR, "ERROR: fifo_uac: header fields expected\n");
269                         return -1;
270                 }
271                 DBG("DEBUG: fifo_uac: header: %.*s\n", sh.len, header );
272                 /* and eventually body */
273                 if (!read_line_set(body, MAX_BODY, stream, &sb.len)) {
274                         LOG(L_ERR, "ERROR: fifo_uac: body expected\n");
275                         return -1;
276                 }
277                 DBG("DEBUG: fifo_uac: body: %.*s\n", sb.len, body );
278                 DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
279                 /* we got it all, initiate transaction now! */
280                 if (response_file) {
281                         fn_len=strlen(response_file)+1;
282                         shmem_file=shm_malloc(fn_len);
283                         if (shmem_file==0) {
284                                 LOG(L_ERR, "ERROR: fifo_uac: no shmem\n");
285                                 return -1;
286                         }
287                         memcpy(shmem_file, response_file, fn_len );
288                 } else {
289                         shmem_file=0;
290                 }
291                 /* HACK: there is yet a shortcoming -- if t_uac fails, callback
292                    will not be triggered and no feedback will be printed
293                    to shmem_file
294                 */
295                 t_uac(&sm,&sd,&sh,&sb,fifo_callback,shmem_file,0 /* no dialog */);
296                 return 1;
297
298         }
299 }
300