void doBusyWorkForTicks(uint32_t numTicks){ MQX_TICK_STRUCT currentTime; _time_get_ticks(¤tTime); uint32_t ticksRun = 0; uint32_t currentTicks = currentTime.TICKS[0]; uint32_t previousTicks = currentTime.TICKS[0]; do{ _time_get_ticks(¤tTime); currentTicks = currentTime.TICKS[0]; if(currentTicks > previousTicks){ ticksRun++; // The ticks run is only updated if the system clock ticks have increased previousTicks = currentTicks; } } while(ticksRun < numTicks); }
/*! * \brief This function receives a message from the specified endpoint if one is available. The data is NOT copied into the user-app. buffer. * * This is the "zero-copy receive" version of the MCC receive function. No data is copied. * Only the pointer to the data is returned. This version is fast, but it requires the user to manage * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and * make the appropriate API call to free it. * * \param[in] endpoint Pointer to the receiving endpoint to receive from. * \param[out] buffer_p Pointer to the MCC buffer of the shared memory where the received data is stored. * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of valid bytes in the buffer. * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). * * \return MCC_SUCCESS * \return MCC_ERR_ENDPOINT (the endpoint does not exist) * \return MCC_ERR_SEMAPHORE (semaphore handling error) * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came) * * \see mcc_send * \see mcc_recv_copy * \see MCC_ENDPOINT */ int mcc_recv_nocopy(MCC_ENDPOINT *endpoint, void **buffer_p, MCC_MEM_SIZE *recv_size, unsigned int timeout_us) { MCC_RECEIVE_LIST *list; int return_value; #if (MCC_OS_USED == MCC_MQX) unsigned int time_us_tmp; unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE; unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE; MQX_TICK_STRUCT tick_time; #endif /* Semaphore-protected section start */ return_value = mcc_get_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Get list of buffers kept by the particular endpoint */ list = mcc_get_endpoint_list(*endpoint); /* Semaphore-protected section end */ return_value = mcc_release_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* The endpoint is not valid */ if(list == null) { return MCC_ERR_ENDPOINT; } if(list->head == (MCC_RECEIVE_BUFFER*)0) { /* Non-blocking call */ if(timeout_us == 0) { return MCC_ERR_TIMEOUT; } /* Blocking call */ else { #if (MCC_OS_USED == MCC_MQX) if(timeout_us == 0xFFFFFFFF) { _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0); } /* timeout_us > 0 */ else { _time_get_ticks(&tick_time); _time_add_usec_to_ticks(&tick_time, timeout_us); _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time); } #endif MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*)); } } /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */ _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index); if(list->head == (MCC_RECEIVE_BUFFER*)0) { /* Buffer not dequeued before the timeout */ return MCC_ERR_TIMEOUT; } /* Get the message pointer from the head of the receive buffer list */ MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len); *buffer_p = (void*)&list->head->data; MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE)); *recv_size = (MCC_MEM_SIZE)(list->head->data_len); /* Semaphore-protected section start */ return_value = mcc_get_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Dequeue the buffer from the endpoint list */ mcc_dequeue_buffer(list); /* Semaphore-protected section end */ return_value = mcc_release_semaphore(); if(return_value != MCC_SUCCESS) return return_value; return return_value; }
/*! * \brief This function receives a message from the specified endpoint if one is available. * The data will be copied from the receive buffer into the user supplied buffer. * * This is the "receive with copy" version of the MCC receive function. This version is simple * to use but it requires copying data from shared memory into the user space buffer. * The user has no obligation or burden to manage the shared memory buffers. * * \param[in] endpoint Pointer to the receiving endpoint to receive from. * \param[in] buffer Pointer to the user-app. buffer where data will be copied into. * \param[in] buffer_size The maximum number of bytes to copy. * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of bytes actually copied into the buffer. * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). * * \return MCC_SUCCESS * \return MCC_ERR_ENDPOINT (the endpoint does not exist) * \return MCC_ERR_SEMAPHORE (semaphore handling error) * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came) * * \see mcc_send * \see mcc_recv_nocopy * \see MCC_ENDPOINT */ int mcc_recv_copy(MCC_ENDPOINT *endpoint, void *buffer, MCC_MEM_SIZE buffer_size, MCC_MEM_SIZE *recv_size, unsigned int timeout_us) { MCC_RECEIVE_LIST *list; MCC_RECEIVE_BUFFER * buf; MCC_SIGNAL affiliated_signal; MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0}; int return_value, i = 0; #if (MCC_OS_USED == MCC_MQX) unsigned int time_us_tmp; unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE; unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE; MQX_TICK_STRUCT tick_time; #endif /* Semaphore-protected section start */ return_value = mcc_get_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Get list of buffers kept by the particular endpoint */ list = mcc_get_endpoint_list(*endpoint); /* Semaphore-protected section end */ return_value = mcc_release_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* The endpoint is not valid */ if(list == null) { return MCC_ERR_ENDPOINT; } if(list->head == (MCC_RECEIVE_BUFFER*)0) { /* Non-blocking call */ if(timeout_us == 0) { return MCC_ERR_TIMEOUT; } /* Blocking call */ else { #if (MCC_OS_USED == MCC_MQX) if(timeout_us == 0xFFFFFFFF) { _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0); } /* timeout_us > 0 */ else { _time_get_ticks(&tick_time); _time_add_usec_to_ticks(&tick_time, timeout_us); _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time); } #endif MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*)); } } /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */ _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index); if(list->head == (MCC_RECEIVE_BUFFER*)0) { /* Buffer not dequeued before the timeout */ return MCC_ERR_TIMEOUT; } /* Copy the message from the MCC receive buffer into the user-app. buffer */ MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE)); if (list->head->data_len > buffer_size) { list->head->data_len = buffer_size; } *recv_size = (MCC_MEM_SIZE)(list->head->data_len); MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len); mcc_memcpy((void*)list->head->data, buffer, list->head->data_len); /* Semaphore-protected section start */ return_value = mcc_get_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Dequeue the buffer from the endpoint list */ buf = mcc_dequeue_buffer(list); /* Enqueue the buffer into the free list */ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); mcc_queue_buffer(&bookeeping_data->free_list, buf); /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */ affiliated_signal.type = BUFFER_FREED; affiliated_signal.destination = tmp_destination; for (i=0; i<MCC_NUM_CORES; i++) { if(i != MCC_CORE_NUMBER) { mcc_queue_signal(i, affiliated_signal); } } mcc_generate_cpu_to_cpu_interrupt(); /* Semaphore-protected section end */ return_value = mcc_release_semaphore(); if(return_value != MCC_SUCCESS) return return_value; return return_value; }
/*! * \brief This function sends a message to an endpoint. * * The message is copied into the MCC buffer and the destination core is signaled. * * \param[in] endpoint Pointer to the receiving endpoint to send to. * \param[in] msg Pointer to the message to be sent. * \param[in] msg_size Size of the message to be sent in bytes. * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call). * * \return MCC_SUCCESS * \return MCC_ERR_ENDPOINT (the endpoint does not exist) * \return MCC_ERR_SEMAPHORE (semaphore handling error) * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer) * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available) * \return MCC_ERR_NOMEM (no free buffer available and timeout_us set to 0) * \return MCC_ERR_SQ_FULL (signal queue is full) * * \see mcc_recv_copy * \see mcc_recv_nocopy * \see MCC_ENDPOINT */ int mcc_send(MCC_ENDPOINT *endpoint, void *msg, MCC_MEM_SIZE msg_size, unsigned int timeout_us) { int return_value, end_time_set_flag = 0; MCC_RECEIVE_LIST *list; MCC_RECEIVE_BUFFER * buf; MCC_SIGNAL affiliated_signal; #if (MCC_OS_USED == MCC_MQX) unsigned int time_us_tmp; MQX_TICK_STRUCT tick_time; #endif /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */ if(msg_size > sizeof(bookeeping_data->r_buffers[0].data)) { return MCC_ERR_INVAL; } /* Semaphore-protected section start */ return_value = mcc_get_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Dequeue the buffer from the free list */ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); buf = mcc_dequeue_buffer(&bookeeping_data->free_list); while(buf == null) { mcc_release_semaphore(); /* Non-blocking call */ if(timeout_us == 0) { return MCC_ERR_NOMEM; } /* Blocking calls: CPU-to-CPU ISR sets the event and thus resumes tasks waiting for a free MCC buffer. * As the interrupt request is send to all cores when a buffer is freed it could happen that several * tasks from different cores/nodes are waiting for a free buffer and all of them are notified that the buffer * has been freed. This function has to check (after the wake up) that a buffer is really available and has not been already * grabbed by another "competitor task" that has been faster. If so, it has to wait again for the next notification. */ /* wait forever */ else if(timeout_us == 0xFFFFFFFF) { #if (MCC_OS_USED == MCC_MQX) _lwevent_wait_ticks(&lwevent_buffer_freed, 1, TRUE, 0); _lwevent_clear(&lwevent_buffer_freed, 1); #endif } /* timeout_us > 0 */ else { #if (MCC_OS_USED == MCC_MQX) if(!end_time_set_flag) { _time_get_ticks(&tick_time); _time_add_usec_to_ticks(&tick_time, timeout_us); end_time_set_flag = 1; } return_value = _lwevent_wait_until(&lwevent_buffer_freed, 1, TRUE, &tick_time); if(return_value == LWEVENT_WAIT_TIMEOUT) { /* Buffer not dequeued before the timeout */ return MCC_ERR_TIMEOUT; } _lwevent_clear(&lwevent_buffer_freed, 1); #endif } MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); mcc_get_semaphore(); buf = mcc_dequeue_buffer(&bookeeping_data->free_list); } /* Semaphore-protected section end */ mcc_release_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Copy the message into the MCC receive buffer */ mcc_memcpy(msg, (void*)buf->data, (unsigned int)msg_size); MCC_DCACHE_FLUSH_MLINES((void*)buf->data, msg_size); buf->data_len = msg_size; MCC_DCACHE_FLUSH_MLINES((void*)&buf->data_len, sizeof(MCC_MEM_SIZE)); /* Semaphore-protected section start */ return_value = mcc_get_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Get list of buffers kept by the particular endpoint */ list = mcc_get_endpoint_list(*endpoint); if(list == null) { /* The endpoint does not exists (has not been registered so far), free the buffer and return immediately - error */ /* Enqueue the buffer back into the free list */ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); mcc_queue_buffer(&bookeeping_data->free_list, buf); mcc_release_semaphore(); return MCC_ERR_ENDPOINT; } /* Write the signal type into the signal queue of the particular core */ affiliated_signal.type = BUFFER_QUEUED; affiliated_signal.destination = *endpoint; return_value = mcc_queue_signal(endpoint->core, affiliated_signal); if(return_value != MCC_SUCCESS) { /* Signal queue is full, free the buffer and return immediately - error */ MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*)); mcc_queue_buffer(&bookeeping_data->free_list, buf); mcc_release_semaphore(); return return_value; } /* Enqueue the buffer into the endpoint buffer list */ mcc_queue_buffer(list, buf); /* Semaphore-protected section end */ mcc_release_semaphore(); if(return_value != MCC_SUCCESS) return return_value; /* Signal the other core by generating the CPU-to-CPU interrupt */ return_value = mcc_generate_cpu_to_cpu_interrupt(); return return_value; }
void SEC_EmailAlert() { MQX_TICK_STRUCT ticks; MQX_XDATE_STRUCT xdate; sockaddr addr; _ip_address ipaddr; uint_32 sock; uint_32 error; uint_32 option; char_ptr event_ptr; char temp[150]; char domain[30]; char user[30]; #if DEMOCFG_AUTH_REQUIRED char temp_encoded[40]; #endif if (!RTCS_resolve_ip_address(EMAIL_SERVER,&ipaddr,NULL,0)) { printf("Error resolving IP address for %s using DNS Server at %d.%d.%d.%d\n", EMAIL_SERVER, IPBYTES(ipcfg_get_dns_ip(BSP_DEFAULT_ENET_DEVICE, 0))); return; } /* Create socket */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == RTCS_SOCKET_ERROR) { printf("Error creating socket\n"); return; } /* Reduce buffer size of socket to save memory */ option = SMTP_BUFFER_SIZE; error = setsockopt(sock, SOL_TCP, OPT_TBSIZE, &option, sizeof(option)); option = SMTP_BUFFER_SIZE; error = setsockopt(sock, SOL_TCP, OPT_RBSIZE, &option, sizeof(option)); option = 1000; error = setsockopt(sock, SOL_TCP, OPT_TIMEWAIT_TIMEOUT, &option, sizeof(option)); /* Allow binding to any address */ #if RTCSCFG_ENABLE_IP4 ((sockaddr_in*)(&addr))->sin_family = AF_INET; ((sockaddr_in*)(&addr))->sin_port = 0; ((sockaddr_in*)(&addr))->sin_addr.s_addr = INADDR_ANY; #elif RTCSCFG_ENABLE_IP6 printf("\nThis application don't support IPv6 only.\n"); _task_block(); #endif error = bind(sock, &addr, sizeof(addr)); if (error != RTCS_OK) { printf("Error in binding socket %08x\n",error); shutdown(sock, FLAG_ABORT_CONNECTION); return; } /* Connect to SMTP server */ #if RTCSCFG_ENABLE_IP4 ((sockaddr_in*)(&addr))->sin_port = IPPORT_SMTP; ((sockaddr_in*)(&addr))->sin_addr.s_addr = ipaddr; #elif RTCSCFG_ENABLE_IP6 printf("\nThis application does not support IPv6 only.\n"); _task_block(); #endif error = connect(sock, &addr, sizeof(addr)); if (error != RTCS_OK) { printf("Error in connection %08x\n",error); shutdown(sock, FLAG_ABORT_CONNECTION); return; } printf("\nConnecting to SMTP server %s...\n",EMAIL_SERVER); printf("SMTP Server Response:\n"); SMTP_Receive_string(sock, temp, sizeof(temp)); /* Follow SMTP protocol to send email */ /* Parse domain name from the FROM address, for use with the EHLO or HELO commands */ sscanf(EMAIL_FROM,"%30s@%30s",user,domain); #if DEMOCFG_AUTH_REQUIRED /* If Authentification is required, use EHLO command */ SMTP_Send_command(sock, "EHLO", domain, temp, sizeof(temp)); SMTP_Send_command(sock,"AUTH LOGIN",NULL,temp,sizeof(temp)); /* Find base64 econding of login name and send to SMTP server */ sprintf(temp,"%s\r\n",base64_encode(AUTH_USERNAME,temp_encoded)); SMTP_Send_string(sock,temp); SMTP_Receive_string(sock,temp,sizeof(temp)-1); /* Find base64 econding of password and send to SMTP server */ sprintf(temp,"%s\r\n",base64_encode(AUTH_PASSWORD,temp_encoded)); SMTP_Send_string(sock,temp); SMTP_Receive_string(sock,temp, sizeof(temp)-1); #else /* If Authentification is not required, use HELO command as not all servers recognize EHLO */ SMTP_Send_command(sock, "HELO", domain, temp, sizeof(temp)); #endif /* Transfer sender email address to server */ SMTP_Send_command(sock,"MAIL FROM:","<" EMAIL_FROM ">" ,temp,sizeof(temp)); /* Transfer recipient email address to server */ SMTP_Send_command(sock,"RCPT TO:","<" EMAIL_TO ">" ,temp,sizeof(temp)); /* Start DATA section */ SMTP_Send_command(sock,"DATA",NULL,temp,sizeof(temp)); printf("Sent:\n"); /* Send Subject, To, and From fields */ SMTP_Send_string(sock,(pointer)Email_header); /* Determine what to send as body of message */ _time_get_ticks(&ticks); _time_ticks_to_xdate(&ticks,&xdate); sprintf(temp, "Date: %s, %d %s %d %02d:%02d:%02d -0000\r\n\r\n", wday[xdate.WDAY],xdate.MDAY, months[xdate.MONTH-1],xdate.YEAR, xdate.HOUR, xdate.MIN, xdate.SEC ); SMTP_Send_string(sock,temp); /* If button pushed was the "Door"... */ if(SEC_Params.Status==SEC_DOOR_OPEN_STATUS) { event_ptr = "Door was opened "; } else /* If button pushed was the "Window"... */ if(SEC_Params.Status==SEC_WINDOW_OPEN_STATUS) { event_ptr = "Window was opened "; } /* If not sure what caused stop mode to exit... */ else { event_ptr = "Unknown event occurred "; } SMTP_Send_string(sock,event_ptr); /* If SNTP enabled, then send exact date and time button press happened */ #if DEMOCFG_ENABLE_SNTP sprintf(temp,"on %d/%d/%d at %02d:%02d:%02d GMT. \r\n",xdate.MONTH,xdate.MDAY,xdate.YEAR,xdate.HOUR,xdate.MIN,xdate.SEC); /* If SNTP not enabled, then give elapsed time instead */ #else sprintf(temp,"%02d:%02d:%02d after system was started. \r\n",xdate.HOUR,xdate.MIN,xdate.SEC); #endif SMTP_Send_string(sock,temp); if (last[0]) { /* Send out how long ago the last event was */ SMTP_Send_string(sock,"Previous event was "); SMTP_Send_string(sock,last); } strcpy(last,temp); /* Send Freescale signature and disconnect from server with QUIT command */ SMTP_Send_string(sock,"\r\n-Freescale Semiconductor\r\n.\r\n"); SMTP_Send_command(sock,"QUIT",NULL,temp,sizeof(temp)); /* Close socket */ shutdown(sock, FLAG_CLOSE_TX); }
int_32 Shell_smtp (int_32 argc, char_ptr argv[]) { struct addrinfo hints; struct addrinfo *result, *rp; int_32 retval = 0; uint_32 sfd = 0; int_32 err_code = 0; boolean print_help; boolean shorthelp = FALSE; SMTP_PARAM_STRUCT params; char_ptr errstr = NULL; char_ptr server = NULL; char_ptr optstring = ":f:t:s:u:p:m:h"; int_32 next_option; char_ptr email_text = NULL; uint_32 email_size = 0; MQX_TICK_STRUCT ticks; MQX_XDATE_STRUCT xdate; char date_str[DATE_LENGTH]; params.login = NULL; params.pass = NULL; print_help = Shell_check_help_request(argc, argv, &shorthelp); if (print_help) { if (!shorthelp) { fprintf(stdout,"Usage:"); } fprintf(stdout, "%s", argv[0]); print_usage(stdout, shorthelp); err_code = SHELL_EXIT_SUCCESS; return(err_code); } /* Parse command line options */ do { next_option = Shell_getopt(argc, argv, optstring); switch (next_option) { case 'f': params.envelope.from = optarg; break; case 't': params.envelope.to = optarg; break; case 'm': params.text = optarg; break; case 's': server = optarg; break; case 'u': params.login = optarg; break; case 'p': params.pass = optarg; break; case 'h': print_usage (stdout, FALSE); return(SHELL_EXIT_SUCCESS); case '?': /* The user specified an invalid option. */ print_usage(stderr, TRUE); return(SHELL_EXIT_ERROR); case ':': /* Option has a missing parameter. */ printf("Option -%c requires a parameter.\n", next_option); return(SHELL_EXIT_ERROR); case -1: /* Done with options. */ break; default: break; } }while(next_option != -1); _time_get_ticks(&ticks); _time_ticks_to_xdate(&ticks,&xdate); snprintf(date_str, DATE_LENGTH, "%s, %d %s %d %02d:%02d:%02d -0000", wday[xdate.WDAY],xdate.MDAY, months[xdate.MONTH-1],xdate.YEAR, xdate.HOUR, xdate.MIN, xdate.SEC); /* Evaluate email size */ email_size = strlen(params.envelope.from) + strlen(params.envelope.to) + strlen(params.text) + strlen(date_str) + strlen("From: <>\r\n") + strlen("To: <>\r\n") + strlen("Subject: Freescale Tower Email\r\n") + strlen("Date: \r\n\r\n") + strlen("\r\n") + 1; /* Allocate space */ email_text = (char_ptr) _mem_alloc_zero(email_size); if (email_text == NULL) { fprintf(stderr, " Unable to allocate memory for email message.\n"); err_code = SHELL_EXIT_ERROR; return(err_code); } /* Prepare email message */ snprintf(email_text, email_size, "From: <%s>\r\n" "To: <%s>\r\n" "Subject: Freescale Tower Email\r\n" "Date: %s\r\n\r\n" "%s\r\n", params.envelope.from, params.envelope.to, date_str, params.text); params.text = email_text; _mem_zero(&hints, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* TCP socket */ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; retval = getaddrinfo(server, NULL, &hints, &result); if (retval != 0) { fprintf(stderr, " getaddrinfo failed. Error: 0x%X\n", retval); err_code = SHELL_EXIT_ERROR; return(err_code); } /* Allocate buffer for error message */ errstr = (char_ptr) _mem_alloc_system_zero(ERR_MSG_BUFF_SIZE); /* Try to send email using one of addresses. If it fails try another one. */ for (rp = result; rp != NULL; rp = rp->ai_next) { _mem_copy(rp->ai_addr, ¶ms.server, sizeof(params.server)); /* Try to send email */ retval = SMTP_send_email(¶ms, errstr, ERR_MSG_BUFF_SIZE); /* If connection failed try another address */ if (retval != SMTP_ERR_CONN_FAILED) { break; } } /* No address succeeded */ if (rp == NULL) { fprintf(stderr, " Unable to connect to %s.\n", server); err_code = SHELL_EXIT_ERROR; } if (retval != SMTP_OK) { printf(" Email sending failed%s %s\n", (strlen(errstr) > 0) ? ":":".", errstr); err_code = SHELL_EXIT_ERROR; } else { printf(" Email send. Server response: %s", errstr); } /* Cleanup */ freeaddrinfo(result); _mem_free(errstr); _mem_free(email_text); return(err_code); }