/home/dko/projects/mobilec/trunk/src/message.c

Go to the documentation of this file.
00001 /*[
00002  * Copyright (c) 2007 Integration Engineering Laboratory
00003                       University of California, Davis
00004  *
00005  * Permission to use, copy, and distribute this software and its
00006  * documentation for any purpose with or without fee is hereby granted,
00007  * provided that the above copyright notice appear in all copies and
00008  * that both that copyright notice and this permission notice appear
00009  * in supporting documentation.
00010  *
00011  * Permission to modify the software is granted, but not the right to
00012  * distribute the complete modified source code.  Modifications are to
00013  * be distributed as patches to the released version.  Permission to
00014  * distribute binaries produced by compiling modified sources is granted,
00015  * provided you
00016  *   1. distribute the corresponding source modifications from the
00017  *    released version in the form of a patch file along with the binaries,
00018  *   2. add special version identification to distinguish your version
00019  *    in addition to the base release version number,
00020  *   3. provide your name and address as the primary contact for the
00021  *    support of your modified version, and
00022  *   4. retain our contact information in regard to use of the base
00023  *    software.
00024  * Permission to distribute the released version of the source code along
00025  * with corresponding source modifications in the form of a patch file is
00026  * granted with same provisions 2 through 4 for binary distributions.
00027  *
00028  * This software is provided "as is" without express or implied warranty
00029  * to the extent permitted by applicable law.
00030 ]*/
00031 
00032 #include <string.h>
00033 #ifndef _WIN32
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <netinet/in.h>
00037 #include <arpa/inet.h>
00038 #include <unistd.h>
00039 #include <netdb.h>
00040 #else
00041 #include "winconfig.h"
00042 #endif
00043 #include <mxml.h>
00044 #include "include/libmc.h"
00045 #include "include/agent.h"
00046 #include "include/mc_platform.h"
00047 #include "include/message.h"
00048 #include "include/mtp_http.h"
00049 #include "include/xml_compose.h"
00050 #include "include/xml_helper.h"
00051 #include "include/xml_parser.h"
00052 
00053 #include "security/asm_node.h"
00054 
00055 #define SOCKET_INPUT_SIZE 4096
00056 
00057 #ifdef MC_SECURITY
00058 int message_Decrypt(message_p message, asm_node_p asm_node)
00059 {
00060   int i;
00061   mxml_node_t* message_node;
00062   mxml_node_t* encrypted_data_node;
00063   mxml_node_t* gaf_message_node;
00064   char* encrypted_hex_string;
00065   unsigned char* message_string;
00066   char buf[3];
00067   unsigned char iv[32];
00068   int tmp = 0;
00069   int decrypt_len;
00070 
00071   gaf_message_node = mxmlFindElement
00072     (
00073      message->xml_root,
00074      message->xml_root,
00075      "MOBILEC_MESSAGE",
00076      NULL,
00077      NULL,
00078      MXML_DESCEND
00079     );
00080   /* Find the message element */
00081   message_node = mxmlFindElement
00082     (
00083      message->xml_root,
00084      message->xml_root,
00085      "MESSAGE",
00086      NULL,
00087      NULL,
00088      MXML_DESCEND
00089     );
00090   if (message_node == NULL) return MC_ERR_PARSE;
00091   encrypted_data_node = mxmlFindElement
00092     (
00093      message->xml_root,
00094      message_node,
00095      "ENCRYPTED_DATA",
00096      NULL,
00097      NULL,
00098      MXML_DESCEND
00099     );
00100   if (encrypted_data_node == NULL) return MC_ERR_PARSE;
00101   encrypted_hex_string = xml_get_text(encrypted_data_node);
00102   
00103   /* Now we need to convert the hex string into an unsigned char str. */
00104   message_string = (unsigned char*)malloc
00105     (
00106      sizeof(char) * 
00107      ((strlen(encrypted_hex_string)/2) + 32)
00108     );
00109   CHECK_NULL(message_string, exit(0););
00110   buf[2] = '\0';
00111   for(i = 0; i < (int)strlen(encrypted_hex_string); i += 2)
00112   {
00113     buf[0] = encrypted_hex_string[i];
00114     buf[1] = encrypted_hex_string[i+1];
00115     sscanf(buf, "%x", &tmp);
00116     message_string[i/2] = (unsigned char) tmp; 
00117   }
00118 
00119   decrypt_len = 
00120      strlen(encrypted_hex_string)/2;
00121   memset(iv, 0, sizeof(iv));
00122   aes_cbc_decrypt
00123     (
00124      &(asm_node->data.dh_data->aes),
00125      iv,
00126      (unsigned char*)message_string,
00127      (unsigned char*)message_string,
00128      decrypt_len
00129     );
00130   /* now we delete the old message node and compose a new one */
00131   mxmlDelete(message_node);
00132 
00133   mxmlLoadString
00134     (
00135      gaf_message_node,
00136      (char*)message_string,
00137      MXML_NO_CALLBACK
00138     );
00139 
00140   /* Free all stuff */
00141   free(encrypted_hex_string);
00142   free(message_string);
00143 
00144   /* re-parse the message */
00145   return message_xml_parse(message);
00146 }
00147 
00148 int
00149 message_Encrypt(message_p message, asm_node_p asm_node)
00150 {
00151   int i;
00152   int encrypt_len;
00153   mxml_node_t* message_node;
00154   mxml_node_t* gaf_message_node;
00155   mxml_node_t* encrypted_data_node;
00156   char* message_str;
00157   int message_len;
00158   char* encrypted_message_str;
00159   unsigned char iv[32];
00160   char buf[4];
00161 
00162   /* First, check to see if the xml root exists. If not, we must create it */
00163   if (message->xml_root == NULL) {
00164     message->xml_root = mxmlLoadString
00165       (
00166        NULL,
00167        message->message_body,
00168        MXML_NO_CALLBACK
00169       );
00170   }
00171 
00172   /* Now we can get rid of the old unencrypted message body */
00173   if(message->message_body) {
00174     free(message->message_body);
00175     message->message_body = NULL;
00176   }
00177 
00178   message_node = mxmlFindElement
00179     (
00180      message->xml_root,
00181      message->xml_root,
00182      "MESSAGE",
00183      NULL,
00184      NULL,
00185      MXML_DESCEND
00186     );
00187   if (message_node == NULL) {
00188     return MC_ERR_PARSE;
00189   }
00190   message_str = mxmlSaveAllocString
00191     (
00192      message_node,
00193      MXML_NO_CALLBACK
00194     );
00195   message_len = strlen(message_str);
00196   message_str = realloc(message_str, message_len + 16);
00197   CHECK_NULL(message_str, exit(0););
00198 
00199   encrypt_len = message_len + (16 - message_len%16);
00200   memset(iv, 0, sizeof(iv));
00201   aes_cbc_encrypt
00202     (
00203      &(asm_node->data.dh_data->aes),
00204      iv,
00205      (unsigned char*) message_str,
00206      (unsigned char*) message_str,
00207      encrypt_len
00208     );
00209   encrypted_message_str = (char*) malloc
00210     (
00211      sizeof(char) * 
00212      (encrypt_len*2)+1
00213     );
00214   CHECK_NULL(encrypted_message_str, exit(0););
00215 
00216 
00217   encrypted_message_str[0] = '\0';
00218   buf[2] = '\0';
00219   for (i = 0; i < encrypt_len ; i++) 
00220   {
00221     sprintf(buf, "%02x", (unsigned char)message_str[i]);
00222     strcat(encrypted_message_str, buf);
00223   }
00224 
00225   /* Now we delete the old message node and replace it with a new one */
00226   mxmlDelete(message_node);
00227   gaf_message_node = mxmlFindElement
00228     (
00229      message->xml_root,
00230      message->xml_root,
00231      "MOBILEC_MESSAGE",
00232      NULL,
00233      NULL,
00234      MXML_DESCEND
00235     );
00236 
00237   message_node = mxmlNewElement
00238     (
00239      gaf_message_node,
00240      "MESSAGE"
00241     );
00242   mxmlElementSetAttr
00243     (
00244      message_node,
00245      "message",
00246      "ENCRYPTED_DATA"
00247     );
00248   mxmlElementSetAttr
00249     (
00250      message_node,
00251      "from",
00252      message->from_address
00253     );
00254 
00255   encrypted_data_node = mxmlNewElement
00256     (
00257      message_node,
00258      "ENCRYPTED_DATA"
00259     );
00260   
00261   xml_new_cdata
00262     (
00263      encrypted_data_node,
00264      encrypted_message_str
00265     );
00266 
00267   message->message_body = mxmlSaveAllocString
00268     (
00269      message->xml_root,
00270      MXML_NO_CALLBACK
00271     );
00272 
00273   free(message_str);
00274   free(encrypted_message_str);
00275 
00276   message->message_type = ENCRYPTED_DATA;
00277 
00278   return MC_SUCCESS;
00279 }
00280 #endif /*MC_SECURITY*/
00281 
00282 message_p
00283 message_New(void)
00284 {
00285   message_p message;
00286   message = (message_p)malloc(sizeof(message_t));
00287   CHECK_NULL(message, exit(0););
00288   message->addr = NULL;
00289   message->connect_id = 0;
00290   message->message_id = 0;
00291   message->isHTTP = 0;
00292   message->message_type = 0;
00293   message->http_type = 0;
00294   message->xml_root = NULL;
00295   message->xml_payload = NULL;
00296   message->message_body = NULL;
00297   message->update_name = NULL;
00298   message->update_num = 0;
00299   message->from_address = NULL;
00300   message->to_address = NULL;
00301   message->target = NULL;
00302   message->agent_xml_flag = 0;
00303   return message;
00304 }
00305 
00306 message_p
00307 message_Copy(message_p src)
00308 {
00309   fprintf(stderr, "FIXME: message_Copy() is not implemented yet. %s:%d\n",
00310       __FILE__, __LINE__);
00311   return NULL;
00312 }
00313 
00314 int
00315 message_InitializeFromAgent(
00316     mc_platform_p mc_platform,
00317     message_p message,
00318     agent_p agent)
00319 {
00320   struct hostent* host;
00321 
00322   char* buf;
00323   char* destination_host;
00324   char* destination_port_str;
00325 #ifndef _WIN32
00326   char* save_ptr; /* For re-entrant strtok_r */
00327 #endif
00328   int destination_port;
00329 
00330   message->message_id = rand();
00331   message->message_type = MOBILE_AGENT;
00332 
00333   message->xml_root = agent_xml_compose(agent);
00334   /* If agent_xml_compose fails, that is a fatal error, since
00335    * 'agent' is gauranteed to be a valid agent. */
00336   CHECK_NULL(message->xml_root, exit(0););
00337   message->message_body = mxmlSaveAllocString( 
00338       message->xml_root,
00339       MXML_NO_CALLBACK );
00340 
00341   message->update_name = NULL;
00342 
00343   message->from_address =
00344     (char*)malloc(sizeof(char) * (strlen(mc_platform->hostname) + 10));
00345   sprintf(
00346       message->from_address,
00347       "%s:%d",
00348       mc_platform->hostname,
00349       mc_platform->port );
00350   if (
00351       agent->datastate->task_progress >=
00352       agent->datastate->number_of_tasks
00353      )
00354   {
00355     message->to_address = 
00356       (char*)malloc
00357       (
00358        sizeof(char) * 
00359        (
00360         strlen(agent->home) + 1
00361        )
00362       );
00363     CHECK_NULL(message->to_address, exit(0););
00364     strcpy
00365       (
00366        message->to_address,
00367        agent->home
00368       );
00369   } else {
00370     message->to_address = 
00371       (char*) malloc
00372       ( 
00373        sizeof(char) * 
00374        (
00375         strlen
00376         (
00377          agent->datastate->tasks[ agent->datastate->task_progress ]
00378          ->server_name 
00379         )
00380         +1
00381        )
00382       );
00383     CHECK_NULL( message->to_address, mc_platform->err = MC_ERR_MEMORY; return MC_ERR_MEMORY;);
00384     strcpy(
00385         message->to_address,
00386         agent->datastate->tasks[ agent->datastate->task_progress ]->server_name 
00387         );
00388   }
00389   message->agent_xml_flag = 0;
00390   message->target = strdup("ams");
00391   /* Set up message->addr */
00392   buf = (char*)malloc
00393     (
00394      sizeof(char) * 
00395      (strlen(message->to_address)+1)
00396     );
00397   CHECK_NULL(buf, exit(0););
00398   strcpy(buf, message->to_address);
00399   destination_host = strtok_r(buf, ":", &save_ptr);
00400   destination_port_str = strtok_r(NULL, ":", &save_ptr);
00401   destination_port = atoi(destination_port_str);
00402   message->addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
00403   if ((host = gethostbyname(destination_host))) {
00404     memcpy(&(message->addr->sin_addr), host->h_addr, host->h_length);
00405     message->addr->sin_port = htons(destination_port);
00406   } else {
00407     WARN("Host not found.");
00408   }
00409   free(buf);
00410   return MC_SUCCESS;
00411 }
00412 
00413 int
00414 message_InitializeFromConnection(
00415     mc_platform_p mc_platform,
00416     message_p message,
00417     connection_p connection)
00418 {
00419   int i = 1;
00420   int n;
00421   char *message_string;
00422   char *buffer;
00423 
00424   message->addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
00425   CHECK_NULL(message->addr, exit(0););
00426   *(message->addr) = connection->addr;
00427 
00428   message->connect_id = connection->connect_id;
00429 
00430   message->message_id = rand();
00431 
00432   message->to_address = NULL;
00433   message->from_address = NULL;
00434   message->target = NULL;
00435 
00436   buffer = (char*) malloc(sizeof(char) * (SOCKET_INPUT_SIZE + 1));
00437   CHECK_NULL(buffer, exit(0););
00438   message_string = (char*) malloc(sizeof(char) * (SOCKET_INPUT_SIZE + 1));
00439   CHECK_NULL(message_string, exit(0););
00440   message_string[0] = '\0';
00441   buffer[0] = '\0';
00442 
00443   /* Receive the message */
00444   while(1) {
00445 #ifndef _WIN32
00446     n = recvfrom(connection->clientfd,
00447         (void *) buffer,
00448         (size_t) sizeof(char)*SOCKET_INPUT_SIZE,
00449         0,
00450         (struct sockaddr *) 0,
00451         (socklen_t *) 0);
00452 #else
00453     n = recvfrom(connection->clientfd,
00454         (void *) buffer,
00455         (size_t) sizeof(char)*SOCKET_INPUT_SIZE,
00456         0,
00457         (struct sockaddr *) 0,
00458         0);
00459 #endif
00460     if (n < 0) {
00461       free(buffer);
00462       return MC_ERR_CONNECT;
00463     } 
00464     else if (n == 0) {
00465       free(buffer);
00466       break;
00467     } else {
00468       buffer[n] = '\0';
00469       i++;
00470       strcat(message_string, buffer);
00471       message_string = realloc
00472         (
00473          message_string, 
00474          sizeof(char) * (SOCKET_INPUT_SIZE+1) * i
00475         );
00476       CHECK_NULL(message_string, exit(0););
00477       buffer[0] = '\0';
00478     }
00479   }
00480   message->message_body = (char*)malloc
00481     (
00482      sizeof(char) * 
00483      (strlen(message_string) + 1)
00484     );
00485   CHECK_NULL(message->message_body, exit(0););
00486   strcpy(message->message_body, message_string);
00487   free(message_string);
00488   message->xml_root = mxmlLoadString
00489     (
00490      NULL, 
00491      message->message_body,
00492      MXML_NO_CALLBACK
00493     );
00494   if (message_xml_parse(message)) {
00495     fprintf(stderr, "Error parsing message at %s:%d.\n",
00496         __FILE__, __LINE__);
00497     message_Destroy(message);
00498     return MC_ERR_PARSE;
00499   }
00500   return MC_SUCCESS;  
00501 }
00502 
00503 int http_to_hostport(const char* http_str, char** host, int* port, char** target)
00504 {
00505   /* We want to convert the string "http://somehost.com:5050/acc" to a 
00506    * host: somehost.com
00507    * port: 5050
00508    * target: acc */
00509   char* tmp;
00510   if(strncmp(http_str, "http://", 7)) {
00511     return MC_ERR_PARSE;
00512   }
00513   http_str += 7;
00514   tmp = strchr(http_str, (int)':');
00515   if (tmp == NULL) return MC_ERR_PARSE;
00516 
00517   /* Get the host */
00518   *host = (char*)malloc(sizeof(char) * 
00519       (tmp - http_str + 1) );
00520   strncpy(*host, http_str, tmp - http_str);
00521   (*host)[tmp-http_str] = '\0';
00522 
00523   /* Get the port */
00524   tmp++;
00525   sscanf(tmp, "%d", port);
00526 
00527   /* Get the target */
00528   tmp = strchr(tmp, (int)'/');
00529   tmp++;
00530   *target = (char*)malloc(sizeof(char) * 
00531       (strlen(tmp)+1) );
00532   strcpy(*target, tmp);
00533 
00534   return 0;
00535 }
00536 
00537 int
00538 message_InitializeFromString(
00539     mc_platform_p mc_platform,
00540     message_p message,
00541     const char* string,
00542     const char* destination_host,
00543     int destination_port,
00544     const char* target)
00545 {
00546   char* destination;
00547   struct hostent* host;
00548 
00549   message->connect_id = 0;
00550   message->message_id = rand();
00551 
00552   message->message_type = MOBILE_AGENT;
00553 
00554   message->xml_root = NULL;
00555 
00556   message->message_body = 
00557     (char*)malloc( sizeof(char) * (strlen(string)+1));
00558   CHECK_NULL(message->message_body, 
00559       mc_platform->err = MC_ERR_MEMORY;
00560       return MC_ERR_MEMORY; );
00561   strcpy(message->message_body, string);
00562 
00563   message->update_name = NULL;
00564 
00565   destination = malloc(sizeof(char)*(strlen(destination_host) + 10));
00566   CHECK_NULL(destination,
00567       mc_platform->err = MC_ERR_MEMORY;
00568       return MC_ERR_MEMORY; );
00569   sprintf(destination, "%s:%d", 
00570       destination_host,
00571       destination_port
00572       );
00573 
00574   message->to_address = destination;
00575   message->from_address = (char*)malloc(
00576       sizeof(char) * (strlen(mc_platform->hostname)+10));
00577   sprintf(message->from_address,
00578       "%s:%d",
00579       mc_platform->hostname,
00580       mc_platform->port );
00581   message->target = (char*)malloc(sizeof(char) * 
00582       (strlen(target)+1));
00583   strcpy(message->target, target);
00584 
00585   /* Set up message->addr */
00586   message->addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
00587   if (destination_host != NULL && strlen(destination_host)!= 0) {
00588     if((host = gethostbyname(destination_host)))
00589     {
00590       memcpy(&(message->addr->sin_addr), host->h_addr, host->h_length);
00591       message->addr->sin_port = htons(destination_port);
00592     } else {
00593       fprintf(stderr, "Warning: Host not found: %s:%d  %s:%d",
00594           destination_host, destination_port, __FILE__, __LINE__ );
00595     }
00596   }
00597 
00598   return MC_SUCCESS;
00599 }
00600 
00601   int
00602 message_Destroy(message_p message)
00603 {
00604   if (message == NULL) {
00605     return MC_SUCCESS;
00606   }
00607   /* We may not want to delete this here,
00608    * in case an agent needs this data. */
00609   if(message->xml_root != NULL && message->agent_xml_flag == 0) {
00610     mxmlDelete(message->xml_root);
00611   }
00612 
00613   if(message->addr) {
00614     free(message->addr);
00615     message->addr = NULL;
00616   }
00617   if(message->message_body != NULL) {
00618     free(message->message_body);
00619     message->message_body = NULL;
00620   }
00621   if(message->update_name != NULL) {
00622     free(message->update_name);
00623   }
00624   if(message->from_address != NULL) {
00625     free(message->from_address);
00626   }
00627   if(message->to_address != NULL) {
00628     free(message->to_address);
00629   }
00630   if(message->target != NULL) {
00631     free(message->target);
00632   }
00633 
00634   free(message);
00635   message = NULL;
00636   return MC_SUCCESS;
00637 }
00638 
00639   int
00640 message_Send(message_p message)
00641 {
00642   char *buffer;
00643   mtp_http_t* mtp_http;
00644   int n;
00645 #ifndef _WIN32
00646   int skt;
00647   struct sockaddr_in sktin;
00648 #else
00649   SOCKET skt;
00650   SOCKADDR_IN sktin;
00651 #endif
00652   struct hostent *host;
00653   char *buf;
00654   char *hostname;
00655 #ifndef _WIN32
00656   char *saveptr; /* For reentrant strtok_r */
00657 #endif
00658   int port;
00659 
00660   /* Compose the http message */
00661   if (
00662       mtp_http_ComposeMessage(
00663         message
00664         )
00665      )
00666   {
00667      return MC_ERR;
00668   }
00669 
00670   /* We need to split up the address into a hostname and port. */
00671   buf = (char*)malloc(sizeof(char)*(strlen(message->to_address)+1));
00672   strcpy(buf, message->to_address);
00673   hostname = strtok_r(buf, ":", &saveptr);
00674   sscanf( strtok_r(NULL, ":", &saveptr), "%d", &port );
00675 
00676   if((skt = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
00677   { 
00678     fprintf(stderr, "Error - can't create socket\n");
00679     return -1;
00680   }
00681 
00682   memset(&sktin, 0, sizeof(sktin));
00683   sktin.sin_family = PF_INET;
00684   sktin.sin_port = htons(port);
00685 
00686   if((host = gethostbyname(hostname))) 
00687   {
00688     memcpy(&sktin.sin_addr, host->h_addr, host->h_length);
00689   }
00690   else if((sktin.sin_addr.s_addr = inet_addr(hostname)) < 0) 
00691   {
00692     fprintf(stderr, "Error - can't get host entry for %s\n", hostname);
00693     free(buf);
00694     return -1;
00695   }
00696 
00697   if(connect(skt, (struct sockaddr *) &sktin, sizeof(sktin)) < 0) {
00698     fprintf(stderr, "Error - can't connect to %s:%d\n",
00699         hostname,
00700         port
00701         );
00702     free(buf);
00703     return MC_ERR_CONNECT;
00704   }
00705   /* now send the string */
00706   if(send(skt, message->message_body, strlen(message->message_body), 0) < 0) 
00707   {
00708     fprintf(stderr, "cannot write to socket %s:%d\n",
00709         __FILE__, __LINE__);
00710 #ifndef _WIN32
00711     close(skt);
00712 #else
00713     closesocket(skt);
00714 #endif
00715     free(buf);
00716     return MC_ERR_SEND;
00717   }
00718   /* Now we should receive an HTTP response */
00719   buffer = (char*) malloc(sizeof(char) * (SOCKET_INPUT_SIZE + 1));
00720   CHECK_NULL(buffer, exit(0););
00721   mtp_http = mtp_http_New();
00722 #ifndef _WIN32
00723   n = recvfrom(skt,
00724       (void *) buffer,
00725       (size_t) sizeof(char)*SOCKET_INPUT_SIZE,
00726       0,
00727       (struct sockaddr *) 0,
00728       (socklen_t *) 0);
00729 #else
00730   n = recvfrom(skt,
00731       (void *) buffer,
00732       (size_t) sizeof(char)*SOCKET_INPUT_SIZE,
00733       0,
00734       (struct sockaddr *) 0,
00735       0);
00736 #endif
00737   if( mtp_http_Parse(mtp_http, buffer) ) {
00738     fprintf(stderr, "http parsing error: Response expected. %s:%d\n",
00739         __FILE__, __LINE__);
00740     fprintf(stderr, "Received message was:\n%s\n", buffer);
00741   }
00742   if (mtp_http->response_code != 200) {
00743     fprintf(stderr, "Warning: remote http server responded: %d %s\n",
00744         mtp_http->response_code, mtp_http->response_string );
00745   }
00746 
00747 #ifndef _WIN32
00748   close(skt);
00749 #else
00750   closesocket(skt);
00751 #endif
00752   free(buf);
00753   return 0;
00754 }
00755 
00756 

Generated on Mon Jun 23 16:01:10 2008 for Mobile-C by  doxygen 1.5.4