fastdfs/storage/fdht_client/fdht_proto.c

487 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
**/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include "fdht_define.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "fastcommon/sockopt.h"
#include "fdht_types.h"
#include "fdht_proto.h"
extern int g_fdht_network_timeout;
int fdht_recv_header(FDHTServerInfo *pServer, fdht_pkg_size_t *in_bytes)
{
FDHTProtoHeader resp;
int result;
if ((result=tcprecvdata_nb(pServer->sock, &resp, \
sizeof(resp), g_fdht_network_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"server: %s:%u, recv data fail, " \
"errno: %d, error info: %s", \
__LINE__, pServer->ip_addr, \
pServer->port, \
result, STRERROR(result));
*in_bytes = 0;
return result;
}
if (resp.status != 0)
{
*in_bytes = 0;
return resp.status;
}
*in_bytes = buff2int(resp.pkg_len);
if (*in_bytes < 0)
{
logError("file: "__FILE__", line: %d, " \
"server: %s:%u, recv package size %d " \
"is not correct", \
__LINE__, pServer->ip_addr, \
pServer->port, *in_bytes);
*in_bytes = 0;
return EINVAL;
}
return resp.status;
}
int fdht_recv_response(FDHTServerInfo *pServer, \
char **buff, const int buff_size, \
fdht_pkg_size_t *in_bytes)
{
int result;
bool bMalloced;
result = fdht_recv_header(pServer, in_bytes);
if (result != 0)
{
return result;
}
if (*in_bytes == 0)
{
return 0;
}
if (*buff == NULL)
{
*buff = (char *)malloc((*in_bytes) + 1);
if (*buff == NULL)
{
*in_bytes = 0;
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail", \
__LINE__, (*in_bytes) + 1);
return errno != 0 ? errno : ENOMEM;
}
bMalloced = true;
}
else
{
if (*in_bytes > buff_size)
{
logError("file: "__FILE__", line: %d, " \
"server: %s:%u, recv body bytes: %d" \
" exceed max: %d", \
__LINE__, pServer->ip_addr, \
pServer->port, *in_bytes, buff_size);
*in_bytes = 0;
return ENOSPC;
}
bMalloced = false;
}
if ((result=tcprecvdata_nb(pServer->sock, *buff, \
*in_bytes, g_fdht_network_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"server: %s:%u, recv data fail, " \
"errno: %d, error info: %s", \
__LINE__, pServer->ip_addr, \
pServer->port, \
result, STRERROR(result));
*in_bytes = 0;
if (bMalloced)
{
free(*buff);
*buff = NULL;
}
return result;
}
return 0;
}
int fdht_quit(FDHTServerInfo *pServer)
{
FDHTProtoHeader header;
int result;
memset(&header, 0, sizeof(header));
header.cmd = FDHT_PROTO_CMD_QUIT;
result = tcpsenddata_nb(pServer->sock, &header, sizeof(header), \
g_fdht_network_timeout);
if(result != 0)
{
logError("file: "__FILE__", line: %d, " \
"server ip: %s, send data fail, " \
"errno: %d, error info: %s", \
__LINE__, pServer->ip_addr, \
result, STRERROR(result));
return result;
}
return 0;
}
void fdht_disconnect_server(FDHTServerInfo *pServer)
{
if (pServer->sock > 0)
{
close(pServer->sock);
pServer->sock = -1;
}
}
int fdht_connect_server_nb(FDHTServerInfo *pServer, const int connect_timeout)
{
int result;
if (pServer->sock > 0)
{
close(pServer->sock);
}
// 通过判断IP地址是IPv4或者IPv6根据结果进行初始化
if (is_ipv6_addr(pServer->ip_addr))
{
pServer->sock = socket(AF_INET6, SOCK_STREAM, 0);
}else{
pServer->sock = socket(AF_INET, SOCK_STREAM, 0);
}
if(pServer->sock < 0)
{
logError("file: "__FILE__", line: %d, " \
"socket create failed, errno: %d, " \
"error info: %s", __LINE__, \
errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
if ((result=tcpsetnonblockopt(pServer->sock)) != 0)
{
close(pServer->sock);
pServer->sock = -1;
return result;
}
if ((result=connectserverbyip_nb(pServer->sock, \
pServer->ip_addr, pServer->port, connect_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"connect to %s:%u fail, errno: %d, " \
"error info: %s", __LINE__, pServer->ip_addr, \
pServer->port, result, STRERROR(result));
close(pServer->sock);
pServer->sock = -1;
return result;
}
return 0;
}
int fdht_connect_server(FDHTServerInfo *pServer)
{
int result;
if (pServer->sock > 0)
{
close(pServer->sock);
}
// 通过判断IP地址是IPv4或者IPv6根据结果进行初始化
if (is_ipv6_addr(pServer->ip_addr))
{
pServer->sock = socket(AF_INET6, SOCK_STREAM, 0);
}else{
pServer->sock = socket(AF_INET, SOCK_STREAM, 0);
}
if(pServer->sock < 0)
{
logError("file: "__FILE__", line: %d, " \
"socket create failed, errno: %d, " \
"error info: %s", __LINE__, \
errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
if ((result=connectserverbyip(pServer->sock, \
pServer->ip_addr, pServer->port)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"connect to %s:%u fail, errno: %d, " \
"error info: %s", __LINE__, pServer->ip_addr, \
pServer->port, result, STRERROR(result));
close(pServer->sock);
pServer->sock = -1;
return result;
}
if ((result=tcpsetnonblockopt(pServer->sock)) != 0)
{
close(pServer->sock);
pServer->sock = -1;
return result;
}
return 0;
}
/**
* request body format:
* namespace_len: 4 bytes big endian integer
* namespace: can be emtpy
* obj_id_len: 4 bytes big endian integer
* object_id: the object id (can be empty)
* key_len: 4 bytes big endian integer
* key: key name
* value_len: 4 bytes big endian integer
* value: value buff
* response body format:
* none
*/
int fdht_client_set(FDHTServerInfo *pServer, const char keep_alive, \
const time_t timestamp, const time_t expires, const int prot_cmd, \
const int key_hash_code, FDHTKeyInfo *pKeyInfo, \
const char *pValue, const int value_len)
{
int result;
char buff[sizeof(FDHTProtoHeader) + FDHT_MAX_FULL_KEY_LEN + 16 + 1024];
FDHTProtoHeader *pHeader;
int in_bytes;
char *p;
memset(buff, 0, sizeof(buff));
pHeader = (FDHTProtoHeader *)buff;
pHeader->cmd = prot_cmd;
pHeader->keep_alive = keep_alive;
int2buff((int)timestamp, pHeader->timestamp);
int2buff((int)expires, pHeader->expires);
int2buff(key_hash_code, pHeader->key_hash_code);
int2buff(16 + pKeyInfo->namespace_len + pKeyInfo->obj_id_len + \
pKeyInfo->key_len + value_len, pHeader->pkg_len);
p = buff + sizeof(FDHTProtoHeader);
PACK_BODY_UNTIL_KEY(pKeyInfo, p)
int2buff(value_len, p);
p += 4;
if ((p - buff) + value_len <= sizeof(buff))
{
memcpy(p, pValue, value_len);
p += value_len;
if ((result=tcpsenddata_nb(pServer->sock, buff, p - buff, \
g_fdht_network_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"send data to server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
return result;
}
}
else
{
if ((result=tcpsenddata_nb(pServer->sock, buff, p - buff, \
g_fdht_network_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"send data to server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
return result;
}
if ((result=tcpsenddata_nb(pServer->sock, (char *)pValue, \
value_len, g_fdht_network_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"send data to server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
return result;
}
}
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"recv data from server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
return result;
}
if (in_bytes != 0)
{
logError("file: "__FILE__", line: %d, " \
"server %s:%u reponse bytes: %d != 0", \
__LINE__, pServer->ip_addr, \
pServer->port, in_bytes);
return EINVAL;
}
return 0;
}
/**
* request body format:
* namespace_len: 4 bytes big endian integer
* namespace: can be emtpy
* obj_id_len: 4 bytes big endian integer
* object_id: the object id (can be empty)
* key_len: 4 bytes big endian integer
* key: key name
* response body format:
* none
*/
int fdht_client_delete(FDHTServerInfo *pServer, const char keep_alive, \
const time_t timestamp, const int prot_cmd, \
const int key_hash_code, FDHTKeyInfo *pKeyInfo)
{
int result;
FDHTProtoHeader *pHeader;
char buff[sizeof(FDHTProtoHeader) + FDHT_MAX_FULL_KEY_LEN + 16];
int in_bytes;
char *p;
memset(buff, 0, sizeof(buff));
pHeader = (FDHTProtoHeader *)buff;
pHeader->cmd = prot_cmd;
pHeader->keep_alive = keep_alive;
int2buff(timestamp, pHeader->timestamp);
int2buff(key_hash_code, pHeader->key_hash_code);
int2buff(12 + pKeyInfo->namespace_len + pKeyInfo->obj_id_len + \
pKeyInfo->key_len, pHeader->pkg_len);
p = buff + sizeof(FDHTProtoHeader);
PACK_BODY_UNTIL_KEY(pKeyInfo, p)
if ((result=tcpsenddata_nb(pServer->sock, buff, p - buff, \
g_fdht_network_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"send data to server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
return result;
}
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
{
if (result == ENOENT)
{
logWarning("file: "__FILE__", line: %d, " \
"recv data from server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
}
else
{
logError("file: "__FILE__", line: %d, " \
"recv data from server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
}
return result;
}
if (in_bytes != 0)
{
logError("file: "__FILE__", line: %d, " \
"server %s:%u reponse bytes: %d != 0", \
__LINE__, pServer->ip_addr, \
pServer->port, in_bytes);
return EINVAL;
}
return 0;
}
int fdht_client_heart_beat(FDHTServerInfo *pServer)
{
int result;
FDHTProtoHeader header;
int in_bytes;
memset(&header, 0, sizeof(header));
header.cmd = FDHT_PROTO_CMD_HEART_BEAT;
header.keep_alive = 1;
if ((result=tcpsenddata_nb(pServer->sock, &header, \
sizeof(header), g_fdht_network_timeout)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"send data to server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
return result;
}
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"recv data from server %s:%u fail, " \
"errno: %d, error info: %s", __LINE__, \
pServer->ip_addr, pServer->port, \
result, STRERROR(result));
return result;
}
if (in_bytes != 0)
{
logError("file: "__FILE__", line: %d, " \
"server %s:%u reponse bytes: %d != 0", \
__LINE__, pServer->ip_addr, \
pServer->port, in_bytes);
return EINVAL;
}
return 0;
}