Beispiel #1
0
static void
server_send(char *cmd)
{
  int l = strlen(cmd);
  byte *z = alloca(l + 1);

  memcpy(z, cmd, l);
  z[l++] = '\n';
  while (l)
    {
      int cnt = write(server_fd, z, l);

      if (cnt < 0)
	{
	  if (errno == EAGAIN)
	    wait_for_write(server_fd);
	  else if (errno == EINTR)
	    continue;
	  else
	    die("Server write error: %m");
	}
      else
	{
	  l -= cnt;
	  z += cnt;
	}
    }
}
Beispiel #2
0
/* send conn's ip and port which used to connect to user server
 * to mesage server */
void send_conn_info_to_message(struct conn_server *server)
{
	struct list_packet *lp = allocator_malloc(&server->packet_allocator);
	packet_init(lp);
	set_length(lp, 18);
	set_command(lp, CMD_CONN_INFO);
	set_field_uint32_t(get_parameters(lp), 0, server->conn_user_ip);
	set_field_uint16_t(get_parameters(lp), 4, server->conn_user_port);
	list_add_tail(&lp->list, &(server->message_conn.send_packet_list));
	wait_for_write(server->efd, server->message_conn.sfd);
}
Beispiel #3
0
/* send offline message to status server */
void send_offline_to_status(struct conn_server *server, uint32_t uin)
{
	struct list_packet *lp = allocator_malloc(&server->packet_allocator);
	packet_init(lp);
	set_length(lp, 24);
	set_command(lp, CMD_STATUS_CHANGE);
	set_uin(lp, uin);
	set_field_uint32_t(get_parameters(lp), 0, uin);
	set_field_uint16_t(get_parameters(lp), 10,
			STATUS_CHANGE_OFFLINE);
	list_add_tail(&lp->list, &(server->status_conn.send_packet_list));
	wait_for_write(server->efd, server->status_conn.sfd);
}
Beispiel #4
0
/* other kind of packet, check clienti's login type,
 * if login ok, send the packet to client */
void srv_other_packet(struct conn_server *server, struct list_packet *packet)
{
	uint32_t uin = get_uin(packet);
	struct connection *conn = get_conn_by_uin(server, uin);
	/* need to check login status */
	if (!conn || conn->type != LOGIN_OK_CONNECTION) {
		allocator_free(&server->packet_allocator, packet);
		return;
	}

	list_add_tail(&packet->list, &conn->send_packet_list);
	wait_for_write(server->efd, conn->sfd);
}
Beispiel #5
0
/* client login successful, we mark the conn as login_ok,
 * and send the packet to client */
void srv_login_ok(struct conn_server *server, struct list_packet *packet)
{
	uint32_t uin = get_uin(packet);
	struct connection *conn = get_conn_by_uin(server, uin);
	if (!conn) {
		allocator_free(&server->packet_allocator, packet);
		return;
	}

	conn->type = LOGIN_OK_CONNECTION;
	list_add_tail(&packet->list, &conn->send_packet_list);
	wait_for_write(server->efd, conn->sfd);
}
Beispiel #6
0
int dac_sendall(dac_t *d, const char *data, int len) {
	do {
		int res = wait_for_write(d, 1500000);
		if (res < 0) {
			return -1;
		} else if (res == 0) {
			trace(d, "write timed out\n");
		}

		res = send(d->conn.sock, data, len, 0);

		if (res == SOCKET_ERROR) {
			log_socket_error(d, "send");
			return -1;
		}

		len -= res;
		data += res;
	} while (len);

	return 0;
}
Beispiel #7
0
size_t network::stream_write(
    network::socket_t const &sockfd,
    void const              *buffer,
    size_t                   buffer_size,
    size_t                   buffer_offset,
    size_t                   amount_to_send,
    bool                    *out_disconnected,
    int                     *out_error /* = NULL */)
{
    char const *buf = (char*) buffer + buffer_offset;

    LLSOCKET_SET_ERROR_RESULT(0);

    if (buffer           == NULL     ||
        buffer_size      == 0        ||
        out_disconnected == NULL     ||
        buffer_offset  > buffer_size ||
        amount_to_send > buffer_size - buffer_offset)
    {
        // no data or invalid parameter. return immediately.
        if (out_disconnected != NULL) *out_disconnected = false;
        return 0;
    }

    // by default, we have not disconnected. if we detect a disconnection
    // while sending, we will set this value to true.
    *out_disconnected    = false;

    // enter a loop to ensure that all of the data gets sent.
    // we may have to issue multiple send calls to the socket.
    size_t retry_count   = 0;
    size_t bytes_sent    = 0;
    size_t bytes_total   = amount_to_send;
    while (bytes_sent    < bytes_total)
    {
        if (retry_count >= LLSOCKET_MAX_RETRIES)
        {
            // this socket has exceeded its retry count. disconnect it.
            network::stream_shutdown(sockfd, NULL, NULL);
            *out_disconnected = true;
            return 0;
        }

        // attempt to send as much data as we can write to the socket.
        int n_to_send   = (int) bytes_total - (int) bytes_sent;
        int n_sent      = send(sockfd, buf, n_to_send, 0);
        if (!network::socket_error(n_sent) && n_sent > 0)
        {
            // @note: do NOT reset retry_count to zero in this case.
            // under Windows at least, the socket will become available
            // again, but immediately fail. awesomeness.
            bytes_sent  += n_sent;
            buf         += n_sent;
            continue;
        }

#if defined(_WIN32) || defined(_WIN64)
        // an error occurred. determine whether we are still connected.
        int     err = WSAGetLastError();
        switch (err)
        {
            case WSANOTINITIALISED:
            case WSAENETDOWN:
            case WSAENETRESET:
            case WSAENOTCONN:
            case WSAENOTSOCK:
            case WSAESHUTDOWN:
            case WSAEHOSTUNREACH:
            case WSAEINVAL:
            case WSAECONNABORTED:
            case WSAECONNRESET:
            case WSAETIMEDOUT:
                {
                    // something has gone wrong with the connection.
                    network::stream_shutdown(sockfd, NULL, NULL);
                    LLSOCKET_SET_ERROR_RESULT(err);
                    *out_disconnected = true;
                }
                return bytes_sent;

            case WSAEACCES:
                {
                    // attempted to send to a broadcast address without
                    // setting the appropriate socket options.
                    network::stream_shutdown(sockfd, NULL, NULL);
                    LLSOCKET_SET_ERROR_RESULT(err);
                    *out_disconnected = true;
                }
                return bytes_sent;

            case WSAENOBUFS:     // ENOBUFS
            case WSAEWOULDBLOCK: // EAGAIN
                {
                    // the resource is temporarily unavailable, probably
                    // because the socket is being flooded with data. we
                    // wait until the socket becomes available again, or
                    // our timeout interval elapses. if the socket becomes
                    // available, we continue sending; if the select times
                    // out, we forcibly disconnect the client.
                    if (wait_for_write(sockfd, LLSOCKET_WAIT_TIMEOUT_USEC))
                    {
                        // the socket is available again. retry.
                        retry_count++;
                        break;
                    }
                    else
                    {
                        // the wait timed out. disconnect the socket.
                        network::stream_shutdown(sockfd, NULL, NULL);
                        LLSOCKET_SET_ERROR_RESULT(err);
                        *out_disconnected = true;
                    }
                }
                return bytes_sent;

            default:
                {
                    // unknown error; try again.
                    LLSOCKET_SET_ERROR_RESULT(err);
                    retry_count++;
                }
                break;
        }
#else
        // an error occurred. determine whether we are still connected.
        int     err = errno;
        switch (err)
        {
            case EBADF:
            case ECONNRESET:
            case ENOTCONN:
            case ENOTSOCK:
            case ETIMEDOUT:
            case EHOSTUNREACH:
            case ENETDOWN:
            case ENETUNREACH:
            case EPIPE:
                {
                    // something has gone wrong with the connection.
                    network::stream_shutdown(sockfd, NULL, NULL);
                    LLSOCKET_SET_ERROR_RESULT(err);
                    *out_disconnected = true;
                }
                return bytes_sent;

            case EACCES:
                {
                    // attempted to send to a broadcast address without
                    // setting the appropriate socket options.
                    network::stream_shutdown(sockfd, NULL, NULL);
                    LLSOCKET_SET_ERROR_RESULT(err);
                    *out_disconnected = true;
                }
                return bytes_sent;

            case ENOBUFS:
            case EAGAIN:
                {
                    // the resource is temporarily unavailable, probably
                    // because the socket is being flooded with data. we
                    // wait until the socket becomes available again, or
                    // our timeout interval elapses. if the socket becomes
                    // available, we continue sending; if the select times
                    // out, we forcibly disconnect the client.
                    if (wait_for_write(sockfd, LLSOCKET_WAIT_TIMEOUT_USEC))
                    {
                        // the socket is available again. retry.
                        retry_count++;
                        break;
                    }
                    else
                    {
                        // the wait timed out. disconnect the socket.
                        network::stream_shutdown(sockfd, NULL, NULL);
                        LLSOCKET_SET_ERROR_RESULT(err);
                        *out_disconnected = true;
                    }
                }
                return bytes_sent;

            default:
                {
                    // unknown error; try again.
                    LLSOCKET_SET_ERROR_RESULT(err);
                    retry_count++;
                }
                break;
        }
#endif
    }
    return bytes_sent;
}
Beispiel #8
0
/* we need to forward this packet to message server, so put it onto
 * message_conn's send queue */
void cmd_message(struct conn_server *server, struct connection *conn,
		struct list_packet *packet)
{
	list_add_tail(&packet->list, &(server->message_conn.send_packet_list));
	wait_for_write(server->efd, server->message_conn.sfd);
}