9ec1284db05484fb1090f471bec106fdf4cb0b2e
[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, str *from, 
101         transaction_cb completion_cb, void *cbp, 
102         dlg_t dlg)
103 {
104
105         struct cell *new_cell;
106         struct proxy_l *proxy;
107         int branch;
108         int ret;
109         int req_len;
110         char *buf;
111         union sockaddr_union to;
112         struct socket_info* send_sock;
113         struct retr_buf *request;
114         str dummy_from;
115
116         /* be optimist -- assume success for return value */
117         ret=1;
118
119         proxy=uri2proxy( dst );
120         if (proxy==0) {
121                 ser_error=ret=E_BAD_ADDRESS;
122                 LOG(L_ERR, "ERROR: t_uac: can't create a dst proxy\n");
123                 goto done;
124         }
125         branch=0;
126         /* might go away -- we ignore it in send_pr_buffer anyway */
127         /* T->uac[branch].request.to_len=sizeof(union sockaddr_union); */
128         hostent2su(&to, &proxy->host, proxy->addr_idx, 
129                 (proxy->port)?htons(proxy->port):htons(SIP_PORT));
130         send_sock=get_send_socket( &to );
131         if (send_sock==0) {
132                 LOG(L_ERR, "ERROR: t_uac: no corresponding listening socket "
133                         "for af %d\n", to.s.sa_family );
134                 ret=E_NO_SOCKET;
135                 goto error00;
136         }
137         generate_callid();
138
139         new_cell = build_cell( NULL ) ; 
140         if (!new_cell) {
141                 ret=E_OUT_OF_MEM;
142                 LOG(L_ERR, "ERROR: t_uac: short of cell shmem\n");
143                 goto error00;
144         }
145         new_cell->completion_cb=completion_cb;
146         new_cell->cbp=cbp;
147         /* cbp is installed -- tell error handling bellow not to free it */
148         cbp=0;
149         new_cell->is_invite=msg_type->len==INVITE_LEN 
150                 && memcmp(msg_type->s, INVITE, INVITE_LEN)==0;
151         new_cell->local=1;
152         LOCK_HASH(new_cell->hash_index);
153         insert_into_hash_table_unsafe(  new_cell );
154         UNLOCK_HASH(new_cell->hash_index);
155
156         request=&new_cell->uac[branch].request;
157         request->to=to;
158         request->send_sock=send_sock;
159
160         if (from) dummy_from=*from; else { dummy_from.s=0; dummy_from.len=0; }
161         buf=build_uac_request(  *msg_type, *dst, dummy_from, *headers, *body, branch,
162                 new_cell /* t carries hash_index, label, md5, uac[].send_sock and
163                      other pieces of information needed to print a message*/
164                 , &req_len );
165     if (!buf) {
166         ret=E_OUT_OF_MEM;
167         LOG(L_ERR, "ERROR: t_uac: short of req shmem\n");
168         goto error01;
169     }      
170         new_cell->method.s=buf;new_cell->method.len=msg_type->len;
171
172         request->buffer = buf;
173         request->buffer_len = req_len;
174         new_cell->nr_of_outgoings++;
175
176         proxy->tx++;
177         proxy->tx_bytes+=req_len;
178
179         if (SEND_BUFFER( request)==-1) {
180                 LOG(L_ERR, "ERROR: t_uac: UAC sending to %.*s failed\n",
181                         dst->len, dst->s );
182                 proxy->errors++;
183                 proxy->ok=0;
184                 ser_error=ret=E_SEND;
185                 goto error01;
186         }
187         start_retr( request );
188
189         /* success */
190         goto done;
191
192 error01: 
193         /* this is the safest way (though not the cheapest) to
194            make a transaction disappear; we may appreciate the
195            safety later when we add more complexity
196         */
197         cleanup_uac_timers(new_cell);
198         put_on_wait(new_cell);
199 error00:
200         free_proxy( proxy );
201         free( proxy );
202 done: 
203         /* if we did not install cbp, release it now */
204         if (cbp) shm_free(cbp);
205         return ser_error=ret;
206 }
207
208 static void fifo_callback( struct cell *t, struct sip_msg *msg,
209         int code, void *param)
210 {
211
212         char *filename;
213         int file;
214         int r;
215         str text;
216
217         DBG("DEBUG: fifo UAC completed with status %d\n", code);
218         if (t->cbp) {
219                 filename=(char *)(t->cbp);
220                 file=open(filename, O_WRONLY);
221                 if (file<0) {
222                         LOG(L_ERR, "ERROR: fifo_callback: can't open file %s: %s\n",
223                                 filename, strerror(errno));
224                         return;
225                 }
226                 get_reply_status(&text,msg,code);
227                 if (text.s==0) {
228                         LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
229                         return;
230                 }
231                 r=write(file, text.s , text.len );
232                 close(file);
233                 pkg_free(text.s);
234                 if (r<0) {
235                         LOG(L_ERR, "ERROR: fifo_callback: write error: %s\n",
236                                 strerror(errno));
237                         return; 
238                 }
239         } else {
240                 LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
241         }
242 }       
243
244 int fifo_uac( FILE *stream, char *response_file ) 
245 {
246         char method[MAX_METHOD];
247         char header[MAX_HEADER];
248         char body[MAX_BODY];
249         char dst[MAX_DST];
250         str sm, sh, sb, sd;
251         char *shmem_file;
252         int fn_len;
253
254         sm.s=method; sh.s=header; sb.s=body; sd.s=dst;
255         while(1) {
256                 if (!read_line(method, MAX_METHOD, stream,&sm.len)||sm.len==0) {
257                         /* line breaking must have failed -- consume the rest
258                            and proceed to a new request
259                         */
260                         LOG(L_ERR, "ERROR: fifo_uac: method expected\n");
261                         return -1;
262                 }
263                 DBG("DEBUG: fifo_uac: method: %.*s\n", sm.len, method );
264                 if (!read_line(dst, MAX_DST, stream, &sd.len)||sd.len==0) {
265                         LOG(L_ERR, "ERROR: fifo_uac: destination expected\n");
266                         return -1;
267                 }
268                 DBG("DEBUG: fifo_uac:  dst: %.*s\n", sd.len, dst );
269                 /* now read header fields line by line */
270                 if (!read_line_set(header, MAX_HEADER, stream, &sh.len)) {
271                         LOG(L_ERR, "ERROR: fifo_uac: header fields expected\n");
272                         return -1;
273                 }
274                 DBG("DEBUG: fifo_uac: header: %.*s\n", sh.len, header );
275                 /* and eventually body */
276                 if (!read_body(body, MAX_BODY, stream, &sb.len)) {
277                         LOG(L_ERR, "ERROR: fifo_uac: body expected\n");
278                         return -1;
279                 }
280                 DBG("DEBUG: fifo_uac: body: %.*s\n", sb.len, body );
281                 DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
282                 /* we got it all, initiate transaction now! */
283                 if (response_file) {
284                         fn_len=strlen(response_file)+1;
285                         shmem_file=shm_malloc(fn_len);
286                         if (shmem_file==0) {
287                                 LOG(L_ERR, "ERROR: fifo_uac: no shmem\n");
288                                 return -1;
289                         }
290                         memcpy(shmem_file, response_file, fn_len );
291                 } else {
292                         shmem_file=0;
293                 }
294                 /* HACK: there is yet a shortcoming -- if t_uac fails, callback
295                    will not be triggered and no feedback will be printed
296                    to shmem_file
297                 */
298                 t_uac(&sm,&sd,&sh,&sb, 0 /* default from */,
299                         fifo_callback,shmem_file,0 /* no dialog */);
300                 return 1;
301
302         }
303 }
304