error_t httpServerInit(HttpServerContext *context, const HttpServerSettings *settings) { error_t error; uint_t i; //Debug message TRACE_INFO("Initializing HTTP server...\r\n"); //Ensure the parameters are valid if(context == NULL || settings == NULL) return ERROR_INVALID_PARAMETER; //Check user settings if(settings->maxConnections == 0 || settings->connections == NULL) return ERROR_INVALID_PARAMETER; //Clear the HTTP server context memset(context, 0, sizeof(HttpServerContext)); //Save user settings context->settings = *settings; //Client connections context->connections = settings->connections; //Create a semaphore to limit the number of simultaneous connections if(!osCreateSemaphore(&context->semaphore, context->settings.maxConnections)) return ERROR_OUT_OF_RESOURCES; //Loop through client connections for(i = 0; i < context->settings.maxConnections; i++) { //Create an event object to manage connection lifetime if(!osCreateEvent(&context->connections[i].startEvent)) return ERROR_OUT_OF_RESOURCES; } #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) //Create a mutex to prevent simultaneous access to the nonce cache if(!osCreateMutex(&context->nonceCacheMutex)) return ERROR_OUT_OF_RESOURCES; #endif //Open a TCP socket context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->socket) return ERROR_OPEN_FAILED; //Set timeout for blocking functions error = socketSetTimeout(context->socket, INFINITE_DELAY); //Any error to report? if(error) return error; //Associate the socket with the relevant interface error = socketBindToInterface(context->socket, settings->interface); //Unable to bind the socket to the desired interface? if(error) return error; //Bind newly created socket to port 80 error = socketBind(context->socket, &IP_ADDR_ANY, settings->port); //Failed to bind socket to port 80? if(error) return error; //Place socket in listening state error = socketListen(context->socket, settings->backlog); //Any failure to report? if(error) return error; //Successful initialization return NO_ERROR; }
error_t sntpClientGetTimestamp(NetInterface *interface, const IpAddr *serverIpAddr, NtpTimestamp *timestamp) { error_t error; uint_t i; systime_t timeout; SntpClientContext context; //Check parameters if(serverIpAddr == NULL || timestamp == NULL) return ERROR_INVALID_PARAMETER; //Use default network interface? if(!interface) interface = netGetDefaultInterface(); //Open a UDP socket context.socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP); //Failed to open socket? if(!context.socket) return ERROR_OPEN_FAILED; //Associate the socket with the relevant interface error = socketBindToInterface(context.socket, interface); //Any error to report? if(error) { //Close socket socketClose(context.socket); //Return status code return error; } //Only accept datagrams from the specified NTP server error = socketConnect(context.socket, serverIpAddr, NTP_PORT); //Any error to report? if(error) { //Close socket socketClose(context.socket); //Return status code return error; } //Initial timeout value timeout = SNTP_CLIENT_INIT_TIMEOUT; //Retransmission loop for(i = 0; i < SNTP_CLIENT_MAX_RETRIES; i++) { //Send NTP request message error = sntpSendRequest(&context); //Failed to send message ? if(error) break; //Wait for a valid NTP response message error = sntpWaitForResponse(&context, timeout); //Valid NTP response received? if(!error) break; //The timeout value is doubled for each subsequent retransmission timeout = MIN(timeout * 2, SNTP_CLIENT_MAX_TIMEOUT); } //Successful processing? if(!error) { //Save server timestamp timestamp->seconds = ntohl(context.message.transmitTimestamp.seconds); timestamp->fraction = ntohl(context.message.transmitTimestamp.fraction); } //Close socket socketClose(context.socket); //Return status code return error; }
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; }
error_t dhcpv6RelayStart(Dhcpv6RelayCtx *context, const Dhcpv6RelaySettings *settings) { error_t error; uint_t i; OsTask *task; //Debug message TRACE_INFO("Starting DHCPv6 relay agent...\r\n"); //Ensure the parameters are valid if(!context || !settings) return ERROR_INVALID_PARAMETER; //The pointer to the network-facing interface shall be valid if(!settings->serverInterface) return ERROR_INVALID_INTERFACE; //Check the number of client-facing interfaces if(!settings->clientInterfaceCount) return ERROR_INVALID_PARAMETER; if(settings->clientInterfaceCount >= DHCPV6_RELAY_MAX_CLIENT_IF) return ERROR_INVALID_PARAMETER; //Loop through the client-facing interfaces for(i = 0; i < settings->clientInterfaceCount; i++) { //A valid pointer is required for each interface if(!settings->clientInterface[i]) return ERROR_INVALID_INTERFACE; } //Check the address to be used when forwarding messages to the server if(ipv6CompAddr(&settings->serverAddress, &IPV6_UNSPECIFIED_ADDR)) return ERROR_INVALID_ADDRESS; //Clear the DHCPv6 relay agent context memset(context, 0, sizeof(Dhcpv6RelayCtx)); //Save the network-facing interface context->serverInterface = settings->serverInterface; //Save the number of client-facing interfaces context->clientInterfaceCount = settings->clientInterfaceCount; //Save all the client-facing interfaces for(i = 0; i < context->clientInterfaceCount; i++) context->clientInterface[i] = settings->clientInterface[i]; //Save the address to be used when relaying client messages to the server context->serverAddress = settings->serverAddress; //Join the All_DHCP_Relay_Agents_and_Servers multicast group //for each client-facing interface error = dhcpv6RelayJoinMulticastGroup(context); //Any error to report? if(error) return error; //Start of exception handling block do { //Open a UDP socket to handle the network-facing interface context->serverSocket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP); //Failed to open socket? if(!context->serverSocket) { //Report an error error = ERROR_OPEN_FAILED; //Stop processing break; } //Explicitly associate the socket with the relevant interface error = socketBindToInterface(context->serverSocket, context->serverInterface); //Unable to bind the socket to the desired interface? if(error) break; //Relay agents listen for DHCPv6 messages on UDP port 547 error = socketBind(context->serverSocket, &IP_ADDR_ANY, DHCPV6_SERVER_PORT); //Unable to bind the socket to the desired port? if(error) break; //Only accept datagrams with source port number 547 error = socketConnect(context->serverSocket, &IP_ADDR_ANY, DHCPV6_SERVER_PORT); //Any error to report? if(error) break; //If the relay agent relays messages to the All_DHCP_Servers address //or other multicast addresses, it sets the Hop Limit field to 32 //Loop through the client-facing interfaces for(i = 0; i < context->clientInterfaceCount; i++) { //Open a UDP socket to handle the current interface context->clientSocket[i] = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP); //Failed to open socket? if(!context->clientSocket[i]) { //Report an error error = ERROR_OPEN_FAILED; //Stop processing break; } //Explicitly associate the socket with the relevant interface error = socketBindToInterface(context->clientSocket[i], context->clientInterface[i]); //Unable to bind the socket to the desired interface? if(error) break; //Relay agents listen for DHCPv6 messages on UDP port 547 error = socketBind(context->clientSocket[i], &IP_ADDR_ANY, DHCPV6_SERVER_PORT); //Unable to bind the socket to the desired port? if(error) break; //Only accept datagrams with source port number 546 error = socketConnect(context->clientSocket[i], &IP_ADDR_ANY, DHCPV6_CLIENT_PORT); //Any error to report? if(error) break; } //Propagate exception if necessary... if(error) break; //Create event objects context->event = osEventCreate(FALSE); context->ackEvent = osEventCreate(FALSE); //Out of resources? if(context->event == OS_INVALID_HANDLE || context->ackEvent == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop processing break; } //The DHCPv6 relay agent is now running context->running = TRUE; //Start the DHCPv6 relay agent service task = osTaskCreate("DHCPv6 Relay", dhcpv6RelayTask, context, DHCPV6_RELAY_STACK_SIZE, DHCPV6_RELAY_PRIORITY); //Unable to create the task? if(task == OS_INVALID_HANDLE) error = ERROR_OUT_OF_RESOURCES; //End of exception handling block } while(0); //Did we encounter an error? if(error) { //Close the socket associated with the network-facing interface socketClose(context->serverSocket); //Close the socket associated with each client-facing interface for(i = 0; i < context->clientInterfaceCount; i++) socketClose(context->clientSocket[i]); //Leave the All_DHCP_Relay_Agents_and_Servers multicast group //for each client-facing interface dhcpv6RelayLeaveMulticastGroup(context); //Close event objects osEventClose(context->event); osEventClose(context->ackEvent); } //Return status code return error; }
error_t smtpSendMail(const SmtpAuthInfo *authInfo, const SmtpMail *mail) { error_t error; uint_t i; uint_t replyCode; IpAddr serverIpAddr; SmtpClientContext *context; //Check parameters if(!authInfo || !mail) return ERROR_INVALID_PARAMETER; //Make sure the server name is valid if(!authInfo->serverName) return ERROR_INVALID_PARAMETER; //Debug message TRACE_INFO("Sending a mail to %s port %" PRIu16 "...\r\n", authInfo->serverName, authInfo->serverPort); //The specified SMTP server can be either an IP or a host name error = getHostByName(authInfo->interface, authInfo->serverName, &serverIpAddr, 0); //Unable to resolve server name? if(error) return ERROR_NAME_RESOLUTION_FAILED; //Allocate a memory buffer to hold the SMTP client context context = osAllocMem(sizeof(SmtpClientContext)); //Failed to allocate memory? if(!context) return ERROR_OUT_OF_MEMORY; //Open a TCP socket context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->socket) { //Free previously allocated resources osFreeMem(context); //Report an error return ERROR_OPEN_FAILED; } #if (SMTP_TLS_SUPPORT == ENABLED) //Do not use SSL/TLS for the moment context->tlsContext = NULL; #endif //Start of exception handling block do { //Bind the socket to a particular network interface? if(authInfo->interface) { //Associate the socket with the relevant interface error = socketBindToInterface(context->socket, authInfo->interface); //Any error to report? if(error) break; } //Set timeout for blocking operations error = socketSetTimeout(context->socket, SMTP_DEFAULT_TIMEOUT); //Any error to report? if(error) break; //Connect to the SMTP server error = socketConnect(context->socket, &serverIpAddr, authInfo->serverPort); //Connection to server failed? if(error) break; #if (SMTP_TLS_SUPPORT == ENABLED) //Open a secure SSL/TLS session? if(authInfo->useTls) { //Initialize TLS context context->tlsContext = tlsInit(); //Initialization failed? if(!context->tlsContext) { //Unable to allocate memory error = ERROR_OUT_OF_MEMORY; //Stop immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(context->tlsContext, context->socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext); //Any error to report? if(error) break; //Perform TLS handshake error = tlsConnect(context->tlsContext); //Failed to established a TLS session? if(error) break; } #endif //Wait for the connection greeting reply error = smtpSendCommand(context, NULL, &replyCode, NULL); //Any communication error to report? if(error) break; //Check whether the greeting message was properly received if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Clear security features context->authLoginSupported = FALSE; context->authPlainSupported = FALSE; context->authCramMd5Supported = FALSE; context->startTlsSupported = FALSE; //Send EHLO command and parse server response error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n", &replyCode, smtpEhloReplyCallback); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } #if (SMTP_TLS_SUPPORT == ENABLED) //Check whether the STARTTLS command is supported if(context->startTlsSupported && !context->tlsContext) { //Send STARTTLS command error = smtpSendCommand(context, "STARTTLS\r\n", &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Initialize TLS context context->tlsContext = tlsInit(); //Initialization failed? if(!context->tlsContext) { //Unable to allocate memory error = ERROR_OUT_OF_MEMORY; //Stop immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(context->tlsContext, context->socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext); //Any error to report? if(error) break; //Perform TLS handshake error = tlsConnect(context->tlsContext); //Failed to established a TLS session? if(error) break; //Clear security features context->authLoginSupported = FALSE; context->authPlainSupported = FALSE; context->authCramMd5Supported = FALSE; //Send EHLO command and parse server response error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n", &replyCode, smtpEhloReplyCallback); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } } #endif //Authentication requires a valid user name and password if(authInfo->userName && authInfo->password) { #if (SMTP_LOGIN_AUTH_SUPPORT == ENABLED) //LOGIN authentication mechanism supported? if(context->authLoginSupported) { //Perform LOGIN authentication error = smtpSendAuthLogin(context, authInfo); //Authentication failed? if(error) break; } else #endif #if (SMTP_PLAIN_AUTH_SUPPORT == ENABLED) //PLAIN authentication mechanism supported? if(context->authPlainSupported) { //Perform PLAIN authentication error = smtpSendAuthPlain(context, authInfo); //Authentication failed? if(error) break; } else #endif #if (SMTP_CRAM_MD5_AUTH_SUPPORT == ENABLED) //CRAM-MD5 authentication mechanism supported? if(context->authCramMd5Supported) { //Perform CRAM-MD5 authentication error = smtpSendAuthCramMd5(context, authInfo); //Authentication failed? if(error) break; } else #endif //No authentication mechanism supported? { //Skip authentication step } } //Format the MAIL FROM command (a null return path must be accepted) if(mail->from.addr) sprintf(context->buffer, "MAIL FROM:<%s>\r\n", mail->from.addr); else strcpy(context->buffer, "MAIL FROM:<>\r\n"); //Send the command to the server error = smtpSendCommand(context, context->buffer, &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Format the RCPT TO command for(i = 0; i < mail->recipientCount; i++) { //Skip recipient addresses that are not valid if(!mail->recipients[i].addr) continue; //Format the RCPT TO command sprintf(context->buffer, "RCPT TO:<%s>\r\n", mail->recipients[i].addr); //Send the command to the server error = smtpSendCommand(context, context->buffer, &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } } //Propagate exception if necessary if(error) break; //Send message body error = smtpSendData(context, mail); //Any error to report? if(error) break; //End of exception handling block } while(0); //Check status code if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE || error == ERROR_AUTHENTICATION_FAILED) { //Properly disconnect from the SMTP server smtpSendCommand(context, "QUIT\r\n", &replyCode, NULL); } #if (SMTP_TLS_SUPPORT == ENABLED) //Gracefully close SSL/TLS session if(context->tlsContext != NULL) tlsFree(context->tlsContext); #endif //Close socket socketClose(context->socket); //Clean up previously allocated resources osFreeMem(context); //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; }
error_t ftpOpenFile(FtpClientContext *context, const char_t *path, uint_t flags) { error_t error; uint_t replyCode; IpAddr ipAddr; uint16_t port; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Open data socket context->dataSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->dataSocket) return ERROR_OPEN_FAILED; //Start of exception handling block do { //Bind the socket to a particular network interface? if(context->interface != NULL) { //Associate the socket with the relevant interface error = socketBindToInterface(context->dataSocket, context->interface); //Any error to report? if(error) break; } //Set timeout for blocking operations error = socketSetTimeout(context->dataSocket, FTP_CLIENT_DEFAULT_TIMEOUT); //Any error to report? if(error) break; //Check data transfer direction if(flags & (FTP_FOR_WRITING | FTP_FOR_APPENDING)) { //Maximize transmission throughput by using a large buffer error = socketSetTxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MAX_TX_BUFFER_SIZE); //Any error to report? if(error) break; //Use a small buffer for the reception path error = socketSetRxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MIN_RX_BUFFER_SIZE); //Any error to report? if(error) break; } else { //Use a small buffer for the transmission path error = socketSetTxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MIN_TX_BUFFER_SIZE); //Any error to report? if(error) break; //Maximize reception throughput by using a large buffer error = socketSetRxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MAX_RX_BUFFER_SIZE); //Any error to report? if(error) break; } //Set representation type if(flags & FTP_TEXT_TYPE) { //Use ASCII type error = ftpSetType(context, 'A'); //Any error to report? if(error) break; } else { //Use image type error = ftpSetType(context, 'I'); //Any error to report? if(error) break; } //Check transfer mode if(!context->passiveMode) { //Place the data socket in the listening state error = socketListen(context->dataSocket, 1); //Any error to report? if(error) break; //Retrieve local IP address error = socketGetLocalAddr(context->controlSocket, &ipAddr, NULL); //Any error to report? if(error) break; //Retrieve local port number error = socketGetLocalAddr(context->dataSocket, NULL, &port); //Any error to report? if(error) break; //Set the port to be used in data connection error = ftpSetPort(context, &ipAddr, port); //Any error to report? if(error) break; } else { //Enter passive mode error = ftpSetPassiveMode(context, &port); //Any error to report? if(error) break; //Establish data connection error = socketConnect(context->dataSocket, &context->serverAddr, port); //Connection to server failed? if(error) break; } //Format the command if(flags & FTP_FOR_WRITING) sprintf(context->buffer, "STOR %s\r\n", path); else if(flags & FTP_FOR_APPENDING) sprintf(context->buffer, "APPE %s\r\n", path); else sprintf(context->buffer, "RETR %s\r\n", path); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) break; //Check FTP response code if(!FTP_REPLY_CODE_1YZ(replyCode)) { //Report an error error = ERROR_UNEXPECTED_RESPONSE; break; } //Check transfer mode if(!context->passiveMode) { //Wait for the server to connect back to the client's data port Socket *socket = socketAccept(context->dataSocket, NULL, NULL); //No connection request? if(!socket) { //Report an error error = ERROR_FAILURE; break; } //Close the listening socket socketClose(context->dataSocket); //Save socket handle context->dataSocket = socket; //Set timeout for blocking operations error = socketSetTimeout(context->dataSocket, FTP_CLIENT_DEFAULT_TIMEOUT); //Any error to report? if(error) break; } //End of exception handling block } while(0); //Any error to report? if(error) { //Clean up side effects socketClose(context->dataSocket); context->dataSocket = NULL; } //Return status code return error; }
error_t ftpConnect(FtpClientContext *context, NetInterface *interface, IpAddr *serverAddr, uint16_t serverPort, uint_t flags) { error_t error; uint_t replyCode; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Clear context memset(context, 0, sizeof(FtpClientContext)); //Underlying network interface context->interface = interface; //Save the IP address of the FTP server context->serverAddr = *serverAddr; //Use passive mode? if(flags & FTP_PASSIVE_MODE) context->passiveMode = TRUE; //Open control socket context->controlSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->controlSocket) return ERROR_OPEN_FAILED; //Start of exception handling block do { //Bind the socket to a particular network interface? if(context->interface != NULL) { //Associate the socket with the relevant interface error = socketBindToInterface(context->controlSocket, context->interface); //Any error to report? if(error) break; } //Set timeout for blocking operations error = socketSetTimeout(context->controlSocket, FTP_CLIENT_DEFAULT_TIMEOUT); //Any error to report? if(error) break; //Specify the size of the send buffer error = socketSetTxBufferSize(context->controlSocket, FTP_CLIENT_SOCKET_MIN_TX_BUFFER_SIZE); //Any error to report? if(error) break; //Specify the size of the receive buffer error = socketSetRxBufferSize(context->controlSocket, FTP_CLIENT_SOCKET_MIN_RX_BUFFER_SIZE); //Any error to report? if(error) break; //Connect to the FTP server error = socketConnect(context->controlSocket, serverAddr, serverPort); //Connection to server failed? if(error) break; //Wait for the connection greeting reply error = ftpSendCommand(context, NULL, &replyCode); //Any communication error to report? if(error) break; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) error = ERROR_UNEXPECTED_RESPONSE; //End of exception handling block } while(0); //Any error to report? if(error) { //Clean up side effects socketClose(context->controlSocket); context->controlSocket = NULL; } //Return status code return error; }