void udpDiscardTask(void *param) { error_t error; size_t length; uint16_t port; IpAddr ipAddr; DiscardServiceContext *context; //Get a pointer to the context context = (DiscardServiceContext *) param; //Main loop while(1) { //Wait for an incoming datagram error = socketReceiveFrom(context->socket, &ipAddr, &port, context->buffer, DISCARD_BUFFER_SIZE, &length, 0); //Any datagram received? if(!error) { //Debug message TRACE_INFO("Discard service: %" PRIuSIZE " bytes received from %s port %" PRIu16 "\r\n", length, ipAddrToString(&ipAddr, NULL), port); //Throw away any received datagram... } } }
void udpChargenTask(void *param) { error_t error; size_t i; size_t k; size_t n; size_t length; uint16_t port; IpAddr ipAddr; ChargenServiceContext *context; //Get a pointer to the context context = (ChargenServiceContext *) param; //Main loop while(1) { //Wait for an incoming datagram error = socketReceiveFrom(context->socket, &ipAddr, &port, context->buffer, CHARGEN_BUFFER_SIZE, &n, 0); //Any datagram received? if(!error) { //When a datagram is received, an answering datagram is sent //containing a random number (between 0 and 512) of characters length = tcpIpStackGetRand() % 513; //Reset line counter n = 0; //Format output data for(i = 0; i < length; i += 74) { //Calculate the length of the current line k = min(length - i, 74); //Copy character pattern memcpy(context->buffer + i, pattern + n, k); //End each line with carriage return and line feed if(k == 74) { context->buffer[i + 72] = '\r'; context->buffer[i + 73] = '\n'; } //Increment line counter if(++n >= 95) n = 0; } //Send data to the remote host error = socketSendTo(context->socket, &ipAddr, port, context->buffer, length, &n, 0); //Debug message TRACE_INFO("Chargen service: %" PRIuSIZE " bytes sent to %s port %" PRIu16 "\r\n", n, ipAddrToString(&ipAddr, NULL), port); } } }
void udpEchoTask(void *param) { error_t error; uint_t length; uint16_t port; IpAddr ipAddr; EchoServiceContext *context; //Get a pointer to the context context = (EchoServiceContext *) param; //Main loop while(1) { //Wait for an incoming datagram error = socketReceiveFrom(context->socket, &ipAddr, &port, context->buffer, ECHO_BUFFER_SIZE, &length, 0); //Any datagram received? if(!error) { //Debug message TRACE_INFO("Echo service: %u bytes received from %s port %u\r\n", length, ipAddrToString(&ipAddr, NULL), port); //Send the data back to the source error = socketSendTo(context->socket, &ipAddr, port, context->buffer, length, NULL, 0); } } }
error_t sntpClientTest(void) { error_t error; time_t unixTime; IpAddr ipAddr; NtpTimestamp timestamp; DateTime date; //Debug message TRACE_INFO("\r\n\r\nResolving server name...\r\n"); //Resolve SNTP server name error = getHostByName(NULL, "0.fr.pool.ntp.org", &ipAddr, 0); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to resolve server name!\r\n"); //Exit immediately return error; } //Debug message TRACE_INFO("Requesting time from SNTP server %s\r\n", ipAddrToString(&ipAddr, NULL)); //Retrieve current time from NTP server using SNTP protocol error = sntpClientGetTimestamp(NULL, &ipAddr, ×tamp); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to retrieve NTP timestamp!\r\n"); } else { //Unix time starts on January 1st, 1970 unixTime = timestamp.seconds - 2208988800; //Convert Unix timestamp to date convertUnixTimeToDate(unixTime, &date); //Debug message TRACE_INFO("Current date/time: %s\r\n", formatDate(&date, NULL)); //Move cursor lcdSetCursor(8, 0); //Refresh LCD display printf("%04u/%02u/%02u %02u:%02u:%02u", date.year, date.month, date.day, date.hours, date.minutes, date.seconds); } //Return status code return error; }
char * rawIpAddrToString(void *rawAddr, int len) { struct ipAddr addr; if (len == 4) { memcpy(&addr.addr.v4, rawAddr, 4); addr.domain = PF_INET; } else { memcpy(&addr.addr.v6, rawAddr, 16); addr.domain = PF_INET6; } return ipAddrToString(&addr); }
error_t dnsResolve(NetInterface *interface, const char_t *name, IpAddr *ipAddr) { error_t error; uint_t i; size_t length; uint16_t identifier; IpAddr serverIpAddr; Socket *socket; DnsHeader *dnsMessage; //Debug message TRACE_INFO("Trying to resolve %s...\r\n", name); //Use default network interface? if(!interface) interface = tcpIpStackGetDefaultInterface(); //Allocate a memory buffer to hold DNS messages dnsMessage = memPoolAlloc(DNS_MESSAGE_MAX_SIZE); //Failed to allocate memory? if(!dnsMessage) return ERROR_OUT_OF_MEMORY; //Open a UDP socket socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_PROTOCOL_UDP); //Failed to open socket? if(!socket) { //Free previously allocated memory osMemFree(dnsMessage); //Return status code return ERROR_OPEN_FAILED; } #if (IPV4_SUPPORT == ENABLED) //IP address of the DNS server serverIpAddr.length = sizeof(Ipv4Addr); serverIpAddr.ipv4Addr = interface->ipv4Config.dnsServer[0]; #elif (IPV6_SUPPORT == ENABLED) //IP address of the DNS server serverIpAddr.length = sizeof(Ipv6Addr); serverIpAddr.ipv6Addr = interface->ipv6Config.dnsServer[0]; #endif //Associate the socket with the relevant interface error = socketBindToInterface(socket, interface); //Any error to report? if(error) { //Free previously allocated memory osMemFree(dnsMessage); //Close socket socketClose(socket); //Return status code return error; } //Connect the newly created socket to the primary DNS server error = socketConnect(socket, &serverIpAddr, DNS_PORT); //Failed to connect? if(error) { //Free previously allocated memory osMemFree(dnsMessage); //Close socket socketClose(socket); //Return status code return error; } //An identifier is used by the client to match replies //with corresponding requests identifier = rand(); //Try to retransmit the DNS message if the previous query timed out for(i = 0; i < DNS_MAX_RETRIES; i++) { //Send DNS query message error = dnsSendQuery(socket, dnsMessage, identifier, name); //Failed to send message ? if(error) break; //Adjust receive timeout error = socketSetTimeout(socket, DNS_REQUEST_TIMEOUT); //Any error to report? if(error) break; //Wait for the server response error = socketReceive(socket, dnsMessage, DNS_MESSAGE_MAX_SIZE, &length, 0); //Any response from the specified DNS server? if(!error) { //Parse DNS response error = dnsParseResponse(dnsMessage, length, identifier, ipAddr); //DNS response successfully decoded? if(!error) break; } } //The maximum number of retransmissions has been reached? if(i >= DNS_MAX_RETRIES) error = ERROR_TIMEOUT; //Free previously allocated memory osMemFree(dnsMessage); //Close socket socketClose(socket); //Debug message if(!error) { //Name resolution succeeds TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL)); } else { //Report an error TRACE_ERROR("DNS resolution failed!\r\n"); } //Return status code return error; }
void tcpEchoListenerTask(void *param) { error_t error; uint16_t clientPort; IpAddr clientIpAddr; Socket *serverSocket; Socket *clientSocket; EchoServiceContext *context; OsTask *task; //Point to the listening socket serverSocket = (Socket *) param; //Main loop while(1) { //Accept an incoming connection clientSocket = socketAccept(serverSocket, &clientIpAddr, &clientPort); //Check whether a valid connection request has been received if(!clientSocket) continue; //Debug message TRACE_INFO("Echo service: connection established with client %s port %u\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort); //The socket operates in non-blocking mode error = socketSetTimeout(clientSocket, 0); //Any error to report? if(error) { //Close socket socketClose(clientSocket); //Wait for an incoming connection attempt continue; } //Allocate resources for the new connection context = osMemAlloc(sizeof(EchoServiceContext)); //Failed to allocate memory? if(!context) { //Close socket socketClose(clientSocket); //Wait for an incoming connection attempt continue; } //Record the handle of the newly created socket context->socket = clientSocket; //Create a task to service the current connection task = osTaskCreate("TCP Echo Connection", tcpEchoConnectionTask, context, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY); //Did we encounter an error? if(task == OS_INVALID_HANDLE) { //Close socket socketClose(clientSocket); //Release resources osMemFree(context); } } }
error_t ftpClientTest(void) { error_t error; size_t length; IpAddr ipAddr; FtpClientContext ftpContext; static char_t buffer[256]; //Debug message TRACE_INFO("\r\n\r\nResolving server name...\r\n"); //Resolve FTP server name error = getHostByName(NULL, "ftp.gnu.org", &ipAddr, 0); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to resolve server name!\r\n"); //Exit immediately return error; } //Debug message TRACE_INFO("Connecting to FTP server %s\r\n", ipAddrToString(&ipAddr, NULL)); //Connect to the FTP server error = ftpConnect(&ftpContext, NULL, &ipAddr, 21, FTP_NO_SECURITY | FTP_PASSIVE_MODE); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to connect to FTP server!\r\n"); //Exit immediately return error; } //Debug message TRACE_INFO("Successful connection\r\n"); //Start of exception handling block do { //Login to the FTP server using the provided username and password error = ftpLogin(&ftpContext, "anonymous", "password", ""); //Any error to report? if(error) break; //Open the specified file for reading error = ftpOpenFile(&ftpContext, "welcome.msg", FTP_FOR_READING | FTP_BINARY_TYPE); //Any error to report? if(error) break; //Dump the contents of the file while(1) { //Read data error = ftpReadFile(&ftpContext, buffer, sizeof(buffer) - 1, &length, 0); //End of file? if(error) break; //Properly terminate the string with a NULL character buffer[length] = '\0'; //Dump current data TRACE_INFO("%s", buffer); } //End the string with a line feed TRACE_INFO("\r\n"); //Close the file error = ftpCloseFile(&ftpContext); //End of exception handling block } while(0); //Close the connection ftpClose(&ftpContext); //Debug message TRACE_INFO("Connection closed...\r\n"); //Return status code return error; }
error_t snmpParseMessage(SnmpAgentContext *context, const uint8_t *p, size_t length) { error_t error; int32_t version; Asn1Tag tag; //Debug message TRACE_INFO("SNMP message received from %s port %" PRIu16 " (%" PRIuSIZE " bytes)...\r\n", ipAddrToString(&context->remoteIpAddr, NULL), context->remotePort, length); //Display the contents of the SNMP message TRACE_DEBUG_ARRAY(" ", p, length); //Dump ASN.1 structure error = asn1DumpObject(p, length, 0); //Any error to report? if(error) return error; //The SNMP message is encapsulated within a sequence error = asn1ReadTag(p, length, &tag); //Failed to decode ASN.1 tag? if(error) return error; //Enforce encoding, class and type error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE); //The tag does not match the criteria? if(error) return error; //Point to the first field of the sequence p = tag.value; length = tag.length; //Read version identifier error = asn1ReadInt32(p, length, &tag, &version); //Failed to decode ASN.1 tag? if(error) return error; //The SNMP agent verifies the version number. If there is a mismatch, //it discards the datagram and performs no further actions if(version != context->version) return ERROR_INVALID_VERSION; //Point to the next field p += tag.totalLength; length -= tag.totalLength; //Read SNMP community name error = asn1ReadTag(p, length, &tag); //Failed to decode ASN.1 tag? if(error) return error; //Enforce encoding, class and type error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); //The tag does not match the criteria? if(error) return error; //Save community name context->request.community = tag.value; context->request.communityLen = tag.length; //Point to the next field p += tag.totalLength; length -= tag.totalLength; //Read PDU error = asn1ReadTag(p, length, &tag); //Failed to decode ASN.1 tag? if(error) return error; //Check encoding if(tag.constructed != TRUE) return ERROR_WRONG_ENCODING; //Enforce class if(tag.class != ASN1_CLASS_CONTEXT_SPECIFIC) return ERROR_INVALID_CLASS; //Save PDU type context->request.pduType = (SnmpPduType) tag.type; //Process the protocol data unit switch(context->request.pduType) { case SNMP_PDU_GET_REQUEST: case SNMP_PDU_GET_NEXT_REQUEST: //Parse GetRequest-PDU or GetNextRequest-PDU error = snmpParseGetRequestPdu(context, tag.value, tag.length); break; case SNMP_PDU_GET_BULK_REQUEST: //Parse GetBulkRequest-PDU error = snmpParseGetBulkRequestPdu(context, tag.value, tag.length); break; case SNMP_PDU_SET_REQUEST: //Parse SetRequest-PDU error = snmpParseSetRequestPdu(context, tag.value, tag.length); break; default: //Invalid PDU type error = ERROR_INVALID_TYPE; break; } //Failed to parse PDU? if(error) return error; //Format response PDU header error = snmpWritePduHeader(context); //Any error to report? if(error) return error; //Debug message TRACE_INFO("SNMP message sent (%" PRIuSIZE " bytes)...\r\n", context->response.messageLen); //Display the contents of the SNMP message TRACE_DEBUG_ARRAY(" ", context->response.message, context->response.messageLen); //Display ASN.1 structure error = asn1DumpObject(context->response.message, context->response.messageLen, 0); //Any error to report? if(error) return error; //Send SNMP response message error = socketSendTo(context->socket, &context->remoteIpAddr, context->remotePort, context->response.message, context->response.messageLen, NULL, 0); //Return status code return error; }
error_t ssiProcessEchoCommand(HttpConnection *connection, const char_t *tag, size_t length) { error_t error; char_t *separator; char_t *attribute; char_t *value; //Discard invalid SSI directives if(length < 4 || length >= HTTP_SERVER_BUFFER_SIZE) return ERROR_INVALID_TAG; //Skip the SSI echo command (4 bytes) memcpy(connection->buffer, tag + 4, length - 4); //Ensure the resulting string is NULL-terminated connection->buffer[length - 4] = '\0'; //Check whether a separator is present separator = strchr(connection->buffer, '='); //Separator not found? if(!separator) return ERROR_INVALID_TAG; //Split the tag *separator = '\0'; //Get attribute name and value attribute = strTrimWhitespace(connection->buffer); value = strTrimWhitespace(separator + 1); //Remove leading simple or double quote if(value[0] == '\'' || value[0] == '\"') value++; //Get the length of the attribute value length = strlen(value); //Remove trailing simple or double quote if(length > 0) { if(value[length - 1] == '\'' || value[length - 1] == '\"') value[length - 1] = '\0'; } //Enforce attribute name if(strcasecmp(attribute, "var")) return ERROR_INVALID_TAG; //Remote address? if(!strcasecmp(value, "REMOTE_ADDR")) { //The IP address of the host making this request ipAddrToString(&connection->socket->remoteIpAddr, connection->buffer); } //Remote port? else if(!strcasecmp(value, "REMOTE_PORT")) { //The port number used by the remote host when making this request sprintf(connection->buffer, "%" PRIu16, connection->socket->remotePort); } //Server address? else if(!strcasecmp(value, "SERVER_ADDR")) { //The IP address of the server for this URL ipAddrToString(&connection->socket->localIpAddr, connection->buffer); } //Server port? else if(!strcasecmp(value, "SERVER_PORT")) { //The port number on this server to which this request was directed sprintf(connection->buffer, "%" PRIu16, connection->socket->localPort); } //Request method? else if(!strcasecmp(value, "REQUEST_METHOD")) { //The method used for this HTTP request strcpy(connection->buffer, connection->request.method); } //Document root? else if(!strcasecmp(value, "DOCUMENT_ROOT")) { //The root directory strcpy(connection->buffer, connection->settings->rootDirectory); } //Document URI? else if(!strcasecmp(value, "DOCUMENT_URI")) { //The URI for this request relative to the root directory strcpy(connection->buffer, connection->request.uri); } //Document name? else if(!strcasecmp(value, "DOCUMENT_NAME")) { //The full physical path and filename of the document requested httpGetAbsolutePath(connection, connection->request.uri, connection->buffer, HTTP_SERVER_BUFFER_SIZE); } //Query string? else if(!strcasecmp(value, "QUERY_STRING")) { //The information following the "?" in the URL for this request strcpy(connection->buffer, connection->request.queryString); } //User name? else if(!strcasecmp(value, "AUTH_USER")) { #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) //The username provided by the user to the server strcpy(connection->buffer, connection->request.auth.user); #else //Basic access authentication is not supported connection->buffer[0] = '\0'; #endif } //GMT time? else if(!strcasecmp(value, "DATE_GMT")) { //The current date and time in Greenwich Mean Time connection->buffer[0] = '\0'; } //Local time? else if(!strcasecmp(value, "DATE_LOCAL")) { //The current date and time in the local timezone connection->buffer[0] = '\0'; } //Unknown variable? else { //Report an error return ERROR_INVALID_TAG; } //Get the length of the resulting string length = strlen(connection->buffer); //Send the contents of the specified environment variable error = httpWriteStream(connection, connection->buffer, length); //Failed to send data? if(error) return error; //Successful processing return NO_ERROR; }
void httpListenerTask(void *param) { uint_t i; uint_t counter; uint16_t clientPort; IpAddr clientIpAddr; HttpServerContext *context; HttpConnection* connection; Socket *socket; //Retrieve the HTTP server context context = (HttpServerContext *) param; //Process incoming connections to the server for(counter = 1; ; counter++) { //Debug message TRACE_INFO("Ready to accept a new connection...\r\n"); //Limit the number of simultaneous connections to the HTTP server osWaitForSemaphore(&context->semaphore, INFINITE_DELAY); //Loop through available client connections for(i = 0; i < context->settings.maxConnections; i++) { //Point to the current connection connection = &context->connections[i]; //Ready to service the client request? if(!connection->running) { //Accept an incoming connection socket = socketAccept(context->socket, &clientIpAddr, &clientPort); //Make sure the socket handle is valid if(socket != NULL) { //Debug message TRACE_INFO("Connection #%u established with client %s port %" PRIu16 "...\r\n", counter, ipAddrToString(&clientIpAddr, NULL), clientPort); //Reference to the HTTP server settings connection->settings = &context->settings; //Reference to the HTTP server context connection->serverContext = context; //Reference to the new socket connection->socket = socket; //Set timeout for blocking functions socketSetTimeout(connection->socket, HTTP_SERVER_TIMEOUT); //The client connection task is now running... connection->running = TRUE; //Service the current connection request osSetEvent(&connection->startEvent); //We are done break; } } } } }
error_t nbnsResolve(NetInterface *interface, const char_t *name, IpAddr *ipAddr) { error_t error; DnsCacheEntry *entry; #if (NET_RTOS_SUPPORT == ENABLED) systime_t delay; //Debug message TRACE_INFO("Resolving host name %s (NBNS resolver)...\r\n", name); #endif //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, HOST_TYPE_IPV4, HOST_NAME_RESOLVER_NBNS); //Check whether a matching entry has been found if(entry) { //Host name already resolved? if(entry->state == DNS_STATE_RESOLVED || entry->state == DNS_STATE_PERMANENT) { //Return the corresponding IP address *ipAddr = entry->ipAddr; //Successful host name resolution error = NO_ERROR; } else { //Host name resolution is in progress... error = ERROR_IN_PROGRESS; } } else { //If no entry exists, then create a new one entry = dnsCreateEntry(); //Record the host name whose IP address is unknown strcpy(entry->name, name); //Initialize DNS cache entry entry->type = HOST_TYPE_IPV4; entry->protocol = HOST_NAME_RESOLVER_NBNS; entry->interface = interface; //Initialize retransmission counter entry->retransmitCount = NBNS_CLIENT_MAX_RETRIES; //Send NBNS query error = nbnsSendQuery(entry); //NBNS message successfully sent? if(!error) { //Save the time at which the query message was sent entry->timestamp = osGetSystemTime(); //Set timeout value entry->timeout = NBNS_CLIENT_INIT_TIMEOUT; entry->maxTimeout = NBNS_CLIENT_MAX_TIMEOUT; //Decrement retransmission counter entry->retransmitCount--; //Switch state entry->state = DNS_STATE_IN_PROGRESS; //Host name resolution is in progress error = ERROR_IN_PROGRESS; } } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); #if (NET_RTOS_SUPPORT == ENABLED) //Set default polling interval delay = DNS_CACHE_INIT_POLLING_INTERVAL; //Wait the host name resolution to complete while(error == ERROR_IN_PROGRESS) { //Wait until the next polling period osDelayTask(delay); //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, HOST_TYPE_IPV4, HOST_NAME_RESOLVER_NBNS); //Check whether a matching entry has been found if(entry) { //Host name successfully resolved? if(entry->state == DNS_STATE_RESOLVED) { //Return the corresponding IP address *ipAddr = entry->ipAddr; //Successful host name resolution error = NO_ERROR; } } else { //Host name resolution failed error = ERROR_FAILURE; } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); //Backoff support for less aggressive polling delay = MIN(delay * 2, DNS_CACHE_MAX_POLLING_INTERVAL); } //Check status code if(error) { //Failed to resolve host name TRACE_INFO("Host name resolution failed!\r\n"); } else { //Successful host name resolution TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL)); } #endif //Return status code return error; }
error_t sslClientTest(void) { error_t error; size_t length; IpAddr ipAddr; static char_t buffer[256]; //Underlying socket Socket *socket = NULL; //SSL/TLS context TlsContext *tlsContext = NULL; //Debug message TRACE_INFO("Resolving server name...\r\n"); //Resolve SSL server name error = getHostByName(NULL, APP_SERVER_NAME, &ipAddr, 0); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to resolve server name!\r\n"); //Exit immediately return error; } //Create a new socket to handle the request socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Any error to report? if(!socket) { //Debug message TRACE_INFO("Failed to open socket!\r\n"); //Exit immediately return ERROR_OPEN_FAILED; } //Start of exception handling block do { //Debug message TRACE_INFO("Connecting to SSL server %s\r\n", ipAddrToString(&ipAddr, NULL)); //Connect to the SSL server error = socketConnect(socket, &ipAddr, APP_SERVER_PORT); //Any error to report? if(error) break; //Initialize SSL/TLS context tlsContext = tlsInit(); //Initialization failed? if(!tlsContext) { //Report an error error = ERROR_OUT_OF_MEMORY; //Exit immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(tlsContext, socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(tlsContext, YARROW_PRNG_ALGO, &yarrowContext); //Any error to report? if(error) break; #if (APP_SET_CIPHER_SUITES == ENABLED) //Preferred cipher suite list error = tlsSetCipherSuites(tlsContext, cipherSuites, arraysize(cipherSuites)); //Any error to report? if(error) break; #endif #if (APP_SET_SERVER_NAME == ENABLED) //Set the fully qualified domain name of the server error = tlsSetServerName(tlsContext, APP_SERVER_NAME); //Any error to report? if(error) break; #endif #if (APP_SET_TRUSTED_CA_LIST == ENABLED) //Import the list of trusted CA certificates error = tlsSetTrustedCaList(tlsContext, trustedCaList, trustedCaListLength); //Any error to report? if(error) break; #endif #if (APP_SET_CLIENT_CERT == ENABLED) //Import the client's certificate error = tlsAddCertificate(tlsContext, clientCert, clientCertLength, clientPrivateKey, clientPrivateKeyLength); //Any error to report? if(error) break; #endif //Establish a secure session error = tlsConnect(tlsContext); //TLS handshake failure? if(error) break; //Format HTTP request sprintf(buffer, "GET %s HTTP/1.0\r\nHost: %s:%u\r\n\r\n", APP_REQUEST_URI, APP_SERVER_NAME, APP_SERVER_PORT); //Debug message TRACE_INFO("\r\n"); TRACE_INFO("HTTP request:\r\n%s", buffer); //Send the request error = tlsWrite(tlsContext, buffer, strlen(buffer), 0); //Any error to report? if(error) break; //Debug message TRACE_INFO("HTTP response:\r\n"); //Read the whole response while(1) { //Read data error = tlsRead(tlsContext, buffer, sizeof(buffer) - 1, &length, 0); //End of stream? if(error) break; //Properly terminate the string with a NULL character buffer[length] = '\0'; //Debug message TRACE_INFO("%s", buffer); } //Successfull processing error = NO_ERROR; //End of exception handling block } while(0); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to communicate with SSL server!\r\n"); } //Terminate TLS session tlsFree(tlsContext); //Close socket socketClose(socket); //Debug message TRACE_INFO("Connection closed...\r\n"); //Return status code return error; }
error_t httpClientTest(void) { error_t error; size_t length; IpAddr ipAddr; Socket *socket; static char_t buffer[256]; //Debug message TRACE_INFO("\r\n\r\nResolving server name...\r\n"); //Resolve HTTP server name error = getHostByName(NULL, CLIENT_SERVER_NAME, &ipAddr, 1, NULL, 0); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to resolve server name!\r\n"); //Exit immedialtely return error; } //Create a new socket to handle the request socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_PROTOCOL_TCP); //Any error to report? if(!socket) { //Debug message TRACE_INFO("Failed to open socket!\r\n"); //Exit immedialtely return error; } //Start of exception handling block do { //Debug message TRACE_INFO("Connecting to HTTP server %s\r\n", ipAddrToString(&ipAddr, NULL)); //Connect to the HTTP server error = socketConnect(socket, &ipAddr, CLIENT_SERVER_PORT); //Any error to report? if(error) break; //Debug message TRACE_INFO("Successful connection\r\n"); //Format HTTP request length = sprintf(buffer, "GET %s HTTP/1.0\r\nHost: %s:%u\r\n\r\n", CLIENT_REQUEST_URI, CLIENT_SERVER_NAME, CLIENT_SERVER_PORT); //Debug message TRACE_INFO("\r\nHTTP request:\r\n%s", buffer); //Send HTTP request error = socketSend(socket, buffer, length, NULL, 0); //Any error to report? if(error) break; //Debug message TRACE_INFO("HTTP response header:\r\n"); //Parse HTTP response header while(1) { //Read the header line by line error = socketReceive(socket, buffer, sizeof(buffer) - 1, &length, SOCKET_FLAG_BREAK_CRLF); //End of stream? if(error) break; //Properly terminate the string with a NULL character buffer[length] = '\0'; //Dump current data TRACE_INFO("%s", buffer); //The end of the header has been reached? if(!strcmp(buffer, "\r\n")) break; } //Debug message TRACE_INFO("HTTP response body:\r\n"); //Parse HTTP response body while(1) { //Read response body error = socketReceive(socket, buffer, sizeof(buffer) - 1, &length, 0); //End of stream? if(error) break; //Properly terminate the string with a NULL character buffer[length] = '\0'; //Dump current data TRACE_INFO("%s", buffer); } //End of exception handling block } while(0); //Close the connection socketClose(socket); //Debug message TRACE_INFO("\r\nConnection closed...\r\n"); //Return status code return error; }
error_t dnsResolve(NetInterface *interface, const char_t *name, HostType type, IpAddr *ipAddr) { error_t error; systime_t delay; DnsCacheEntry *entry; //Debug message TRACE_INFO("Resolving host name %s (DNS resolver)...\r\n", name); //Acquire exclusive access to the DNS cache osMutexAcquire(dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS); //Check whether a matching entry has been found if(entry) { //Host name already resolved? if(entry->state == DNS_STATE_RESOLVED || entry->state == DNS_STATE_PERMANENT) { //Return the corresponding IP address *ipAddr = entry->ipAddr; //Successful host name resolution error = NO_ERROR; } else { //Host name resolution is in progress... error = ERROR_IN_PROGRESS; } } else { //If no entry exists, then create a new one entry = dnsCreateEntry(); //Record the host name whose IP address is unknown strcpy(entry->name, name); //Initialize DNS cache entry entry->type = type; entry->protocol = HOST_NAME_RESOLVER_DNS; entry->interface = interface; //Select primary DNS server entry->dnsServerNum = 0; //Get an ephemeral port number entry->port = socketGetEphemeralPort(); //An identifier is used by the DNS client to match replies //with corresponding requests entry->id = tcpIpStackGetRand(); //Callback function to be called when a DNS response is received error = udpAttachRxCallback(interface, entry->port, dnsProcessResponse, NULL); //Check status code if(!error) { //Initialize retransmission counter entry->retransmitCount = DNS_CLIENT_MAX_RETRIES; //Send DNS query error = dnsSendQuery(entry); //DNS message successfully sent? if(!error) { //Save the time at which the query message was sent entry->timestamp = osGetTickCount(); //Set timeout value entry->timeout = DNS_CLIENT_INIT_TIMEOUT; entry->maxTimeout = DNS_CLIENT_MAX_TIMEOUT; //Decrement retransmission counter entry->retransmitCount--; //Switch state entry->state = DNS_STATE_IN_PROGRESS; //Host name resolution is in progress error = ERROR_IN_PROGRESS; } else { //Unregister callback function udpDetachRxCallback(interface, entry->port); } } } //Release exclusive access to the DNS cache osMutexRelease(dnsCacheMutex); //Set default polling interval delay = DNS_CACHE_INIT_POLLING_INTERVAL; //Wait the host name resolution to complete while(error == ERROR_IN_PROGRESS) { //Wait until the next polling period osDelay(delay); //Acquire exclusive access to the DNS cache osMutexAcquire(dnsCacheMutex); //Search the DNS cache for the specified host name entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS); //Check whether a matching entry has been found if(entry) { //Host name successfully resolved? if(entry->state == DNS_STATE_RESOLVED) { //Return the corresponding IP address *ipAddr = entry->ipAddr; //Successful host name resolution error = NO_ERROR; } } else { //Host name resolution failed error = ERROR_FAILURE; } //Release exclusive access to the DNS cache osMutexRelease(dnsCacheMutex); //Backoff support for less aggressive polling delay = min(delay * 2, DNS_CACHE_MAX_POLLING_INTERVAL); } //Check status code if(error) { //Failed to resolve host name TRACE_INFO("Host name resolution failed!\r\n"); } else { //Successful host name resolution TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL)); } //Return status code return error; }
error_t ping(NetInterface *interface, const IpAddr *ipAddr, time_t timeout, time_t *rtt) { error_t error; uint_t i; size_t length; uint16_t identifier; uint16_t sequenceNumber; time_t startTime; time_t roundTripTime; Socket *socket; IcmpEchoMessage *message; //Debug message TRACE_INFO("Pinging %s with 64 bytes of data...\r\n", ipAddrToString(ipAddr, NULL)); //Length of the complete ICMP message including header and data length = sizeof(IcmpEchoMessage) + PING_DATA_SIZE; //Allocate memory buffer to hold an ICMP message message = osMemAlloc(length); //Failed to allocate memory? if(!message) return ERROR_OUT_OF_MEMORY; //Identifier field is used to help matching requests and replies identifier = rand(); //Sequence Number field is increment each time an Echo Request is sent sequenceNumber = osAtomicInc16(&pingSequenceNumber); //Format ICMP Echo Request message message->type = ICMP_TYPE_ECHO_REQUEST; message->code = 0; message->checksum = 0; message->identifier = identifier; message->sequenceNumber = sequenceNumber; //Copy data for(i = 0; i < PING_DATA_SIZE; i++) message->data[i] = i; #if (IPV4_SUPPORT == ENABLED) //Target address is an IPv4 address? if(ipAddr->length == sizeof(Ipv4Addr)) { Ipv4Addr srcIpAddr; //Select the source IPv4 address and the relevant network //interface to use when pinging the specified host error = ipv4SelectSourceAddr(&interface, ipAddr->ipv4Addr, &srcIpAddr); //Any error to report? if(error) { //Free previously allocated memory osMemFree(message); //Return the corresponding error code return error; } //ICMP Echo Request message message->type = ICMP_TYPE_ECHO_REQUEST; //Message checksum calculation message->checksum = ipCalcChecksum(message, length); //Open a raw socket socket = socketOpen(SOCKET_TYPE_RAW, SOCKET_PROTOCOL_ICMP); } else #endif #if (IPV6_SUPPORT == ENABLED) //Target address is an IPv6 address? if(ipAddr->length == sizeof(Ipv6Addr)) { Ipv6PseudoHeader pseudoHeader; //Select the source IPv6 address and the relevant network //interface to use when pinging the specified host error = ipv6SelectSourceAddr(&interface, &ipAddr->ipv6Addr, &pseudoHeader.srcAddr); //Any error to report? if(error) { //Free previously allocated memory osMemFree(message); //Return the corresponding error code return error; } //ICMPv6 Echo Request message message->type = ICMPV6_TYPE_ECHO_REQUEST; //Format IPv6 pseudo header pseudoHeader.destAddr = ipAddr->ipv6Addr; pseudoHeader.length = htonl(length); pseudoHeader.reserved = 0; pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Message checksum calculation message->checksum = ipCalcUpperLayerChecksum( &pseudoHeader, sizeof(Ipv6PseudoHeader), message, length); //Open a raw socket socket = socketOpen(SOCKET_TYPE_RAW, SOCKET_PROTOCOL_ICMPV6); } else #endif //Target address is not valid? { //Free previously allocated memory osMemFree(message); //Report an error return ERROR_INVALID_ADDRESS; } //Failed to open socket? if(!socket) { //Free previously allocated memory osMemFree(message); //Report an error return ERROR_OPEN_FAILED; } //Associate the newly created socket with the relevant interface error = socketBindToInterface(socket, interface); //Unable to bind the socket to the desired interface? if(error) { //Free previously allocated memory osMemFree(message); //Close socket socketClose(socket); //Return status code return error; } //Connect the socket to the target host error = socketConnect(socket, ipAddr, 0); //Any error to report? if(error) { //Free previously allocated memory osMemFree(message); //Close socket socketClose(socket); //Return status code return error; } //Send Echo Request message error = socketSend(socket, message, length, NULL, 0); //Failed to send message ? if(error) { //Free previously allocated memory osMemFree(message); //Close socket socketClose(socket); //Return status code return error; } //Save the time at which the request was sent startTime = osGetTickCount(); //Timeout value exceeded? while((osGetTickCount() - startTime) < timeout) { //Adjust receive timeout error = socketSetTimeout(socket, timeout); //Any error to report? if(error) break; //Wait for an incoming ICMP message error = socketReceive(socket, message, sizeof(IcmpEchoMessage) + PING_DATA_SIZE, &length, 0); //Any error to report? if(error) break; //Check message length if(length != (sizeof(IcmpEchoMessage) + PING_DATA_SIZE)) continue; //Verify message type if(ipAddr->length == sizeof(Ipv4Addr) && message->type != ICMP_TYPE_ECHO_REPLY) continue; if(ipAddr->length == sizeof(Ipv6Addr) && message->type != ICMPV6_TYPE_ECHO_REPLY) continue; //Response identifier matches request identifier? if(message->identifier != identifier) continue; //Make sure the sequence number is correct if(message->sequenceNumber != sequenceNumber) continue; //Loop through data field for(i = 0; i < PING_DATA_SIZE; i++) { //Compare received data against expected data if(message->data[i] != i) break; } //Valid Echo Reply message received? if(i == PING_DATA_SIZE) { //Calculate round-trip time roundTripTime = osGetTickCount() - startTime; //Debug message TRACE_INFO("Echo received (round-trip time = %ums)...\r\n", roundTripTime); //Free previously allocated memory osMemFree(message); //Close socket socketClose(socket); //Return round-trip time if(rtt) *rtt = roundTripTime; //No error to report return NO_ERROR; } } //Debug message TRACE_INFO("No echo received!\r\n"); //Free previously allocated memory osMemFree(message); //Close socket socketClose(socket); //No Echo Reply received from host... return ERROR_NO_RESPONSE; }
void tcpDiscardListenerTask(void *param) { error_t error; uint16_t clientPort; IpAddr clientIpAddr; Socket *serverSocket; Socket *clientSocket; DiscardServiceContext *context; OsTask *task; //Point to the listening socket serverSocket = (Socket *) param; //Main loop while(1) { //Accept an incoming connection clientSocket = socketAccept(serverSocket, &clientIpAddr, &clientPort); //Check whether a valid connection request has been received if(!clientSocket) continue; //Debug message TRACE_INFO("Discard service: connection established with client %s port %" PRIu16 "\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort); //Adjust timeout error = socketSetTimeout(clientSocket, DISCARD_TIMEOUT); //Any error to report? if(error) { //Close socket socketClose(clientSocket); //Wait for an incoming connection attempt continue; } //Allocate resources for the new connection context = osAllocMem(sizeof(DiscardServiceContext)); //Failed to allocate memory? if(!context) { //Close socket socketClose(clientSocket); //Wait for an incoming connection attempt continue; } //Record the handle of the newly created socket context->socket = clientSocket; //Create a task to service the current connection task = osCreateTask("TCP Discard Connection", tcpDiscardConnectionTask, context, DISCARD_SERVICE_STACK_SIZE, DISCARD_SERVICE_PRIORITY); //Did we encounter an error? if(task == OS_INVALID_HANDLE) { //Close socket socketClose(clientSocket); //Release resources osFreeMem(context); } } }