/** * recv_data - 非阻塞接收固定大小数据,在超时时间(timeout)内不接收完不返回 * * @sockfd [in] 套接字 * @buf [in] 接收数据缓存 * @size [in] 接收数据大小 * @timeout [in] 接收的超时时间(秒),默认为3 * * return: * == 0 成功 * != 0 错误码,error.h的错误码 * */ int rcv_non_block( int sockfd, char* buf, int size, int timeout /*= 3*/) { int rsize = 0; int flag, errorcode, res; while ( rsize != size ) { errorcode = recv( sockfd, buf + rsize, size - rsize, 0 ); if ( errorcode == 0 ) return BUILD_ERROR(_OSerrno(), E_RCV); else if ( errorcode == SOCKET_ERROR ) { errorcode = GetLastError(); if ( WSAEWOULDBLOCK == errorcode ) { flag = 0x1; res = select_socket( &sockfd, &flag, 1, timeout, 0 ); if ( 0 != res ) { return res; } else continue; } return BUILD_ERROR(errorcode, 0); } rsize += errorcode; } return 0; }
/** * select2sock - 用select管理两套接字 * * @cliSockInfo: [in/out] 已建立好连接的与srv的套接字相关信息 * @srvSockInfo: [in/out] 已建立好连接的与cli的套接字相关信息 * * * return * <0 错误码里包含具体原因(有端关闭?用户取消线程) */ int select2sock(SOCK_INFO &cliSockInfo, SOCK_INFO &srvSockInfo) { struct timeval tv; /** the timeout of select*/ fd_set fdRead; /** the fd_set*/ unsigned long toSrvBytes = 0; /** transmit from cli to srv bytes*/ unsigned long toCliBytes = 0; /** transmit from srv to cli bytes*/ int ret; if(ret = init(cliSockInfo.sock, srvSockInfo.sock, tv) < 0) return ret; while(1) { if(USER_CANCLE) /** cancel this thread*/ return BUILD_ERROR(0, EFASTCLOSE); INIT_SELECT(fdRead, cliSockInfo.sock, srvSockInfo.sock); ret = select(0, &fdRead, NULL, NULL, &tv); switch (ret) { case SOCKET_ERROR: /** some error happen*/ ret = BUILD_ERROR(_OSerrno(), ESUCESS); break; case 0: /** select timeout*/ ret = 0; break; default: /** need to look for fdRead and transmit*/ ret = trsData(fdRead, cliSockInfo, srvSockInfo); break; } if(ret < 0) return ret; } }
/** * setSockBuf - 设置套接字的发送缓冲区与接收缓冲区 * * @sock: [in] 需要设置的套接字 * return * ==0 成功 * < 0 失败 */ int setSockBuf(SOCKET sock) { int optVal = SOCKET_BUFF_SIZE; int optLen = sizeof(int); /** set recv buffer size*/ if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, optLen) == SOCKET_ERROR) return BUILD_ERROR(_OSerrno(), EOS); /** set send buffer size*/ if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, optLen) == SOCKET_ERROR) return BUILD_ERROR(_OSerrno(), EOS); return 0; }
/** * selectSocket - 检查描述符状态 * * @pfd [in]所有待检查描述符数组指针 * @pflag [in]所有描述符需要校验的标志位数组(每个元素的0位:可读校验;1位:可写校验;2位:err校验) * @count [in]描述符号个数 * @tval [in]超时时间设置结构 * * return: * == 0 成功 * != 0 错误码,对应errorcode.h中定义的错误原因 */ int select_socket( const int* pfd, int* pflag, int count, int sec, int usec ) { int i, err, maxfd1 = 0; fd_set fdr, fdw, fde; struct timeval tval; FD_ZERO( &fdr ); FD_ZERO( &fdw ); FD_ZERO( &fde ); for ( i = 0; i < count; i++ ) { if ( pfd[i] > maxfd1 ) maxfd1 = pfd[i]; if ( (pflag[i] & 0x1) ) FD_SET( (const unsigned int)pfd[i], &fdr ); if ( (pflag[i] & 0x2) ) FD_SET( (const unsigned int)pfd[i], &fdw ); if ( (pflag[i] & 0x4) ) FD_SET( (const unsigned int)pfd[i], &fde ); } tval.tv_sec = sec; tval.tv_usec = usec; err = select( maxfd1 + 1, &fdr, &fdw, &fde, &tval ); if ( err == SOCKET_ERROR ) { return BUILD_ERROR(_OSerrno(), E_MYABORT); } else if ( 0 == err ) return BUILD_ERROR(0, E_TIMEOUT); for ( i = 0; i < count; i++ ) { if ( pflag[i] & 0x1 ) if ( !FD_ISSET( (const int)pfd[i], &fdr ) ) pflag[i] &= (~0x1); if ( pflag[i] & 0x2 ) if ( !FD_ISSET( (const int)pfd[i], &fdw ) ) pflag[i] &= (~0x2); if ( pflag[i] & 0x4 ) if ( !FD_ISSET( (const int)pfd[i], &fde ) ) pflag[i] &= (~0x4); } return 0; }
/*开始监听*/ unsigned int __stdcall smg_listen(void *in) { int lis_sock = (int)in; struct sockaddr_in client; int addr_size = sizeof(client); int cli_sock; listen(lis_sock, 5); while(1){ cli_sock = accept(lis_sock, (struct sockaddr *)&client, &addr_size); if(cli_sock == INVALID_SOCKET) return BUILD_ERROR(_OSerrno(), 0); g_log.writeLog(LOG_TYPE_INFO, "通过监听端口[%d] 从[%s:%d] 收到socket[%d]", g_option.smg_bind_port, inet_ntoa(client.sin_addr), ntohs(client.sin_port), cli_sock); /*创建线程来处理该连接*/ _beginthreadex(NULL, 0, srv_thread, (void *)cli_sock, 0, NULL); } return 0; }
/** * initLog - 初始化一个日志文件 * * @handle: [in] 全局句柄 * @logName: [in] 日志文件名 * @logSuffix [in] 日志文件的后缀名 * * Note: 如果传入的dir是非法的或是不存在的,该函数会返回失败 * * return * 0 成功 * <0 失败 */ int MWriteLog::initLog(HANDLE handle, char *logName, char *logSuffix) { char szPath[256] = {0}; char gcCliLog[256] = {0}; /* gcClient.log的绝对路径 */ bool writeDisk = false; /* 默认不写日志 */ int rc; /*定义需要生成日志文件所创建的文件名(在handle所在的目录下)*/ #define GCLOG "gcClient.log" m_handle = handle; rc = ::GetModuleFileName((HMODULE)handle, szPath, sizeof(szPath)-1); if(rc == 0) return BUILD_ERROR(_OSerrno(), 0); rc = _getDir(szPath, strlen(szPath)); if(rc != 0) return rc; rc = _snprintf(gcCliLog, sizeof(gcCliLog)-1-sizeof(GCLOG), szPath); if(gcCliLog[strlen(gcCliLog)-1] != '\\'){ gcCliLog[strlen(gcCliLog)] = '\\'; ++rc; } _snprintf(gcCliLog+rc, sizeof(GCLOG), "%s", GCLOG); if(_access(gcCliLog, 0) != -1)/*存在*/ writeDisk = true; return initLog(szPath, writeDisk, logName, logSuffix); #undef GCLOG }
/** * setSockUnBlock - 设置套接字为非阻塞 * * @sock: [in] 需要设置的套接字 * return * ==0 成功 * <0 失败 */ int setSockUnBlock(SOCKET sock) { unsigned long arg = 1; if(ioctlsocket(sock, FIONBIO, (unsigned long*)&arg) == SOCKET_ERROR) return BUILD_ERROR(_OSerrno(), ESETSOCK); return 0; }
int block_connect(char *ip, unsigned short port) { int err; struct sockaddr_in addrServer; if((err = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET) return BUILD_ERROR(_OSerrno(), 0); addrServer.sin_family = AF_INET; addrServer.sin_addr.s_addr = inet_addr(ip); addrServer.sin_port = htons(port); if(connect(err,(const struct sockaddr *)&addrServer,sizeof(sockaddr)) != 0) return BUILD_ERROR(_OSerrno(), 0); return err; }
int init_network() { WSADATA wsd; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) return BUILD_ERROR(_OSerrno(), 0); return 0; }
/** * send_nonblock - 非阻塞发送固定大小数据 * * @sockfd [in]套接字 * @buf [in]发送数据缓存 * @size [in]发送数据大小 * * return: * == 0 成功 * != 0 错误码,error.h */ int send_nonblock( int sockfd, char* buf, int size ) { int rc; rc = send( sockfd, buf, size, 0 ); if(rc != size) return BUILD_ERROR(_OSerrno(), 0); return 0; }
int create_listen(unsigned short port) { int listen_sock; struct sockaddr_in local; listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (listen_sock == SOCKET_ERROR) return BUILD_ERROR(_OSerrno(), 0); local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_family = AF_INET; local.sin_port = htons(port); re_bind_sock(listen_sock); /*设置重绑定*/ if (bind(listen_sock, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR) return BUILD_ERROR(_OSerrno(), 0); /*注意:当端口被占用时,必须要返回这个错误码,用户才会重新设置监听端口*/ return listen_sock; }
/** * cliToSrv - 从客户端向服务端转发数据 * * @hs [in] 操作数 * * return * ==0 正常,不需要关闭套接字 * <0 出错(包括有套接字关闭) */ int cliToSrv(SOCK_INFO &hs) { int ret; char *pSend = NULL; ret = recv(hs.sock, hs.buffer+MAX_HTTPHEAD_SIZE, MAX_IOBUFFER_LEN, 0); if(ret <= 0) return BUILD_ERROR(_OSerrno(), ECCLOSE); ret = buildHttpData(hs.buffer+MAX_HTTPHEAD_SIZE, ret, MAX_HTTPHEAD_SIZE, &pSend, hs.usUnitSerial, hs.ulLinkNo); if(ret < 0) return ret; ret = sendToPeer(hs.peerSock, pSend, ret); if(ret != 0) return BUILD_ERROR(_OSerrno(), ESCLOSE); return 0; }
int del_report(struct msg_report &node, struct report_list &rep_list) { MLocalSection locSec; if(list_empty(&rep_list.msg_used)) return BUILD_ERROR(0, E_LIST_EMPTY); locSec.Attch(&rep_list.msg_lock); struct report_node *pNode = list_entry(rep_list.msg_used.next, struct report_node, list_node); assert(pNode != NULL); memmove(&node, &(pNode->rep), sizeof(node)); _del2insert(&(pNode->list_node), &rep_list.msg_free); return 0; }
int add_report(struct msg_report &rep_msg, struct report_list &rep_list) { MLocalSection locSec; locSec.Attch(&rep_list.msg_lock); if(list_empty(&rep_list.msg_free)) //链表满 return BUILD_ERROR(0, E_MSG_LEN); struct report_node *pNode = list_entry(rep_list.msg_free.next, struct report_node, list_node); assert(pNode != NULL); memcpy(&(pNode->rep), &rep_msg, sizeof(struct msg_report)); _del2insert(&(pNode->list_node), &rep_list.msg_used); return 0; }
unsigned int __stdcall srv_thread(void * in) { int sock = (int)in; assert(sock > 0); int last_time = time(NULL); int now_time; struct timeval tv; fd_set fd_read; int err; setnonblocking(sock); /*设置套接字非阻塞*/ set_sock_buf(sock, 1024*64);/*设置套接字缓冲区大小*/ tv.tv_sec = 1; tv.tv_usec = 0; while(1){ FD_ZERO(&fd_read); FD_SET((unsigned int)sock, &fd_read); err = select(0, &fd_read, NULL, NULL, &tv); if(err == 0){ /*没数据,超时*/ now_time = time(NULL); if(now_time - last_time > (int)g_option.sp2smg_timeout){ /*链路超时*/ err = BUILD_ERROR(0, E_LINK_TIMEOUT); clean_link(sock, err); return err; } }else if(err > 0){ last_time = time(NULL); if(FD_ISSET(sock, &fd_read)){ err = rcv_msg2rsp(sock); if(err != 0){ clean_link(sock, err); return err; } }else{assert(0);} }else{assert(0);} /*不应该的流程*/ } return 0; }
/** * initLog - 初始化一个日志文件 * * @handle 加载该日志的句柄 * @dir: [in] 写日志文件的目录(非文件) * @needWriteDisk: [in] 是否需要写盘 * @logName: [in] 日志文件名 * @logSuffix [in] 日志文件的后缀名 * * Note: 如果传入的dir是非法的或是不存在的,该函数会返回失败 * * return * 0 成功 * <0 失败 */ int MWriteLog::initLog(char* dir, bool writeDisk, char *logName, char *logSuffix) { SYSTEMTIME sys; char logFileName[256] = {'\0'}; int rc; MLocalSection locSec; InitializeCriticalSection(&m_Lock); if(dir == NULL || logName == NULL || logSuffix == NULL) return -1; locSec.Attch(&m_Lock); m_bNeedWriteDisk = writeDisk; if(m_bNeedWriteDisk == false) return 0; _snprintf(m_cLogPreName, sizeof(m_cLogPreName)-1, logName); _snprintf(m_cLogSuffix, sizeof(m_cLogSuffix)-1, logSuffix); rc = _snprintf(logFileName, sizeof(logFileName)-2, dir); if(logFileName[strlen(logFileName)-1] != '\\') { logFileName[strlen(logFileName)] = '\\'; ++rc; } _snprintf(m_cLogFileDir, sizeof(m_cLogFileDir)-1, logFileName); GetLocalTime(&sys); _snprintf(logFileName+rc, sizeof(logFileName)-rc-1, "%s%04d%02d%02d_%u.%s", m_cLogPreName, sys.wYear,sys.wMonth,sys.wDay, m_handle, m_cLogSuffix); m_iLastDay = sys.wDay; m_pFile = fopen(logFileName, "a"); if(m_pFile == NULL) return BUILD_ERROR(_OSerrno(), 0); return 0; }
/** * trsData - 对数据进行转发 * * @fdRead: [in] 可读套接字集合 * @lhs [in/out] 左操作数 * @rhs [in/out] 右操作数 * * * return * ==0 正常,不需要关闭套接字 * <0 出错(包括有一端套接字关闭) */ int trsData(fd_set &fdRead, SOCK_INFO &lhs, SOCK_INFO &rhs) { int ret; for( unsigned int i = 0; i < fdRead.fd_count; ++i ) { if(fdRead.fd_array[i] == lhs.sock) { ret = _trsData(lhs); if(ret != 0) return ret; }else if(fdRead.fd_array[i] == rhs.sock) { ret = _trsData(rhs); if(ret != 0) return ret; } else { return BUILD_ERROR(0, EABORT); } } return 0; }
/** need ajusted*/ int srvToCli(SOCK_INFO &hs) { unsigned int &leaveParased = hs.engine.leaveParased; HTTP_PARASE_PARAM &httpParam = hs.engine.httpParase; LINE_PARASE_PARAM &headParam = hs.engine.lineParase; int onceRecved = 0; int ret; onceRecved = recv(hs.sock, hs.buffer+leaveParased, sizeof(hs.buffer)-leaveParased, 0); if(onceRecved <= 0) return BUILD_ERROR(_OSerrno(), ESCLOSE); /** do something with hs.HTTP_PARASE_ENG*/ //ret = paraseHttpData(hs,); ret = httpParase(hs.buffer, onceRecved+leaveParased, httpParam, headParam, hs.peerSock); assert(ret <= onceRecved+leaveParased); if(ret < 0) { printf("解析出错\n"); return ret; } if(httpParam.state == HTTP_PARASE_OK) { initState(httpParam, headParam); // ret = sendToPeer(hs.peerSock, hs.buffer, ret);/** can send 0 bi*/ // if(ret != 0) // return BUILD_ERROR(_OSerrno(), ECCLOSE); } leaveParased = onceRecved+leaveParased-ret; memmove(hs.buffer, hs.buffer+ret, leaveParased); return 0; }
// returns either 0 (loaded from cache) // or a reason to rebuild. const char* fetch_cached_build(build_context *context, data *builder, build_db::record * newrecord, const char *handler_name, db::data *input, const char *path, type_handler_i *th) { // Time to hunt for cached object. build_db::record *record = build_db::find(builder::get_build_db(builder), path); if (!record) return "no build record found"; const char *old_builder = build_db::get_builder(record); if (strcmp(old_builder, handler_name)) { RECORD_DEBUG(newrecord, "Old builder=" << old_builder << " current=" << handler_name) return "builders are diffeent"; } build_db::deplist *dlist = build_db::inputdeps_get(builder::get_build_db(builder), path); destroy_deplist destroy(dlist); if (!dlist) { return "no dlist"; } bool gotmatch = false; for (int i=0;;i++) { const char *entrypath = build_db::deplist_path(dlist, i); if (!entrypath) { break; } if (!i) { RECORD_DEBUG(newrecord, "Examining cache...") } const char *signature = build_db::deplist_signature(dlist, i); if (!build_db::deplist_is_external_resource(dlist, i)) { char inputsig[SIG_BUF_SIZE]; if (builder->liveupdates) { strcpy(inputsig, "<broken signature>"); db::signature(input, entrypath, inputsig); } else { if (!inputset::get_object_sig(builder->input_set, entrypath, inputsig)) { if (!inputset::get_object_sig(builder->tmp_input_set, entrypath, inputsig)) { BUILD_ERROR(builder, "Signature missing weirdness [" << entrypath << "]") strcpy(inputsig, "bonkers"); } } } RECORD_DEBUG(newrecord, "=> i: " << entrypath << " old:" << signature << " new " << inputsig) // only care for builder match when the input is going to be built with this builder if (strcmp(inputsig, signature)) { RECORD_DEBUG(newrecord, "!! Detected modification in [" << entrypath << "]") return "input or has been modified"; } gotmatch = true; } else {