/** * Handles incoming data on a client connection. * @param socket_server Socket server * @param conn Client connection */ static void handle_connection(struct lwpb_transport_socket_server *socket_server, struct lwpb_socket_server_conn *conn) { void *res_buf; size_t res_len; ssize_t len; size_t used; struct protocol_header_info info; lwpb_err_t ret; used = conn->pos - conn->buf; len = recv(conn->socket, conn->pos, conn->len - used, 0); if (len <= 0) { close_connection(socket_server, conn); return; } conn->pos += len; used = conn->pos - conn->buf; LWPB_DEBUG("Client(%d) received %d bytes", conn->index, len); // Try to decode the request ret = parse_request(conn->buf, used, &info, socket_server->server->service_list); if (ret != PARSE_ERR_OK) return; LWPB_DEBUG("Client(%d) received request header", conn->index); LWPB_DEBUG("type = %d, service = %p, method = %p, header_len = %d, msg_len = %d", info.msg_type, info.service_desc, info.method_desc, info.header_len, info.msg_len); if (!info.service_desc) { // TODO unknown service } if (!info.method_desc) { // TODO unknown method } // Allocate response buffer ret = lwpb_transport_alloc_buf(&socket_server->super, &res_buf, &res_len); if (ret != LWPB_ERR_OK) { // TODO handle memory error } ret = socket_server->server->call_handler( socket_server->server, info.method_desc, info.method_desc->req_desc,conn->buf + info.header_len, info.msg_len, info.method_desc->res_desc, res_buf, &res_len, socket_server->server->arg); // Send response back to server send_response(conn->socket, info.method_desc, res_buf, res_len); lwpb_transport_free_buf(&socket_server->super, res_buf); }
static void handle_data(struct lwpb_transport_socket_client *socket_client) { ssize_t len; size_t used; struct protocol_header_info info; lwpb_err_t ret; used = socket_client->pos - socket_client->buf; len = recv(socket_client->socket, socket_client->pos, socket_client->len - used, 0); if (len <= 0) { // Server closed connection TODO LWPB_FAIL("Server closed connection"); return; } socket_client->pos += len; used = socket_client->pos - socket_client->buf; LWPB_DEBUG("Received %d bytes", len); // Try to decode the request ret = parse_request(socket_client->buf, used, &info, NULL); if (ret != PARSE_ERR_OK) return; LWPB_DEBUG("Received request header"); LWPB_DEBUG("type = %d, service = %p, method = %p, header_len = %d, msg_len = %d", info.msg_type, info.service_desc, info.method_desc, info.header_len, info.msg_len); if (!info.service_desc) { // TODO unknown service } if (!info.method_desc) { // TODO unknown method } // Process response ret = socket_client->client->response_handler( socket_client->client, socket_client->last_method, socket_client->last_method->res_desc, socket_client->buf + info.header_len, info.msg_len, socket_client->client->arg); if (ret != LWPB_ERR_OK) { } }
/** * Closes a client connection. * @param socket_server Socket server * @param conn Client connection */ static void close_connection(struct lwpb_transport_socket_server *socket_server, struct lwpb_socket_server_conn *conn) { LWPB_DEBUG("Client(%d) disconnected", conn->index); close(conn->socket); conn->socket = -1; socket_server->num_conns--; }
/** * Accepts new connections on the listen socket. * @param socket_server Socket server */ static void handle_new_connection(struct lwpb_transport_socket_server *socket_server) { int socket; struct sockaddr_storage addr; socklen_t len = sizeof(addr); char tmp[16]; struct sockaddr_in *addr_in; int i; const char msg[] = "No more connections allowed\n"; socket = accept(socket_server->socket, (struct sockaddr *) &addr, &len); if (socket < 0) { LWPB_ERR("Accepting new socket failed (errno: %d)", errno); return; } make_nonblock(socket); for (i = 0; i < LWPB_TRANSPORT_SOCKET_SERVER_CONNS; i++) { struct lwpb_socket_server_conn *conn = &socket_server->conns[i]; if (conn->socket == -1) { addr_in = (struct sockaddr_in *) &addr; inet_ntop(addr.ss_family, &addr_in->sin_addr, tmp, sizeof(tmp)); LWPB_DEBUG("Client(%d) accepted conncetion from %s", conn->index, tmp); conn->socket = socket; if (!conn->buf) lwpb_transport_alloc_buf(&socket_server->super, &conn->buf, &conn->len); conn->pos = conn->buf; socket_server->num_conns++; return; } } // No more connections allowed LWPB_DEBUG("No more connections allowed"); send(socket, msg, sizeof(msg), 0); close(socket); }
/** * Initializes the socket client transport implementation. * @param socket_client Socket client transport data * @return Returns the transport handle. */ lwpb_transport_t lwpb_transport_socket_client_init( struct lwpb_transport_socket_client *socket_client) { int i; LWPB_DEBUG("Initializing socket client"); lwpb_transport_init(&socket_client->super, &transport_funs); socket_client->client = NULL; socket_client->socket = -1; socket_client->buf = NULL; return &socket_client->super; }
/** * Initializes the socket server transport implementation. * @param socket_server Socket server transport data * @return Returns the transport handle. */ lwpb_transport_t lwpb_transport_socket_server_init( struct lwpb_transport_socket_server *socket_server) { int i; LWPB_DEBUG("Initializing socket server"); lwpb_transport_init(&socket_server->super, &transport_funs); socket_server->server = NULL; socket_server->socket = -1; socket_server->num_conns = 0; for (i = 0; i < LWPB_TRANSPORT_SOCKET_SERVER_CONNS; i++) { struct lwpb_socket_server_conn *conn = &socket_server->conns[i]; conn->index = i; conn->socket = -1; conn->buf = NULL; } return &socket_server->super; }
/** * Opens the socket server for communication. * @param transport Transport handle * @param host Hostname or IP address (using local address if NULL) * @param port Port number for listen port * @return Returns LWPB_ERR_OK if successful. */ lwpb_err_t lwpb_transport_socket_server_open(lwpb_transport_t transport, const char *host, u16_t port) { struct lwpb_transport_socket_server *socket_server = (struct lwpb_transport_socket_server *) transport; lwpb_err_t ret = LWPB_ERR_OK; int status; struct addrinfo hints; struct addrinfo *res; struct sockaddr_in *addr; char tmp[16]; int yes = 1; if (socket_server->socket != -1) { LWPB_INFO("Socket server already opened"); return LWPB_ERR_OK; } // Resolve hostname LWPB_DEBUG("Resolving hostname '%s'", host); memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; // IPv4 hints.ai_socktype = SOCK_STREAM; // TCP stream sockets hints.ai_flags = AI_PASSIVE; // Fill in the IP snprintf(tmp, sizeof(tmp), "%d", port); if ((status = getaddrinfo(host, tmp, &hints, &res)) != 0) { LWPB_ERR("getaddrinfo error: %s\n", gai_strerror(status)); ret = LWPB_ERR_NET_INIT; goto out; } addr = (struct sockaddr_in *) res->ai_addr; inet_ntop(res->ai_family, &addr->sin_addr, tmp, sizeof(tmp)); // Create server socket LWPB_DEBUG("Creating server socket"); socket_server->socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (socket_server->socket == -1) { LWPB_ERR("Cannot create server socket"); ret = LWPB_ERR_NET_INIT; goto out; } // Reuse address if necessary if (setsockopt(socket_server->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { LWPB_ERR("Cannot set SO_REUSEADDR (error: %d)", errno); ret = LWPB_ERR_NET_INIT; goto out; } // Make non-blocking make_nonblock(socket_server->socket); // Bind listen socket LWPB_DEBUG("Binding server socket to %s:%d", tmp, port); if (bind(socket_server->socket, res->ai_addr, res->ai_addrlen) == -1) { LWPB_ERR("Cannot bind server socket (errno: %d)", errno); ret = LWPB_ERR_NET_INIT; goto out; } // Start listening LWPB_DEBUG("Start listening on server socket"); if (listen(socket_server->socket, LWPB_TRANSPORT_SOCKET_SERVER_CONNS) == -1) { LWPB_ERR("Cannot listen on server socket (errno: %d)", errno); close(socket_server->socket); ret = LWPB_ERR_NET_INIT; goto out; } out: freeaddrinfo(res); return ret; }
/** * Opens the socket client for communication. * @param transport Transport handle * @param host Hostname or IP address (using local address if NULL) * @param port Port number for listen port * @return Returns LWPB_ERR_OK if successful. */ lwpb_err_t lwpb_transport_socket_client_open(lwpb_transport_t transport, const char *host, u16_t port) { struct lwpb_transport_socket_client *socket_client = (struct lwpb_transport_socket_client *) transport; lwpb_err_t ret = LWPB_ERR_OK; int status; struct addrinfo hints; struct addrinfo *res; struct sockaddr_in *addr; char tmp[16]; int yes = 1; if (socket_client->socket != -1) { LWPB_INFO("Socket client already opened"); return LWPB_ERR_OK; } // Allocate receive buffer ret = lwpb_transport_alloc_buf(&socket_client->super, &socket_client->buf, &socket_client->len); if (ret != LWPB_ERR_OK) return ret; socket_client->pos = socket_client->buf; // Resolve hostname LWPB_DEBUG("Resolving hostname '%s'", host); memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; // IPv4 hints.ai_socktype = SOCK_STREAM; // TCP stream sockets hints.ai_flags = AI_PASSIVE; // Fill in the IP snprintf(tmp, sizeof(tmp), "%d", port); if ((status = getaddrinfo(host, tmp, &hints, &res)) != 0) { LWPB_ERR("getaddrinfo error: %s\n", gai_strerror(status)); ret = LWPB_ERR_NET_INIT; goto out; } addr = (struct sockaddr_in *) res->ai_addr; inet_ntop(res->ai_family, &addr->sin_addr, tmp, sizeof(tmp)); // Create client socket LWPB_DEBUG("Creating client socket"); socket_client->socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (socket_client->socket == -1) { LWPB_ERR("Cannot create client socket"); ret = LWPB_ERR_NET_INIT; goto out; } // Reuse address if necessary if (setsockopt(socket_client->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { LWPB_ERR("Cannot set SO_REUSEADDR (error: %d)", errno); ret = LWPB_ERR_NET_INIT; goto out; } // Connect to server LWPB_DEBUG("Connecting to %s:%d", tmp, port); if (connect(socket_client->socket, res->ai_addr, res->ai_addrlen) == -1) { LWPB_ERR("Cannot open connection (errno: %d)", errno); ret = LWPB_ERR_NET_INIT; goto out; } // Make non-blocking make_nonblock(socket_client->socket); out: freeaddrinfo(res); return ret; }