6. Debugging Libraries
Warning:

No developer support is offered for these libraries, and these libraries generally cannot be included in retail products. Contact Nintendo (support@noa.com) if you want to do so.

Limited debugging libraries are available for checking network connectivity, such as socket communication using the wireless module.

Table 6-1. Debugging Libraries

Feature

Library Name

Namespace

Description

Socket Communication

SOCKET

nn::socket

Library for implementing data transmission to and from a remote host via sockets.

SSL Communication

SSL

nn::ssl

Helper library for secure communication via SSL.

HTTP Communication

HTTP

nn::http

Library for communication via HTTP.

Note:

The HTTP library conducts socket communications internally, and the process is not affected by the socket API operations of the application.

For example, the application can call functions like nn::socket::Initialize and nn::socket::Finalize while using the HTTP library without affecting the processing of the HTTP library.

6.1. Socket Communication

The SOCKET library for socket communication handles communication with a remote host via sockets bound to addresses and port numbers. Sockets provide a means for low-level communication between the local machine and remote hosts for transmitting data, waiting for connections from remote hosts, and connecting from the local host to a remote host.

6.1.1. Initializing

Call the nn::socket::Initialize function to initialize the SOCKET library.

Code 6-1. Initializing the SOCKET Library
size_t nn::socket::GetRequiredMemorySize(size_t bufferSizeForSockets, 
                                         s32 maxSessions);
nn::Result nn::socket::Initialize(uptr bufferAddress, size_t bufferSize,
                                  s32 bufferSizeForSockets, s32 maxSessions);

The bufferAddress and bufferSize parameters specify the starting address of the working memory used by the library and the size of that memory. The starting address of the working memory must be 4096-byte aligned and must be allocated from non-device memory. Call the nn::socket::GetRequiredMemorySize function, passing the size of the send/receive buffer to allocate for an entire socket (bufferSizeForSockets) and the maximum number of sessions (maxSessions) as arguments, to get the required size of the working memory.

You can use the nn::socket::SetSockOpt function to specify the send/receive buffer to assign to each socket. By default, a 16-KB send/receive buffer (8 KB for sending and 8 KB for receiving) is assigned to a single TCP socket, and a 32-KB send/receive buffer is assigned to a single UDP socket. Even if the maximum number of sockets is 1, allocate at least 64 KB with bufferSizeForSockets.

The maxSessions argument specifies the number of threads that use sockets (the maximum number of sessions). The library can handle calls to blocking library functions from the specified number of threads. Strictly speaking, the library can handle function calls from more than the specified number of threads (as long as they are not calling blocking library functions), but we do not recommend this approach. Both asynchronous and synchronous library function calls block, until there is a free session, if they exceed the maximum number of sessions. Processing blocks until there is an open session, even when other conditions to unblock have been satisfied, such as when data has finished being received or sent. Note that this may cause processing that is meant to be asynchronous to work synchronously instead. You can check socket states with a single call to the nn::socket::Poll function, which allows you to reduce the number of required sessions.

Warning:

The size of the send/receive buffer assigned by default may be subject to change.

6.1.2. Creating a Socket

Both the remote host and the local host must create sockets before socket communication can occur. Call the nn::socket::Socket function to create a socket. The number of sockets that an application can use simultaneously is limited to 16.

Note:

The number of sockets that can be used simultaneously may be subject to change.

Code 6-2. Creating a Socket
s32 nn::socket::Socket(s32 af, s32 type, s32 protocol); 

af may only specify PF_INET.

type specifies the type of socket to create as either SOCK_STREAM for stream sockets or SOCK_DGRAM for datagram sockets. Stream sockets require that the sockets on both sides of the communication establish a connection, whereas datagram sockets allow for one-way sending or receiving of data blocks. Stream sockets also guarantee the order of arrival of data blocks. Datagram sockets do not, but as a consequence transmit faster.

protocol specifies the protocol the socket uses, but currently only 0 may be specified. A protocol value of 0 indicates the use of the default protocol for the protocol family and type specified in the af and type parameters. The default protocol is TCP for stream sockets and UDP for datagram sockets.

If the return value is 1 or greater, the return value is a socket descriptor for identifying the socket. A value of 0 or less indicates an error. The following table lists the errors that may occur.

Table 6-2. Errors When Creating a Socket

Return Value

Error Description

ENETRESET

Library not initialized.

EAFNOSUPPORT

Specified protocol family not supported.

EOPNOTSUPP

The socket is not a stream socket.

EMFILE

No more socket descriptors can be created.

ENOMEM

Insufficient memory to allocate working memory.

EPROTOTYPE

Specified socket type not supported.

EINVAL

Invalid call.

ENETDOWN

Local network interface is down.

EWOULDBLOCK

Same as EAGAIN.

6.1.3. Binding Addresses and Port Numbers

A socket cannot be used for communication unless it is bound to a socket address indicating which address and which port number to use. A freshly created socket does not have a socket address bound to it. Call the nn::socket::Bind function to bind a socket address to a socket.

Code 6-3. Binding an Address and Port Number
s32 nn::socket::Bind(s32 s, const nn::socket::SockAddrIn* sockAddr);

s specifies the socket descriptor for the created socket. An error occurs if the specified socket already has a socket address bound to it.

sockAddr specifies a pointer to the nn::socket::SockAddrIn structure in which the socket address (address family, port number, address) has been set. Only IPv4 addresses are supported.

A return value of 0 indicates success. A nonzero return value indicates an error. The following table lists the errors that may occur.

Table 6-3. Errors When Binding Addresses and Port Numbers

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor not valid.

ENETDOWN

Local network interface is down.

EINVAL

Invalid operation (such as when the socket is already bound).

EAFNOSUPPORT

Specified address family not supported.

EADDRINUSE

Specified socket address already in use.

ENOMEM

Insufficient memory to allocate working memory.

6.1.4. Operating Modes

Call the nn::socket::Fcntl function to get or set a socket’s operating mode.

Code 6-4. Getting and Setting a Socket’s Operating Mode
s32 nn::socket::Fcntl(s32 s, s32 cmd, s32 val);

s specifies the socket descriptor for the socket for which to set or get the operating mode.

cmd specifies whether to set (F_SETFL) or get (F_GETFL) the socket’s operating mode.

val specifies either 0 or a bitwise OR of the flags to set for the operating mode. This parameter is ignored when the cmd value is F_GETFL.

The only flag that may be set is O_NONBLOCK for non-blocking operation. Sockets that do not have this flag set operate in blocking mode instead. Sockets are set to blocking mode when first created.

When cmd is F_GETFL, the return value is a bitwise OR of the operating mode flags that have been set. When cmd is F_SETFL, a return value of 0 indicates successful completion. For any cmd value, a negative return value indicates an error. The following table lists the errors that may occur.

Table 6-4. Errors When Getting or Setting a Socket’s Operating Mode

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor not valid.

ENETDOWN

Local network interface is down.

EINVAL

Invalid process (invalid value specified for cmd).

ENOMEM

Insufficient memory to allocate working memory.

6.1.5. Waiting for Connections

Datagram sockets can send and receive data right after a socket address is bound, but stream sockets must establish a connection before data may be transmitted.

The stream socket on the server side creates a queue for connection requests from client-side stream sockets by calling the nn::socket::Listen function, and then accepts incoming connection requests by calling the nn::socket::Accept function.

Code 6-5. Waiting for Connections
s32 nn::socket::Listen(s32 s, s32 backlog);
s32 nn::socket::Accept(s32 s, nn::socket::SockAddrIn* sockAddr);

The s parameter for both functions specifies the socket to use for incoming requests. This socket must have been created as a stream socket, and must have a socket address bound.

backlog specifies the maximum number of items in the queue used as the socket listening backlog. A value of 0 or a negative number is treated as a value of 1.

sockAddr specifies a pointer to an nn::socket::SockAddrIn structure storing the socket address of the socket that received the request.

A return value of 0 for the nn::socket::Listen function indicates success. A negative return value indicates an error.

For the nn::socket::Accept function, if there is no socket awaiting connection in the queue, processing blocks if the socket used to wait for connections is in synchronous mode. A return value of 1 or greater is the socket descriptor for a newly created socket that has the same address as the socket used to wait for connections. A value of 0 or less indicates an error.

The following table lists the errors that may occur.

Table 6-5. Errors When Waiting for Connections

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor not valid.

EOPNOTSUPP

Unsupported operation.

EINVAL

Invalid operation.

EAFNOSUPPORT

Specified address family not supported.

ENOBUFS

Insufficient resources.

EAGAIN

No socket is waiting for connections. (Non-blocking mode)

ECONNABORTED

Connection attempt canceled.

ENOMEM

Insufficient memory to create the listening backlog.

EWOULDBLOCK

Same as EAGAIN.

6.1.6. Connecting to a Remote Host

The client-side stream socket attempts a connection to the server-side stream socket using the nn::socket::Connect function, and cannot send or receive data until a connection is established. A call to nn::socket::Connect by a datagram socket only overwrites the sending target socket address.

Code 6-6. Connecting to a Remote Host
s32 nn::socket::Connect(s32 s, const nn::socket::SockAddrIn* sockAddr);

s specifies the socket descriptor for the socket used for the connection. If this socket has no socket address bound, the function binds the socket to an unused local socket address.

sockAddr specifies a pointer to an nn::socket::SockAddrIn structure to which the connection target socket address has been set.

A return value of 0 indicates success. A nonzero return value indicates an error. The following table lists the errors that may occur.

Table 6-6. Errors When Connecting to a Remote Host

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor not valid.

EAFNOSUPPORT

Socket does not support specified address family.

EALREADY

Already attempting to connect in non-blocking mode.

ECONNREFUSED

Connection reset by remote host after the local and remote host simultaneously became open.

ECONNRESET

Connection was reset.

EINPROGRESS

Specified socket is currently changing state.

EINVAL

Invalid process (invalid value specified for sockAddr).

EISCONN

Socket already in use and cannot be used for other processing.

ENETDOWN

Local network interface is down.

ENETUNREACH

Could not reach the connection target.

ENOBUFS

Failed to allocate the temporary socket address for the empty socket.

ENOMEM

Insufficient memory to allocate working memory.

ETIMEDOUT

Response from connection target timed out.

If the socket specified by s is a datagram socket, the function only overwrites the socket’s sending target socket address with the socket address set in sockAddr, with no difference in operation for different operating modes.

If the socket specified by s is a stream socket and the operating mode is synchronous, the function blocks until a connection is established. If the operating mode is asynchronous, the function returns immediately, and the nn::socket::Poll function can be used to check if a connection has been established.

Code 6-7. Checking a Connection to a Remote Host
struct nn::socket::PollFd
{
    s32         fd;
    s32         events;
    s32         revents;
};
s32 nn::socket::Poll(nn::socket::PollFd fds[], u32 nfds, s32 timeout);

The nn::socket::Poll function surveys multiple socket descriptors for sockets that can send and receive.

fds specifies an array of nn::socket::PollFd structures that contain the socket descriptors and survey conditions. The structure member variable fd contains a socket descriptor to survey, and the events member variable contains the survey conditions. The revents member stores the survey results. Set it to 0 when calling the function.

If a connection could not be established by a call to nn::socket::Connect, the POLLRDNORM and POLLWRNORM flags are set in revents, and an error is then returned when data is transmitted. The following table lists the flags set for the survey conditions set in events and for the survey results set in revents.

Table 6-7. Flags Set for Survey Conditions and Survey Results

Flag

Description

POLLRDNORM

Indicates an ability to receive.

POLLRDBAND

Indicates an ability to receive (for priority data).

POLLPRI

Indicates an ability to receive (for highest-priority data).

POLLWRNORM

Indicates an ability to send.

POLLWRBAND

Indicates an ability to send (for priority data).

POLLERR

Indicates that an error occurred. Only set for survey results.

POLLHUP

Indicates that the socket was disconnected. Only set for survey results.

POLLNVAL

Indicates that an invalid socket descriptor was specified. Only set for survey results.

POLLIN

Indicates an ability to receive. Bitwise OR of POLLRDNORM and POLLRDBAND.

POLLOUT

Indicates an ability to send. Same as POLLWRNORM.

nfds specifies the number of elements in the array specified in fds.

timeout specifies the number of milliseconds to wait until timing out when no sockets are found matching the conditions. Specify as a number greater than 0 or as INFTIM (no timeout).

A call to nn::socket::Poll blocks until a socket is found that matches the conditions. However, the block is released if the specified timeout period passes with no matching sockets found, if the socket is disconnected, or if an error occurs in the socket.

A return value of 1 or greater is the number of sockets that matched the conditions. A return value of 0 indicates that the function timed out. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-8. Errors When Checking Connection to a Remote Host

Return Value

Error Description

ENETRESET

Library not initialized.

ENETDOWN

Local network interface is down.

EINVAL

Invalid operation.

6.1.7. Receiving Data

You can receive data using the nn::socket::RecvFrom, nn::socket::Recv, or nn::socket::Read functions. For stream sockets, data cannot be received unless a connection has been established on both the server and client side.

Code 6-8. Receiving Data
s32 nn::socket::RecvFrom(s32 s, void* buf, s32 len, s32 flags, 
                         nn::socket::SockAddrIn* sockFrom);
s32 nn::socket::Recv(s32 s, void* buf, s32 len, s32 flags);
s32 nn::socket::Read(s32 s, void* buf, s32 len);
s32 nn::socket::SockAtMark(s32 s);

s specifies a socket descriptor for a local socket.

buf specifies a pointer to a buffer for storing the received data, and len specifies the size of that buffer in bytes.

flags specifies flags for any special operations to carry out when receiving. If MSG_DONTWAIT is specified, the function does not block even if the socket is in synchronous mode. If MSG_PEEKN is specified, data that is received by the state is not changed, and the same data can be received again. If MSG_OOB is specified, out-of-band data can be received. Check whether the nn::socket::SockAtMark function’s return value is 1 to determine whether out-of-band data is included in the receivable data. This function can also be used to check whether the last byte of TCP protocol "urgent data" is at the start of receivable data.

If the sockFrom parameter specifies a pointer to an nn::socket::SockAddrIn structure, the socket address of the sender of the data is stored.

If receiving via a stream socket and the operating mode is synchronous, the function blocks until data is received. If the mode is asynchronous or if flags specifies MSG_DONTWAIT, only that data that is receivable when the function is called is stored in the buffer, and the function does not block.

If receiving via a datagram socket, all of the data to receive must be received in a single function call. If the received data is greater than the size of the receive buffer and flags does not specify MSG_PEEKN, any data that does not fit in the buffer is discarded.

A return value of 1 or greater is the number of bytes of received data. A return value of 0 when using a stream socket indicates that the remote host has finished sending data. The return value will never be 0 when using a datagram socket. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-9. Errors When Receiving Data

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor not valid.

EAGAIN

No socket is waiting for connections (The non-blocking mode or flags specifies MSG_DONTWAIT).

EINVAL

Invalid operation.

EOPNOTSUPP

Unsupported operation.

ENOTCONN

Specified socket is not connected to the remote host.

ECONNRESET

Connection was reset.

EINTR

Process interrupted.

ETIMEDOUT

The process timed out.

ENETDOWN

Local network interface is down.

ENOMEM

Insufficient memory to allocate working memory.

EWOULDBLOCK

Same as EAGAIN.

6.1.8. Sending Data

You can receive data using the nn::socket::SendTo, nn::socket::Send, or nn::socket::Write functions. For stream sockets, data cannot be sent unless a connection has been established on both the server and client side.

Code 6-9. Sending Data
s32 nn::socket::SendTo(s32 s, const void* buf, s32 len, s32 flags, 
                       const nn::socket::SockAddrIn* sockTo);
s32 nn::socket::Send(s32 s, const void* buf, s32 len, s32 flags);
s32 nn::socket::Write(s32 s, const void* buf, s32 len);

s specifies a socket descriptor for a local socket.

buf specifies a pointer to a buffer for storing the data to send, and the len parameter specifies the size of that buffer in bytes.

flags specifies flags for any special operations to carry out when sending.

If sockTo specifies a pointer to an nn::socket::SockAddrIn structure, the function sends the data to the socket address set in the structure.

The function blocks until data sending has completed.

A return value of 0 indicates success. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-10. Errors When Sending Data

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor not valid.

EAGAIN

If in blocking mode, the prior send attempt was blocked.

If the socket is a stream socket in non-blocking mode, data to be sent out-of-band cannot be reserved for sending in the internal send buffer.

ECONNRESET

Connection was reset.

EINTR

Process interrupted.

EINVAL

Invalid operation.

EOPNOTSUPP

Unsupported operation.

EDSTADDRREQ

If the socket is a stream socket, the socket is being used to accept connection requests.

If the socket is a datagram socket, the socket address for the communication target to send data to has not been determined.

EMSGSIZE

Data exceeds the size of the internal send buffer. (Datagram sockets only.)

ENETDOWN

Local network interface is down.

ENETUNREACH

Could not reach the connection target.

ENOBUFS

Failed to allocate the temporary socket address for the empty socket. Alternatively, failed to allocate the temporary send buffer.

ENOMEM

Insufficient memory to allocate working memory.

ENOTCONN

Specified socket is not connected to the remote host.

ETIMEDOUT

The process timed out.

EWOULDBLOCK

Same as EAGAIN.

6.1.9. Setting Options

Call the nn::socket::SetSockOpt or nn::socket::GetSockOpt functions to set and get socket options, such as internal socket setting values and internal state information.

Code 6-10. Setting Options
s32 nn::socket::SetSockOpt(s32 s, s32 level, s32 optname, const void* optval, 
                           s32 optlen);
s32 nn::socket::GetSockOpt(s32 s, s32 level, int optname, void* optval, 
                           int* optlen)

For more information about the values that can be specified for these function parameters, see the header file nn/socket/socket_User.autogen.h.

A return value of 0 indicates success. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-11. Errors When Setting Options

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor not valid.

EINVAL

Invalid operation.

ENETDOWN

Local network interface is down.

ENOMEM

Insufficient memory to allocate working memory.

ENOPROTOOPT

Unsupported option.

6.1.10. Disconnecting a Socket

Call the nn::socket::Shutdown function to halt socket communications and disconnect a socket.

Code 6-11. Disconnecting a Socket
s32 nn::socket::Shutdown(s32 s, s32 how);

s specifies the socket descriptor for the socket to shut down.

how specifies how to shut down the socket. Specify SHUT_RD to stop receiving data, SHUT_WR to stop sending data, and SHUT_RDWR to stop both sending and receiving.

A return value of 0 indicates success. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-12. Errors When Disconnecting a Socket

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor is not valid.

ENOTCONN

Specified socket is not connected to the remote host.

EINVAL

Invalid operation.

ENETDOWN

Local network interface is down.

ENOMEM

Insufficient memory to allocate working memory.

6.1.11. Closing a Socket

Only a limited number of sockets may be used at any one time. Close any unneeded sockets by calling the nn::socket::Close function.

Code 6-12. Closing a Socket
inline s32 nn::socket::Close(s32 s);

The s parameter specifies the socket descriptor for the socket to close.

A socket can no longer be used after it has been closed. If a function blocks after being called using a closed socket, the blocks are released and an error is returned. When closing a stream socket in asynchronous mode, the socket is closed according to the Linger option setting.

The default behavior for the Close function is to return immediately without blocking. Any remaining data to send is then sent in the background, after which the socket releases the resources it was using.

A return value of 0 indicates success. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-13. Errors When Closing a Socket

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor is not valid.

ENOTCONN

Specified socket is not connected to the remote host.

ENOMEM

Insufficient memory to allocate working memory.

6.1.12. Finalizing

When no longer using the SOCKET library, call the nn::socket::Finalize function to finalize the library.

Code 6-13. Finalizing the SOCKET Library
nn::Result nn::socket::Finalize(void);

This releases any resources in use by the library and destroys any socket descriptors in use.

6.1.13. Utility Functions

The SOCKET library includes various utility functions for purposes such as getting socket addresses, getting network adapter information, getting remote host information via DNS, converting addresses to and from strings and numeric values, and converting numbers to the host byte order and the network byte order.

Code 6-14. Getting a Socket Address
s32 nn::socket::GetSockName(s32 s, nn::socket::SockAddrIn* sockAddr);
s32 nn::socket::GetPeerName(s32 s, nn::socket::SockAddrIn* sockAddr);

The nn::socket::GetSockName function gets the local socket address for the socket indicated by the socket descriptor passed in s and puts it in sockAddr. The local socket address is the communication source socket address. If no local socket address has been configured using the nn::socket::Bind or nn::socket::Connect functions, this function returns an address of 0.0.0.0 if called on a UDP-protocol socket (a datagram socket), and returns an error if called on a TCP-protocol socket (a stream socket).

The nn::socket::GetPeerName function gets the remote socket address for the socket indicated by the socket descriptor passed in s and puts it in sockAddr. The remote socket address is the communication target socket address.

A return value of 0 indicates success for either function. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-14. Errors When Getting a Socket Address

Return Value

Error Description

ENETRESET

Library not initialized.

EBADF

Specified socket descriptor is not valid.

ENOTCONN

Not connected to remote host or no communication target. (Only for the GetPeerName function.)

EINVAL

Invalid operation. (Only for the GetSockName function.)

ENETDOWN

Local network interface is down.

Code 6-15. Getting Network Adapter Information
u32 nn::socket::GetHostId(void);

The nn::socket::GetHostId function returns the IPv4 address of the local host. A return value of 0 indicates that the network cannot be used. The returned IP address is a 32-bit numeric value in network byte order.

Code 6-16. Getting Remote Host Information via DNS
nn::socket::HostEnt* nn::socket::GetHostByName(const char8* name);
nn::socket::HostEnt* nn::socket::GetHostByAddr(const void* addr, s32 len, 
                                               s32 type);
s32 nn::socket::GetAddrInfo(const char8* nodeName, const char8* servName, 
                const nn::socket::AddrInfo* hints, nn::socket::AddrInfo** res);
void nn::socket::FreeAddrInfo(nn::socket::AddrInfo* head);
s32 nn::socket::GetNameInfo(const void* sa, char8* node, s32 nodeLen, 
                            char8* service, s32 serviceLen, s32 flags);

The nn::socket::GetHostByName and nn::socket::GetHostByAddr functions both get information for the specified host. GetHostByName searches for a host based on either the host’s name or address string in dot-decimal notation, and GetHostByAddr searches based on the host’s address. Processing blocks while searching, and the function may query the DNS server. The actual representation of the structure holding the return value is a buffer internal to the library, so neither of these functions is thread-safe.

nn::socket::GetAddrInfo gets information for the host found based on hostname and service name. Configure the search parameters using the flags member of the nn::socket::AddrInfo structure passed in the hints parameter. The flags member stores a bitwise OR of the flags defined by the nn::socket::AddrInfoFlag enumerators.

Table 6-15. nn::socket::AddrInfoFlag Enumerators

Flag

Description

AI_PASSIVE

Uses 0.0.0.0 when nodeName specifies NULL.

AI_CANONNAME

Gets the canonical name for nodeName.

AI_NUMERICHOST

nodeName specifies an address in dot-decimal notation.

AI_NUMERICSERV

servName specifies a port number as a string.

Processing blocks while searching, and the function may query the DNS server. The search results structure returned in res is stored in memory allocated by the library from the allocator specified in the nn::socket::Initialize function. Be sure to release this memory when the search results are no longer needed by calling the nn::socket::FreeAddrInfo function.

A return value of 0 indicates success for the nn::socket::GetAddrInfo function. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-16. Errors When Getting Host Information With nn::socket::GetAddrInfo

Return Value

Error Description

EAI_FAIL

Failed, possibly due to invalid conditions specified in hints.

EAI_MEMORY

Failed to allocate memory.

EAI_NONAME

Could not find the specified host.

The nn::socket::GetNameInfo function searches for the hostname and service name based on an address. Configure the search parameters by specifying a bitwise OR of the flags defined by the nn::socket::NameInfoFlag enumerators in the flags parameter.

Table 6-17. nn::socket::NameInfoFlag Enumerators

Flag

Description

NI_NOFQDN

Gets only the node name portion of a fully qualified domain name as the hostname.

NI_NUMERICHOST

Stores the host address in node after converting to a dot-decimal notation string.

NI_NAMEREQD

If the specified host cannot be found, the numeric host address is converted to a string, not replaced, and handled as an error (EAI_NONAME).

NI_NUMERICSERV

Stores the service (port number) in service, converted to a numeric string.

Processing blocks while searching, and the function may query the DNS server.

A return value of 0 indicates success. A negative return value indicates an error. The following table lists the errors that may occur.

Table 6-18. Errors When Getting Host Information With nn::socket::GetNameInfo

Return Value

Error Description

EAI_FAMILY

Unsupported protocol family included in the socket address specified in sa.

EAI_NONAME

Invalid buffer size specified in nodeLen or serviceLen.

If NI_NAMEREQD was specified in flags, the specified host was not found.

Code 6-17. Converting an Address
s32 nn::socket::InetAtoN(const char* cp, nn::socket::InAddr* inp);
char* nn::socket::InetNtoA(nn::socket::InAddr in);
s32 nn::socket::InetPtoN(int af, const char* src, void* dst);
const char* nn::socket::InetNtoP(int af, const void* src, char* dst, 
                                 unsigned len);

Call the nn::socket::InetAtoN and nn::socket::InetNtoA functions to convert an address between a numeric string and the nn::socket::InAddr structure’s numeric format. These functions can convert IPv4 host addresses. The nn::socket::InetPtoN and nn::socket::InetNtoP functions previously allowed various values for the af address family argument, but on the CTR-SDK these functions only take the value AF_INET for this argument.

These functions can be used even if nn::socket::Initialize has not been called.

Code 6-18. Converting Byte Order
bit32 nn::socket::HtoNl(bit32 v);
bit32 nn::socket::NtoHl(bit32 v);
bit16 nn::socket::HtoNs(bit16 v);
bit16 nn::socket::NtoHs(bit16 v);

Use these functions to convert a numeric value from host byte order to network byte order (HtoN) and back again (NtoH). The functions ending in "l" take 32-bit values, while those ending in "s" take 16-bit values.

6.2. SSL Communication

The SSL library is a wrapper for SSL communication to help keep communication secure.

6.2.1. Initializing

Call the nn::ssl::Initialize function to initialize the SSL library.

Code 6-19. Initializing the SSL Library
nn::Result nn::ssl::Initialize(void);

6.2.2. Generating an Instance of the Connection Class

SSL communication is handled by the nn::ssl::Connection class, which itself is a wrapper for sockets.

Code 6-20. Connection Class Constructor and Assigning Sockets
class nn::ssl::Connection
{
    explicit Connection(s32 socket);
    explicit Connection();
    bool AssignSocket(s32 socket);
}

Two constructors are available: one that takes a socket descriptor as an argument, and one that does not. For Connection class instances generated without an argument, you must call the AssignSocket member function to bind a socket.

6.2.1. Setting the Communication Target

Use the Initialize member function to set the communication target server to the connection class.

Code 6-21. Setting the Communication Target
class nn::ssl::Connection
{
    nn::Result Initialize(const char* pServerName, 
                          u32 verifyOpt = VERIFY_NONE);
}

pServerName specifies the hostname of the communication target server. When using SSL communication, this hostname is compared against the dnsName/ipAddress values in the subjectAltName extended region or the CommonName of the server certificate, and a communication error occurs if these values do not match. The maximum length of the specifiable hostname string, including the string terminator, is nn::socket::MAXDNAME bytes.

verifyOpt specifies any options for server verification during SSL communication. Omit this parameter to use the default server verification. When implementing a server verification option that is not implemented by default, specify in verifyOpt an enumerator value from the nn::ssl:VerifyOption enumerated type that specifies this option. To use multiple verification options simultaneously, specify the bitwise OR of these values. This parameter can take the following values.

Table 6-19. Specifiable Values for Server Verification Options

Value

Description

VERIFY_DATE

Verify the certificate’s expiration date.

USE_SESSION_CACHE

Use SSL resumption and attempt to reuse the session when connecting to the same host multiple times in a row.

VERIFY_EV

Verifies the EV certificate. Verification succeeds unless the server certificate is linked to an EV certificate.

Trusted EV certificates can be set using AddEVPolicyID.

VERIFY_IGNORE

Verifies the server certificate, but ignores results and proceeds. Call GetCertVerifyErrors to get verification results.

GET_ALL_SERVER_CERT_CHAIN

Saves all certificate data in the certificate chain when saving the server certificate in the buffer specified by SetServerCertBuffer. Omit this option to save only the server certificate.

Other options not in the table are implemented by default, as defined in the nn::ssl::VerifyOption enumerated type.

Note:

When saving all certificates in the certificate chain, each certificate is saved with the first four bytes indicating the length of the certificate data, followed by the certificate data itself. The data layout starts with the first certificate in the chain (the server certificate) and continues through to the last certificate in the chain (the CA certificate). However, if CA verification fails, the CA certificate cannot be designated and is excluded.

6.2.4. Setting the Certificate and CRL

Use the following function to configure the connection class with the certificate and CRL stores and the client certificate to use in the handshake with the server.

Code 6-22. Setting the Certificate and CRL
class nn::ssl::Connection
{
    nn::Result SetServerCertStore(nn::ssl::CertStore& certStore);
    nn::Result SetClientCert(nn::ssl::ClientCert& clientCert);
    nn::Result SetCRLStore(nn::ssl::CrlStore& crlStore);
}

Use the SetServerCertStore function to set a server certificate store, use SetCRLStore to set a CRL store, and use SetClientCert to set a client certificate.

6.2.4.1. Certificate Store Class

The certificate store class is defined by nn::ssl::CertStore.

Code 6-23. Certificate Store Class
class nn::ssl::CertStore
{
    explicit CertStore();
    virtual ~CertStore(void);

    nn::Result Initialize(void);
    nn::Result Finalize(void);

    nn::Result RegisterCert(const u8* pCertData, size_t certDataSize, 
                            nn::ssl::CertId* pCertIdCourier=NULL);
    nn::Result RegisterCert(nn::ssl::InternalCaCert inCaCertName, 
                            nn::ssl::CertId* pCertIdCourier=NULL);
    nn::Result UnRegisterCert(nn::ssl::CertId certId);
}

The constructor has no arguments. Generate an instance and call the Initialize function.

Call the RegisterCert member function to register a certificate to the certificate store. pCertData and certDataSize specify the certificate data and its size in bytes. Specify nn::ssl::InternalCaCert as the argument instead to set a certificate stored internally to the certificate store. pCertIdCourier may be omitted unless you need to unregister an individual certificate. Call the Finalize function to unregister all certificates that have not been individually unregistered. Call the RegisterCert member function multiple times to register multiple certificates to the certificate store.

Use the UnRegisterCert member function to unregister an individual certificate from the certificate store. Specify the certificate ID obtained in pCertIdCourier when registering the certificate via RegisterCert as the value for the certId argument.

Be sure to call the Finalize function when the certificate store is no longer needed.

6.2.4.2. CRL Store Class

The CRL store class is defined by nn::ssl::CrlStore.

Code 6-24. CRL Store Class
class nn::ssl::CrlStore
{
    explicit CrlStore();
    virtual ~CrlStore(void);

    nn::Result Initialize(void);
    nn::Result Finalize(void);

    nn::Result RegisterCrl(const u8* pCrlData, size_t crlDatasize, 
                           nn::ssl::CrlId* pCrlIdCourier=NULL);
    nn::Result RegisterCrl(nn::ssl::InternalCrl inCrlName, 
                           nn::ssl::CrlId* pCrlIdCourier=NULL);
    nn::Result UnRegisterCrl(nn::ssl::CrlId crlId);
}

The constructor has no arguments. Generate an instance and call the Initialize function.

Call the RegisterCrl member function to register a CRL to the CRL store. pCrlData and crlDataSize specify the CRL data and its size in bytes. Specify nn::ssl::InternalCrl as the argument instead to set a CRL stored internally to the CRL store. pCrlIdCourier may be omitted unless you need to unregister an individual CRL. Call the Finalize function to unregister all CRLs that have not been individually unregistered. Call the RegisterCrl member function multiple times to register multiple CRLs to the CRL store.

Use the UnRegisterCrl member function to unregister an individual CRL from the CRL store. Specify the CRL ID obtained in pCrlIdCourier when registering the certificate via RegisterCrl as the value for the crlId argument.

Be sure to call the Finalize function when the CRL store is no longer needed.

6.2.4.3. Client Certificate Class

The client certificate class is defined by nn::ssl::ClientCert.

Code 6-25. Client Certificate Class
class nn::ssl::ClientCert
{
    explicit ClientCert();
    virtual ~ClientCert(void);

    nn::Result Initialize(const u8* pCertData, size_t certDataSize, 
                          const u8* pPrivateKeyData, size_t privateKeyDataSize);
    nn::Result Initialize(nn::ssl::InternalClientCert inClientCertName);
    nn::Result Finalize(void);
}

The constructor has no arguments. Generate an instance and call the Initialize function.

pCertData and certDataSize specify the client certificate data and its size in bytes. pPrivateKeyData and privateKeyDataSize specify the private key data and its size in bytes. Specify nn::ssl::InternalClientCert instead to use an internal client certificate.

Be sure to call the Finalize function when the client certificate is no longer needed.

6.2.5. Handshaking

Call the DoHandshake function of the Connection class to use the configured certificate and CRL stores and client certificate to handshake with the connection target server.

Code 6-26. Handshaking
class nn::ssl::Connection
{
    nn::Result SetServerCertBuffer(uptr bufferAddress, size_t bufferSize);
    nn::Result DoHandshake(void);
    nn::Result DoHandshake(size_t* pServerCertSize, 
                           u32*    pServerCertNum = NULL);
}

Call the DoHandshake function version with arguments when you need information about a server certificate sent from the server. The size of the server certificate in bytes is stored in the variable pointer specified in pServerCertSize.

Specify the buffer to store the server certificate by calling the SetServerCertBuffer function. The starting address and size of this buffer must both be 4096-byte aligned. Calling the DoHandshake function version with arguments without specifying a buffer via SetServerCertBuffer is effectively identical to calling the DoHandshake function version that has no arguments.

6.2.6. Transferring Data

After confirming a successful handshake, you can start sending and receiving data via SSL communication.

Code 6-27. Sending and Receiving Data via an SSL Connection
class nn::ssl::Connection
{
    nn::Result Read(u8* pDataBuf, size_t dataBufSize, 
                    size_t* pReadSizeCourier = NULL);
    nn::Result Peek(u8* pDataBuf, size_t dataBufSize, 
                    size_t* pReadSizeCourier = NULL);
    nn::Result Write(const u8* pDataBuf, size_t dataBufSize, 
                     size_t* pWrittenDataSizeCourier = NULL);
}

The Read and Peek member functions both receive data. Peek does not change the state of data received, and data received this way can be received again. pDataBuf and dataBufSize specify a buffer to receive the data and its size in bytes. Specify a pointer to a variable in pReadSizeCourier for receiving the data size if you need the size in bytes of the received data.

The Write member function sends data. pDataBuf and dataBufSize specify a buffer to store the data to send and its size in bytes. Specify a pointer to a variable in pWrittenDataSizeCourier for receiving the data size if you need the size in bytes of the sent data.

6.2.7. Disconnecting

Only a limited number of SSL connections may be used at any one time. Be sure to call the Shutdown member function on class instances that are no longer needed to disconnect SSL connections and finalize the instances.

Code 6-28. Disconnecting an SSL Connection
class nn::ssl::Connection
{
    nn::Result Shutdown(void);
}

6.2.8. Finalizing

When you are no longer using the SSL library, call the nn::ssl::Finalize function to finalize the library.

Code 6-29. Finalizing the SSL Library
nn::Result nn::ssl::Finalize(void); 

6.3. HTTP Communication

The HTTP library handles connecting to the specified URL and communicating over the network via the HTTP protocol. The library also supports the HTTPS protocol.

6.3.1. Initializing

Call the nn::http::Initialize function to initialize the HTTP library.

Code 6-30. Initializing the HTTP Library
nn::Result nn::http::Initialize(uptr bufferAddress = 0, size_t bufferSize = 0);

You must call this function before using the HTTP library. The function returns nn::http::ResultAlreadyInitialized if called after the library is already initialized.

To use a buffer set aside by the application for communication, specify the buffer’s starting address and size in the bufferAddress and bufferSize parameters. Note that these values must be 4096-byte aligned.

6.3.2. Generating an Instance of the Connection Class

Use the nn::http::Connection class to work with HTTP connections. You must generate one instance of this class for each URL to connect to. The number of connections that can be used at one time by the system as a whole and by the application is limited, so take care when managing connections.

There are two constructor versions: one with arguments and one without. After generating an instance using the constructor with no arguments, you must call the Initialize member function to configure the URL to connect to, the connection method, and whether to use a default proxy.

Code 6-31. HTTP Connection Class Constructors and Initialization
class nn::http::Connection
{
    explicit Connection(void);
    explicit Connection(const char* pUrl, 
                        RequestMethod method = REQUEST_METHOD_GET, 
                        bool isUseDefaultProxy = true);
    nn::Result Initialize(const char* pUrl, 
                          RequestMethod method = REQUEST_METHOD_GET, 
                          bool isUseDefaultProxy = true);
}

Specify the URL to connect to in the pUrl parameter.

Specify the HTTP request method in the method parameter. Select from one of the following three types.

Table 6-20. List of Method Types

Definition

Description

REQUEST_METHOD_GET

GET method. The parameters indicating which data to get are embedded in the URL.

REQUEST_METHOD_POST

POST method. The data to send to the server is added as POST data in the body of the request.

REQUEST_METHOD_HEAD

HEAD method. Similar to the GET method, but only retrieves the message header for the specified URL.

Specify true for the isUseDefaultProxy parameter to use the default proxy when connecting. Specify false to use a different proxy, and configure that separately.

In case of any error occurring during initialization, check the Description property of the nn::Result class instance returned by the Initialize function.

Table 6-21. Errors Occurring During Initialization

Description Value

Cause of Error

ER_CONN_ADD

The system as a whole has no free communications resources.

ER_REQ_URL

The specified URL is invalid.

ER_ALREADY_ASSIGN_HOST

A destination URL has already been specified

ER_CONN_PROCESS_MAX

No free application-allocated communications resources.

6.3.3. Configuring Communication

Use these functions to configure various aspects of communication, such as proxy settings, basic verification, or the receive buffer size of the socket used in communication. These settings must be configured before initiating a connection.

Code 6-32. Configuring Communication
class nn::http::Connection
{
    nn::Result SetProxy(const char* pProxyName, u16 port, 
                        const char* pUserName, const char* pPassword);
    nn::Result SetBasicAuthorization(const char* pUserName, 
                                     const char* pPassword);
}

Call the SetProxy function to use a proxy other than the default. Specify the proxy URL and port in the pProxyName and port parameters, and specify the verification user name and password in the pUserName and pPassword parameters.

Call the SetBasicAuthorization function if you need to configure basic user verification on connection. Specify the user name and password to use in the pUserName and pPassword parameters.

6.3.3.1. Configuring for HTTPS Communication

To use the HTTPS protocol, you must first configure SSL communication settings, such as the CA, CRL, and client certificates.

Code 6-33. Configuring HTTPS Communication
class nn::http::Connection
{
    nn::Result SetRootCa(const u8* pCertData, size_t certDataSize);
    nn::Result SetRootCa(nn::http::InternalCaCertId inCaCertName);
    nn::Result SetRootCaStore(nn::http::CertStore& certStore);
    nn::Result SetCrl(const u8* pCrlData, size_t crlDataSize);
    nn::Result SetCrl(nn::http::InternalCrlId inCrlName);
    nn::Result SetCrlStore(CrlStore& crlStore);
    nn::Result SetClientCert(const u8* pCertData, size_t certDataSize, 
                             const u8* pPrivateKeyData, size_t privateKeyDataSize);
    nn::Result SetClientCert(nn::http::InternalClientCertId inClientCertName);
    nn::Result SetClientCert(nn::http::ClientCert& clientCert);
    nn::Result GetSslError(s32* pResultCodeBuf) const;
    nn::Result SetVerifyOption(u32 verifyOption);
    nn::Result DisableVerifyOptionForDebug(u32 excludeVerifyOptions);
}

Call the SetRootCa function to register a CA certificate. You can register the certificate data directly, or specify nn::http::InternalCaCertId to use the internal CA certificate included in the system.

If you need to register multiple CA certificates, either call SetRootCa multiple times, or call SetRootCaStore and specify an instance of the nn::http::CerStore class as an argument. This allows you to use the same set of CA certificates for multiple connections.

Do not destroy the instance of the nn::http::CertStore class until you are done using the set of CA certificates.

Code 6-34. nn::http::CertStore Class Definition
class nn::http::CertStore
{
    explicit CertStore();
    virtual ~CertStore (void);

    nn::Result Initialize(void);
    nn::Result Finalize(void);
    nn::Result RegisterCert(const u8* pCertData, size_t certDataSize, 
                            nn::http::CertId* pCertIdCourier=NULL);
    nn::Result RegisterCert(nn::http::InternalCaCertId inCaCertName, 
                            nn::http::CertId* pCertIdCourier=NULL);
    nn::Result UnRegisterCert(nn::http::CertId certId);
}

Be sure to call the Initialize member function when using an nn::http::CertStore class instance. Call the RegisterCert function to register a CA certificate. Call the function multiple times to register multiple CA certificates to use them together as a set.

To register an individual CA certificate, call the UnRegisterCert function, passing as an argument the value returned in the pCertIdCourier parameter when you registered the certificate. After you finish using a class instance, you must call the Finalize function to destroy the instance.

Call the SetCrl function to set a CRL. You can set the CRL data directly, or specify nn::http::InternalCrlId to use the internal CA certificates included in the system. Note that there are no internal CRLs at present.

Much as for CA certificates, if you need to register multiple CRLs, either call SetCrl multiple times, or call SetCrlStore and specify an instance of the nn::http::CrlStore class as an argument. Use the nn::http::CrlStore class the same way you would use the nn::http::CertStore class.

Code 6-35. nn::http::CrlStore Class Definition
class nn::http::CrlStore
{
    explicit CrlStore();
    virtual ~CrlStore (void);

    nn::Result Initialize(void);
    nn::Result Finalize(void);
    nn::Result RegisterCrl(const u8* pCrlData, size_t crlDataSize, 
                            nn::http::CrlId* pCrlIdCourier=NULL);
    nn::Result RegisterCrl(nn::http::InternalCrlId inCrlName, 
                            nn::http::CrlId* pCrlIdCourier=NULL);
    nn::Result UnRegisterCrl(nn::http::CrlId crlId);
}

Call the SetClientCert function to register a client certificate. You can configure the certificate by specifying the certificate data and secret key, by specifying the system’s internal client certificate, or by using an nn::http::ClientCert class instance to use the same set of client certificates for multiple connections.

When using an nn::http::ClientCert class instance with multiple connections, do not destroy the instance until you finish using it.

Code 6-36. nn::http::ClientCert Class Definition
class nn::http::ClientCert
{
    explicit ClientCert();
    virtual ~ClientCert (void);

    nn::Result Initialize(const u8* pCertData, size_t certDataSize, 
                          const u8* pPrivateKeyData, size_t privateKeyDataSize);
    nn::Result Initialize(nn::http::InternalClientCertId inClientCertName);
    nn::Result Finalize(void);
} 

The nn::http::ClientCert class includes two versions of its Initialize function, one that allows you to specify the certificate data and secret key, and one that uses the system’s internal client certificate. After you finish using a class instance, you must call the Finalize function to destroy the instance.

Call the SetVerifyOption function to enable any server verification option that is disabled by default. The options enabled by default are VERIFY_COMMON_NAME (CommonName verification), VERIFY_ROOT_CA (RootCA verification), and VERIFY_SUBJECT_ALT_NAME (SubjectAlternativeName verification).

Other options that you can enable in the current SDK version are VERIFY_DATE (checks for certificate expiration), USE_SESSION_CACHE (allows for sessions to be resumed), and VERIFY_EV (EV certificate verification).

You can call the DisableVerifyOptionForDebug function to disable all verification options, but note that this is intended only for debugging purposes.

Check for any errors occurring during HTTPS communication by calling the GetSslError function and examining the value stored in the pResultCodeBuf parameter. These error code values are defined by the nn::ssl::ResultCode class.

6.3.4. Configuring Data to Send

Before initiating a connection and sending data, you must first add a message field header or POST data. Use the lazy POST data setting mode to add POST data after initiating a connection.

Code 6-37. Adding a Header or Data Before Sending
class nn::http::Connection
{
    nn::Result AddHeaderField(const char* pLabel, const char* pValue);
    nn::Result SetPostDataEncoding(nn::http::EncodingType type);
    nn::Result AddPostDataAscii(const char* pLabel, const char* pValue);
    nn::Result AddPostDataBinary(const char* pLabel, const void* pValue, 
                                 size_t valueSize);
    nn::Result AddPostDataRaw(const void* pValue, size_t valueSize);
} 

Call the AddHeaderField function to add a header to the message field. For example, specify the strings Connection for the pLabel parameter and keep-alive for the pValue parameter to add a header with the label Connection and the content keep-alive.

Call the SetPostDataEncoding function to specify the POST data encoding method, and then call AddPostDataAscii or another appropriate function to add the data.

Specify a value defined by the nn::http::EncodingType enumerated type for the type argument.

Table 6-22. POST Data Encoding Methods

Definition

Description

ENCODING_TYPE_AUTO

Sends data in URL encoding if all data was added using the AddPostDataAscii function. Sends as multipart if any data was added using the AddPostDataBinary function. (Default.)

ENCODING_TYPE_URL

Sends data in URL encoding. Call the AddPostDataAscii function to add POST data.

ENCODING_TYPE_MULTIPART

Sends data without encoding it. POST data added using the AddPostDataAscii function is not encoded.

POST data added using the AddPostDataAscii function (ASCII string data) and sent in URL encoding has both labels and data encoded. POST data that includes binary data or for which the encoding method is specified as multi-part is sent without encoding either the labels or data.

POST data added using the AddPostDataBinary function (binary data) is sent as is, without encoding.

Call the AddPostDataRaw function to add multiple POST data items at the same time, unlike the two functions above. This function only allows you to specify binary POST data. Calling either the AddPostDataAscii or AddPostDataBinary functions after calling AddPostDataRaw returns an error with ER_POST_ADDED_ANOTHER set for the Description. Calling AddPostDataRaw a second time discards the data added the first time, adding instead the POST data specified in this second call.

6.3.4.1. Lazy POST Data Setting Mode

Use the lazy POST data setting mode to send POST data after initiating a connection. Note that the SendPostData* functions execute synchronously when sending POST data in this mode, so processing blocks until sending is finished. However, you can impose a timeout by specifying a value for the timeout parameter of the overloaded version. This causes the function to call Cancel internally after the timeout period has passed, canceling the connection.

Code 6-38. Sending in the Lazy POST Data Setting Mode
class nn::http::Connection
{
    nn::Result SetLazyPostDataSetting(nn::http::PostDataType dataType);
    nn::Result NotifyFinishSendPostData(void);
    nn::Result SendPostDataAscii(const char* pLabel, const char* pValue);
    nn::Result SendPostDataAscii(const char* pLabel, const char* pValue, 
                                 const nn::fnd::TimeSpan& timeout);
    nn::Result SendPostDataBinary(
                const char* pLabel, const void* pValue, size_t valueSize);
    nn::Result SendPostDataBinary(
                const char* pLabel, const void* pValue, size_t valueSize, 
                const nn::fnd::TimeSpan& timeout);
    nn::Result SendPostDataRaw(const void* pValue, size_t valueSize);
    nn::Result SendPostDataRaw(const void* pValue, size_t valueSize, 
                               const nn::fnd::TimeSpan& timeout);
}

Call the SetLazyPostDataSetting function to use this mode. The function to call and the sending method used for the POST data differ depending on the value specified for the sending data type specified in dataType. Specify a value defined by the nn::http::PostDataType enumerated type for the dataType parameter.

Table 6-23. Sending Data Types in the Lazy POST Data Setting Mode

Definition

Description

POST_DATA_TYPE_URLENCODE

Sends data in URL encoding.

POST_DATA_TYPE_MULTIPART

Sends data in multi-part format.

POST_DATA_TYPE_RAW

Sends data in raw format.

When sending in URL encoding, you can call either the SendPostDataAscii or SendPostDataBinary functions. Call SendPostDataAscii to send the data in URL encoding with a format where (label name)=(data content), and call SendPostDataBinary to send identical but unencoded data.

When sending in multi-part format, you can call either the SendPostDataAscii or SendPostDataBinary functions. Data is sent in chunks, with each chunk starting with boundary data and header fields. Both functions add a header field after the boundary data with the label Content-Disposition: form-data; name=[label]. The SendPostDataBinary function precedes this header with another one containing the text Content-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n.

When sending in raw format, you can call only the SendPostDataRaw function. Data is sent in chunks as chunked data.

You must call the NotifyFinishSendPostData function once done sending all POST data. After calling this function, the system waits to receive an HTTP response.

6.3.5. Opening a Connection

Initiate an HTTP connection to the URL specified in initialization. There are two ways to initiate a connection. Call either the Connect function, which blocks until a connection is established, or the ConnectAsync function, which returns immediately. Call the Cancel function to cancel a connection.

Code 6-39. Initiating and Canceling a Connection
class nn::http::Connection
{
    nn::Result Connect(void);
    nn::Result ConnectAsync(void);
    nn::Result Cancel(void);
}

Connect still blocks even if all HTTP connections available to the system are already in use, whereas ConnectAsync returns an error immediately.

Call the Cancel function to cancel an HTTP connection, with that instance of the Connection class halting communication.

Warning:

When a connection is initiated using the nn::http::Connection::Connect or nn::http::Connection::ConnectAsync function, if the WAN cable to the access point is removed while the function is receiving the header information, the function continues to wait forever.

To prevent this situation from occurring, you must implement your program in a way that terminates communication (by calling nn::http::Connection::Cancel) after a timeout period.

6.3.6. Receiving a Response

After calling Connect or a similar function to initiate connection, call the Read function to get the HTTP response message body, GetStatusCode to get the response status, GetHeaderField to get a specific message header, and GetHeaderAll to get all headers. You can impose a timeout by specifying a value for the timeout parameter of the overloaded version. This causes the function to call Cancel internally after the timeout period has passed, canceling the connection.

Code 6-40. Receiving a Response
class nn::http::Connection
{
    nn::Result Read(u8* pBodyBuf, size_t bufLen);
    nn::Result Read(u8* pBodyBuf, size_t bufLen, 
                    const nn::fnd::TimeSpan& timeout);
    nn::Result GetStatusCode(s32* pStatusCodeCourier) const;
    nn::Result GetStatusCode(s32* pStatusCodeCourier, 
                             const nn::fnd::TimeSpan& timeout) const;
    nn::Result GetHeaderField(
                const char* pLabel, char* pFieldBuf, size_t bufSize, 
                size_t* pFieldLengthCourier = NULL) const;
    nn::Result GetHeaderField(
                const char* pLabel, char* pFieldBuf, size_t bufSize, 
                const nn::fnd::TimeSpan& timeout, 
                size_t* pFieldLengthCourier = NULL) const;
    nn::Result GetHeaderAll(
                char* pHeaderBuf, size_t bufSize, 
                size_t* pLengthCourier = NULL) const;
    nn::Result GetHeaderAll(
                char* pHeaderBuf, size_t bufSize, 
                const nn::fnd::TimeSpan& timeout, 
                size_t* pLengthCourier = NULL) const;
} 

When calling the Read function, specify the buffer to store the message body in the pBodyBuf parameter and its size in the bufLen parameter. If the message body is too big to fit in the buffer, the function stores as much of the body as fits and then returns nn::http::ResultBodyBufShortage, in which case you can call Read again to read the remainder of the message body. Any other error returned indicates a failure to receive the HTTP response. However, HTTP status errors for events such as authentication failures are sent with the error message as the message body, so that Read operates as normal, as a successful connection, returning nn::http::ResultBodyBufShortage if the message body is too big to fit in the buffer, and returning an instance whose IsSuccess member returns true upon reading through to the end of the message body.

When calling the GetStatusCode function, specify an s32 variable in the pStatusCodeCourier parameter to store the response status. Check this response status to find out if any communication errors have occurred. If called when receiving the message header, this function blocks until the header has been fully received. If called after calling Read, the header has already been fully received, and this function returns immediately.

When calling the GetHeaderField function, specify the label of the header field to get in the pLabel parameter, the buffer to store this data in the pFieldBuf parameter, and the buffer size in the bufSize parameter. As long as pFieldBuf is not NULL, bufSize is not 0, and pFieldLengthCourier is not NULL, the size in bytes of the specified label’s header field is stored in the variable specified in pFieldLengthCourier.

When calling the GetHeaderAll function, specify the buffer to store all header fields in the pHeaderBuf parameter and the buffer size in the bufSize parameter. As long as pHeaderBuf is not NULL, bufSize is not 0, and pLengthCourier is not NULL, the size in bytes of the buffer required to store all message headers is stored in the variable specified in pLengthCourier. If called when receiving the message header, these functions block until the header has been fully received. If called after calling Read, the header has already been fully received, and these functions return immediately.

6.3.7. Getting Connection State and Other Information

The Connection class includes functions to get the state of the class, the codes of any errors that have occurred, and response reception progress.

Code 6-41. Getting Connection State and Other Information
class nn::http::Connection
{
    nn::Result GetStatus(nn::http::Status* pStatusBuf) const;
    nn::Result GetError(nn::http::ResultCode* pResultCodeBuf) const;
    nn::Result GetProgress(size_t* pReceivedLen, size_t* pContentLen) const;
} 

When calling the GetStatus function, specify a buffer in the pStatusBuf parameter to store the connection state. The stored value is an nn::http::Status enumerated type.

When calling the GetError function, specify a buffer in pResultCodeBuf parameter to store the error code. The stored value is an nn::http::ResultCode enumerated type.

When calling the GetProgress function, specify a variable in the pReceivedLen parameter to store the size in bytes of the message body received so far, and specify a variable in the pContentLen parameter to store the total length of the message body. This total length is the value of the Content-Length HTTP response header, so pContentLen stores 0 if the Content-Length header is missing.

6.3.8. Closing a Connection

After fully receiving the HTTP response and once the class instance is no longer needed, be sure to call the Finalize function to destroy it. You do not need to call the function for instances that have not been initialized and do not specify a target URL.

Code 6-42. Closing a Connection
class nn::http::Connection
{
    nn::Result Finalize(void);
} 

6.3.9. Finalizing

Call nn::http::Finalize after you finish using the HTTP library. The function returns nn::http::ResultNotInitializedErr if the library has not been initialized.

Code 6-43. Finalizing the HTTP Library
nn::Result nn::http::Finalize(void);

CONFIDENTIAL