00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <arpa/inet.h>
00036 #include <errno.h>
00037 #include <fcntl.h>
00038 #include <netinet/in.h>
00039 #include <netdb.h>
00040 #include <stdlib.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <sys/un.h>
00044 #include <sys/socket.h>
00045 #include <sys/stat.h>
00046 #include <sys/types.h>
00047 #include <unistd.h>
00048 #include <signal.h>
00049
00050 #include "../../resolve.h"
00051 #include "mi_datagram.h"
00052 #include "datagram_fnc.h"
00053 #include "mi_datagram_parser.h"
00054 #include "mi_datagram_writer.h"
00055
00056
00057 #ifndef SUN_LEN
00058 #define SUN_LEN(sa) ( strlen((sa)->sun_path) + \
00059 (size_t)(((struct sockaddr_un*)0)->sun_path) )
00060 #endif
00061
00062 #if !defined(AF_LOCAL)
00063 #define AF_LOCAL AF_UNIX
00064 #endif
00065
00066 int flags;
00067 static char *mi_buf = 0;
00068
00069 static union {
00070 struct sockaddr_un un;
00071 struct sockaddr_in in;
00072 } reply_addr;
00073
00074 static unsigned int reply_addr_len;
00075
00076 extern int mi_socket_timeout;
00077 static unsigned int mi_socket_domain;
00078
00079 static int mi_sock_check(int fd, char* fname);
00080
00081 #define mi_create_dtgram_replysocket(_socketfd,_socket_domain, _err) \
00082 _socketfd = socket(_socket_domain, SOCK_DGRAM, 0);\
00083 if (_socketfd == -1) {\
00084 LM_ERR("cannot create socket: %s\n", strerror(errno));\
00085 goto _err;\
00086 }\
00087 \
00088 flags = fcntl(_socketfd, F_GETFL);\
00089 if (flags == -1){\
00090 LM_ERR("fcntl failed: %s\n", strerror(errno));\
00091 goto _err;\
00092 }\
00093 if (fcntl(_socketfd, F_SETFL, flags | O_NONBLOCK) == -1) {\
00094 LM_ERR("fcntl: set non-blocking failed: %s\n", strerror(errno));\
00095 goto _err;\
00096 }
00097
00098
00099 int mi_init_datagram_server(sockaddr_dtgram *addr, unsigned int socket_domain, rx_tx_sockets * socks, int mode, int uid, int gid )
00100 {
00101 char * socket_name;
00102
00103
00104
00105 mi_socket_domain = socket_domain;
00106
00107
00108 socks->rx_sock = socket(socket_domain, SOCK_DGRAM, 0);
00109 if (socks->rx_sock == -1) {
00110 LM_ERR("cannot create RX socket: %s\n", strerror(errno));
00111 return -1;
00112 }
00113
00114 switch(socket_domain)
00115 {
00116 case AF_LOCAL:
00117 LM_DBG("we have a unix socket: %s\n", addr->unix_addr.sun_path);
00118 socket_name = addr->unix_addr.sun_path;
00119 if(bind(socks->rx_sock,(struct sockaddr*)&addr->unix_addr, SUN_LEN(&addr->unix_addr))< 0) {
00120 LM_ERR("bind: %s\n", strerror(errno));
00121 goto err_rx;
00122 }
00123 if(mi_sock_check(socks->rx_sock, socket_name)!=0)
00124 goto err_rx;
00125
00126 if (mode){
00127 if (chmod(socket_name, mode)<0){
00128 LM_ERR("failed to change the permissions for %s to %04o:"
00129 "%s[%d]\n",socket_name, mode, strerror(errno), errno);
00130 goto err_rx;
00131 }
00132 }
00133
00134 if ((uid!=-1) || (gid!=-1)){
00135 if (chown(socket_name, uid, gid)<0){
00136 LM_ERR("failed to change the owner/group for %s to %d.%d;"
00137 "%s[%d]\n",socket_name, uid, gid, strerror(errno), errno);
00138 goto err_rx;
00139 }
00140 }
00141 break;
00142
00143 case AF_INET:
00144 if (bind(socks->rx_sock, &addr->udp_addr.s,
00145 sockaddru_len(addr->udp_addr))< 0) {
00146 LM_ERR("bind: %s\n", strerror(errno));
00147 goto err_rx;
00148 }
00149 break;
00150 #ifdef USE_IPV6
00151 case AF_INET6:
00152 if(bind(socks->rx_sock, (struct sockaddr*)&addr->udp_addr.sin6, sizeof(addr->udp_addr)) < 0) {
00153 LM_ERR("bind: %s\n", strerror(errno));
00154 goto err_rx;
00155 }
00156 break;
00157 #endif
00158 default:
00159 LM_ERR("domain not supported\n");
00160 goto err_both;
00161
00162 }
00163 mi_create_dtgram_replysocket(socks->tx_sock,socket_domain, err_both);
00164
00165 return 0;
00166 err_both:
00167 close(socks->tx_sock);
00168 err_rx:
00169 close(socks->rx_sock);
00170 return -1;
00171 }
00172
00173
00174
00175 int mi_init_datagram_buffer(void) {
00176
00177 mi_buf = pkg_malloc(DATAGRAM_SOCK_BUF_SIZE);
00178 if ( mi_buf==NULL) {
00179 LM_ERR("no more pkg memory\n");
00180 return -1;
00181 }
00182 return 0;
00183 }
00184
00185
00186
00187
00188
00189 int mi_sock_check(int fd, char* fname)
00190 {
00191 struct stat fst;
00192 struct stat lst;
00193
00194 if (fstat(fd, &fst)<0){
00195 LM_ERR("fstat failed: %s\n",
00196 strerror(errno));
00197 return -1;
00198 }
00199
00200 if (!S_ISSOCK(fst.st_mode)){
00201 LM_ERR("%s is not a sock\n", fname);
00202 return -1;
00203 }
00204
00205 if (fst.st_nlink>1){
00206 LM_ERR("security: sock_check: %s is hard-linked %d times\n",
00207 fname, (unsigned)fst.st_nlink);
00208 return -1;
00209 }
00210
00211
00212 if (lstat(fname, &lst)<0){
00213 LM_ERR("lstat failed: %s\n", strerror(errno));
00214 return -1;
00215 }
00216 if (S_ISLNK(lst.st_mode)){
00217 LM_ERR("security: sock_check: %s is a soft link\n", fname);
00218 return -1;
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 return 0;
00232 }
00233
00234
00235
00236
00237 static int mi_send_dgram(int fd, char* buf, unsigned int len,
00238 const struct sockaddr* to, int tolen, int timeout)
00239 {
00240 int n;
00241 size_t total_len;
00242 total_len = strlen(buf);
00243
00244
00245
00246
00247 if(total_len == 0 || tolen ==0)
00248 return -1;
00249
00250 if (total_len>DATAGRAM_SOCK_BUF_SIZE) {
00251 LM_DBG("datagram too big, trunking, datagram_size is %i\n", DATAGRAM_SOCK_BUF_SIZE);
00252 len = DATAGRAM_SOCK_BUF_SIZE;
00253 }
00254
00255 n=sendto(fd, buf, len, 0, to, tolen);
00256 return n;
00257 }
00258
00259
00260
00261
00262
00263 static int identify_command(datagram_stream * dtgram, struct mi_cmd * *f)
00264 {
00265 char *command,*p, *start;
00266
00267
00268 p= dtgram->start;
00269 start = p;
00270 if (!p){
00271 LM_ERR("null pointer \n");
00272 return -1;
00273 }
00274
00275
00276 if ( dtgram->len ==0 ){
00277 LM_DBG("command empty case1 \n");
00278 goto error;
00279 }
00280 if (*p != MI_CMD_SEPARATOR){
00281 LM_ERR("command must begin with: %c \n", MI_CMD_SEPARATOR);
00282 goto error;
00283 }
00284 command = p+1;
00285
00286 LM_DBG("the command starts here: %s\n", command);
00287 p=strchr(command, MI_CMD_SEPARATOR );
00288 if (!p ){
00289 LM_ERR("empty command \n");
00290 goto error;
00291 }
00292 if(*(p+1)!='\n'){
00293 LM_ERR("the request's first line is invalid :no newline after "
00294 "the second %c\n",MI_CMD_SEPARATOR);
00295 goto error;
00296 }
00297
00298
00299 *p=0;
00300 LM_DBG("the command is %s\n",command);
00301
00302 *f=lookup_mi_cmd( command, p-command);
00303 if(!*f)
00304 goto error;
00305
00306 LM_DBG("dtgram->len is %i\n", dtgram->len);
00307 dtgram->current = p+2 ;
00308 dtgram->len -=p+2 - dtgram->start;
00309 LM_DBG("dtgram->len is %i\n",dtgram->len);
00310
00311 return 0;
00312 error:
00313 return -1;
00314 }
00315
00316
00317
00318 static inline void free_async_handler( struct mi_handler *hdl )
00319 {
00320 if (hdl)
00321 shm_free(hdl);
00322 }
00323
00324
00325 static void datagram_close_async(struct mi_root *mi_rpl,struct mi_handler *hdl, int done)
00326 {
00327 datagram_stream dtgram;
00328 int ret;
00329 my_socket_address *p;
00330 int reply_sock, flags;
00331
00332 p = (my_socket_address *)hdl->param;
00333
00334 LM_DBG("the socket domain is %i and af_local is %i\n", p->domain, AF_LOCAL);
00335
00336 mi_create_dtgram_replysocket(reply_sock, p->domain, err);
00337
00338
00339 if (mi_rpl!=0) {
00340
00341 dtgram.start = pkg_malloc(DATAGRAM_SOCK_BUF_SIZE);
00342 if(!dtgram.start) {
00343 LM_ERR("no more pkg memory\n");
00344 goto err;
00345 }
00346
00347 if(mi_datagram_write_tree(&dtgram , mi_rpl) != 0) {
00348 LM_ERR("failed to build the response \n");
00349 goto err;
00350 }
00351 LM_DBG("the response is %s", dtgram.start);
00352
00353
00354 ret = mi_send_dgram(reply_sock, dtgram.start, dtgram.current - dtgram.start,
00355 (struct sockaddr *)&p->address, p->address_len, mi_socket_timeout);
00356 if (ret>0) {
00357 LM_DBG("the response: %s has been sent in %i octets\n", dtgram.start, ret);
00358 } else {
00359 LM_ERR("failed to send the response, ret is %i\n",ret);
00360 }
00361 free_mi_tree(mi_rpl);
00362 pkg_free(dtgram.start);
00363 } else if (done) {
00364 mi_send_dgram(reply_sock, MI_COMMAND_FAILED, MI_COMMAND_FAILED_LEN,
00365 (struct sockaddr*)&reply_addr, reply_addr_len, mi_socket_timeout);
00366 free_async_handler( hdl );
00367 }
00368
00369 close(reply_sock);
00370 return;
00371
00372 err:
00373 if(dtgram.start)
00374 pkg_free(dtgram.start);
00375 close(reply_sock);
00376 return;
00377 }
00378
00379
00380
00381 static inline struct mi_handler *build_async_handler(unsigned int sock_domain,
00382 struct sockaddr *reply_addr, unsigned int reply_addr_len)
00383 {
00384 struct mi_handler *hdl;
00385 void *p;
00386 my_socket_address *repl_address;
00387
00388 hdl = (struct mi_handler*)shm_malloc( sizeof(struct mi_handler) + sizeof(my_socket_address));
00389 if (hdl==0) {
00390 LM_ERR("no more shm mem\n");
00391 return 0;
00392 }
00393
00394 p = (void *)((hdl) + 1);
00395 repl_address = p;
00396
00397 switch(sock_domain)
00398 {
00399 case AF_LOCAL: LM_DBG("we have an unix socket\n");
00400 memcpy(&repl_address->address.unix_deb, reply_addr, reply_addr_len);
00401 break;
00402 case AF_INET: LM_DBG("we have an IPv4 socket\n");
00403 memcpy(&repl_address->address.inet_v4, reply_addr, reply_addr_len);
00404 break;
00405 case AF_INET6: LM_DBG("we have an IPv6 socket\n");
00406 memcpy(&repl_address->address.inet_v6, reply_addr, reply_addr_len);
00407 break;
00408 default: LM_CRIT("socket_domain has an incorrect value\n");
00409 shm_free(hdl);
00410 return NULL;
00411 }
00412 repl_address->domain = sock_domain;
00413 repl_address->address_len = reply_addr_len;
00414
00415 hdl->handler_f = datagram_close_async;
00416 hdl->param = (void*)repl_address;
00417
00418 return hdl;
00419 }
00420
00421
00422
00423 void mi_datagram_server(int rx_sock, int tx_sock)
00424 {
00425 struct mi_root *mi_cmd;
00426 struct mi_root *mi_rpl;
00427 struct mi_handler *hdl;
00428 struct mi_cmd * f;
00429 datagram_stream dtgram;
00430
00431 int ret, len;
00432
00433 ret = 0;
00434 f = 0;
00435
00436 while(1) {
00437 memset(mi_buf, 0, DATAGRAM_SOCK_BUF_SIZE);
00438 reply_addr_len = sizeof(reply_addr);
00439
00440
00441 ret = recvfrom(rx_sock, mi_buf, DATAGRAM_SOCK_BUF_SIZE, 0,
00442 (struct sockaddr*)&reply_addr, &reply_addr_len);
00443
00444 if (ret == -1) {
00445 LM_ERR("recvfrom: (%d) %s\n", errno, strerror(errno));
00446 if ((errno == EINTR) ||
00447 (errno == EAGAIN) ||
00448 (errno == EWOULDBLOCK) ||
00449 (errno == ECONNREFUSED)) {
00450 LM_DBG("got %d (%s), going on\n", errno, strerror(errno));
00451 continue;
00452 }
00453 LM_DBG("error in recvfrom\n");
00454 continue;
00455 }
00456
00457 if(ret == 0)
00458 continue;
00459
00460 LM_DBG("received %.*s\n", ret, mi_buf);
00461
00462 if(ret> DATAGRAM_SOCK_BUF_SIZE) {
00463 LM_ERR("buffer overflow\n");
00464 continue;
00465 }
00466
00467 LM_DBG("mi_buf is %s and we have received %i bytes\n",mi_buf, ret);
00468 dtgram.start = mi_buf;
00469 dtgram.len= ret;
00470 dtgram.current = dtgram.start;
00471
00472 ret = identify_command(&dtgram, &f);
00473
00474 if(ret != 0) {
00475 LM_ERR("command not available\n");
00476 mi_send_dgram(tx_sock, MI_COMMAND_NOT_AVAILABLE,
00477 MI_COMMAND_AVAILABLE_LEN,
00478 (struct sockaddr* )&reply_addr, reply_addr_len,
00479 mi_socket_timeout);
00480 continue;
00481 }
00482 LM_DBG("we have a valid command \n");
00483
00484
00485 if (f->flags&MI_ASYNC_RPL_FLAG) {
00486 hdl = build_async_handler(mi_socket_domain,
00487 (struct sockaddr* )&reply_addr, reply_addr_len);
00488 if (hdl==0) {
00489 LM_ERR("failed to build async handler\n");
00490 mi_send_dgram(tx_sock, MI_INTERNAL_ERROR,
00491 MI_INTERNAL_ERROR_LEN,(struct sockaddr* )&reply_addr,
00492 reply_addr_len, mi_socket_timeout);
00493 continue;
00494 }
00495 } else {
00496 hdl = 0;
00497 }
00498
00499 LM_DBG("after identifing the command, the received datagram is %s\n", dtgram.current);
00500
00501
00502 if (f->flags&MI_NO_INPUT_FLAG) {
00503 LM_DBG("the command has no params\n");
00504 mi_cmd = 0;
00505 } else {
00506 LM_DBG("parsing the command's params\n");
00507 mi_cmd = mi_datagram_parse_tree(&dtgram);
00508 if (mi_cmd==NULL){
00509 LM_ERR("failed to parse the MI tree\n");
00510 mi_send_dgram(tx_sock, MI_PARSE_ERROR, MI_PARSE_ERROR_LEN,
00511 (struct sockaddr* )&reply_addr, reply_addr_len,
00512 mi_socket_timeout);
00513 free_async_handler(hdl);
00514 continue;
00515 }
00516 mi_cmd->async_hdl = hdl;
00517 }
00518
00519 LM_DBG("done parsing the mi tree\n");
00520 if ( (mi_rpl=run_mi_cmd(f, mi_cmd))==0 ) {
00521
00522 LM_ERR("failed to process the command\n");
00523 mi_send_dgram(tx_sock, MI_COMMAND_FAILED, MI_COMMAND_FAILED_LEN,
00524 (struct sockaddr* )&reply_addr, reply_addr_len,
00525 mi_socket_timeout);
00526 goto failure;
00527 }
00528
00529
00530 LM_DBG("command process (%s)succeded\n",f->name.s);
00531
00532 if (mi_rpl!=MI_ROOT_ASYNC_RPL) {
00533 if(mi_datagram_write_tree(&dtgram , mi_rpl) != 0){
00534 LM_ERR("failed to build the response \n");
00535 goto failure;
00536 }
00537
00538 len = dtgram.current - dtgram.start;
00539 ret = mi_send_dgram(tx_sock, dtgram.start,len,
00540 (struct sockaddr* )&reply_addr,
00541 reply_addr_len, mi_socket_timeout);
00542 if (ret>0){
00543 LM_DBG("the response: %s has been sent in %i octets\n", dtgram.start, ret);
00544 } else {
00545 LM_ERR("failed to send the response\n");
00546 }
00547 free_mi_tree( mi_rpl );
00548 free_async_handler(hdl);
00549 if (mi_cmd)
00550 free_mi_tree( mi_cmd );
00551 } else {
00552 if (mi_cmd)
00553 free_mi_tree( mi_cmd );
00554 }
00555
00556 continue;
00557
00558 failure:
00559 free_async_handler(hdl);
00560
00561 if (mi_cmd)
00562 free_mi_tree( mi_cmd );
00563
00564 if (mi_rpl)
00565 free_mi_tree(mi_rpl);
00566 continue;
00567 }
00568 }
00569