📄 hg_comm.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Uwe Steinmann <Uwe.Steinmann@fernuni-hagen.de> | +----------------------------------------------------------------------+ *//* $Id: hg_comm.c,v 1.52.8.5.4.2 2007/01/01 09:46:43 sebastian Exp $ *//* #define HW_DEBUG */#include <stdlib.h>#include "php.h"#include "php_globals.h"#include "SAPI.h"#if HYPERWAVE#include <stdio.h>#include <string.h> #include <sys/types.h>#ifdef PHP_WIN32# include <winsock.h># define EWOULDBLOCK WSAEWOULDBLOCK# define ETIMEDOUT WSAETIMEDOUT# define bcopy memcpy# define bzero(a, b) memset(a, 0, b)#else# include <sys/socket.h># include <netinet/in.h># include <netdb.h># include <unistd.h># include <sys/param.h># include <arpa/inet.h>#endif#include <fcntl.h>#include <errno.h>#include "hg_comm.h"#include "ext/standard/head.h"/* Defining hw_optimize does optimize the send_objectbyidquery() function. Instead of getting the complete return message including the objectrecords with recv_hg_msg(), only the header of the return message is fetched. The object records itself are fetched as they are needed straight from the socket. This method requires less memory and is twice as fast because reading from the net seems to be a bottleneck which has less impact if the processing of the data is done in parallel.*/#define hw_optimize/* Define hw_less_server_stress does reduce the stress on the hw server, by using send_objectbyidquery() instead of send_getobject() multiple times. send_objectbyidquery() gets a bunch of object records with one message. This also reduced the number of lines in the servers log files. Unfortunately this is not faster unless hw_optimize is defined, because getting object records with multiple send_getobject() is already optimized. First all request messages for each object are send and the the answers are read. This gives the server the possibility to answer request already while more request are comming in.*/#define hw_less_server_stressstatic int set_nonblocking(int fd);/* static int set_blocking(int fd); */static int hg_read_exact(int sockfd, char *buf, int size);/* static int hg_read(int sockfd, char *buf, int size); */static int hg_write(int sockfd, char *buf, int size);static int send_hg_msg(int sockfd, hg_msg *msg, int length);static void build_msg_header(hg_msg *msg, int length, int version_msgid, int msg_type);static char *build_msg_int(char *buf, int val);static char *build_msg_str(char *buf, char *str);static int swap(int val);int version = HW_VERSION;/* F_DISTRIBUTED has the effect that all object ids are virtual. This means whenever an object is requested a new id is generated for this session. Wavemaster and Harmony set this flag. How do I know? tcpdump tells a lot if the output is investigated. The bit is also need to allow access on other server through the local server. The hw_mapid() function won't work unless you set F_DISTRIBUTED *//* int version = HW_VERSION | F_DISTRIBUTED; *//* int version = HW_VERSION | F_DISTRIBUTED | F_COMPRESSED; */static int msgid = 1;static int sock_flags = -1;static int non_blocking = 0;static int swap_on = 0;static int rtimeout = 40;static int wtimeout = 40;static int lowerror = 0;/************************************************************************ Function fnInsStr() ** ** Insert string in string at position. The old string will be freed ** with efree!!! The new string is allocated with malloc. ** Parameter: string *str: string in which insstr is to be inserted ** int pos: Position where string is to inserted (0=first) ** string *insstr: string to be inserted ** Return: pointer to new string or NULL. If NULL is returned the ** memory for the old string has not been freed. ************************************************************************/char *fnInsStr(char *str, int pos, char *insstr){ char *newstr, *ptr; if((str == NULL) || (insstr == NULL)) return NULL; if(pos > (int)strlen(str)) return NULL; if(insstr[0] == '\0') return str; if(NULL == (newstr = malloc(strlen(str) + strlen(insstr) + 1))) { lowerror = LE_MALLOC; return NULL; } ptr = newstr; memcpy(newstr, str, pos); ptr += pos; strcpy(ptr, insstr); ptr += strlen(insstr); strcpy(ptr, str+pos); free(str); return newstr;}/************************************************************************ Function fnAddAnchor() ** ** Inserts new anchor into anchor list. ** Parameter: DLIST pList: Anchor list ** int objectID: object ID of Anchor ** int start: start position ** int end: end position ** Return: Pointer to new anchor, NULL if error ************************************************************************/#ifdef newlistANCHOR *fnAddAnchor(zend_llist *pAnchorList, int objectID, int start, int end)#elseANCHOR *fnAddAnchor(DLIST *pAnchorList, int objectID, int start, int end)#endif{ ANCHOR *cur_ptr;#ifdef newlist ANCHOR **ptr; if(NULL == (cur_ptr = (ANCHOR *) emalloc(sizeof(ANCHOR)))) return NULL;#else if((cur_ptr = (ANCHOR *) dlst_newnode(sizeof(ANCHOR))) == NULL) { return NULL; }#endif memset(cur_ptr, 0, sizeof(ANCHOR)); cur_ptr->start = start; cur_ptr->end = end; cur_ptr->id = objectID; cur_ptr->destdocname = NULL; cur_ptr->nameanchor = NULL; cur_ptr->link = NULL; cur_ptr->tagattr = NULL; cur_ptr->htmlattr = NULL; cur_ptr->codebase = NULL; cur_ptr->code = NULL; cur_ptr->keyword = NULL; cur_ptr->fragment = NULL;#ifdef newlist zend_llist_prepend_element(pAnchorList, &cur_ptr); ptr = (ANCHOR **) zend_llist_get_first(pAnchorList);#else dlst_insertafter(pAnchorList, cur_ptr, PHP_DLST_HEAD(pAnchorList));#endif return(cur_ptr);}/************************************************************************ Function fnDeleteAnchor() ** ** Inserts new anchor into anchor list. ** Parameter: ptr: pointer to node ** Return: void ************************************************************************/#ifdef newlistvoid fnDeleteAnchor(void *ptr1)#elsevoid fnDeleteAnchor(ANCHOR *ptr)#endif{#ifdef newlist ANCHOR **ptr2, *ptr; ptr2 = (ANCHOR **) ptr1; ptr = *ptr2;#endif if(ptr->destdocname) efree(ptr->destdocname); if(ptr->nameanchor) efree(ptr->nameanchor); if(ptr->link) efree(ptr->link); if(ptr->tagattr) efree(ptr->tagattr); if(ptr->htmlattr) efree(ptr->htmlattr); if(ptr->codebase) efree(ptr->codebase); if(ptr->code) efree(ptr->code); if(ptr->keyword) efree(ptr->keyword); if(ptr->fragment) efree(ptr->fragment);#ifdef newlist efree(ptr);#else dlst_freenode(ptr);#endif}/************************************************************************ Function fnListAnchor() ** ** Lists all anchors in anchor list. ** Parameter: ptr: pointer to list ** Return: void ************************************************************************/#ifdef newlistvoid fnListAnchor(zend_llist *pAnchorList)#elsevoid fnListAnchor(DLIST *pAnchorList)#endif{#ifdef newlist ANCHOR *cur_ptr, **ptr; ptr = (ANCHOR **) zend_llist_get_last(pAnchorList); if(ptr) cur_ptr = *ptr; while(ptr) { fprintf(stderr, "0x%X->0x%X ", (int) ptr, (int) cur_ptr);#else ANCHOR *cur_ptr; cur_ptr = (ANCHOR *) dlst_last(pAnchorList); while(cur_ptr) { fprintf(stderr, "0x%X ", (int) cur_ptr);#endif fprintf(stderr, "%d, %d, %s, %s, %s, %s %s\n", cur_ptr->start, cur_ptr->end, cur_ptr->tanchor == 1 ? "src" : "dest", cur_ptr->destdocname, cur_ptr->nameanchor, cur_ptr->link, cur_ptr->tagattr);#ifdef newlist ptr = (ANCHOR **) zend_llist_get_prev(pAnchorList); if(ptr) cur_ptr = *ptr;#else cur_ptr = (ANCHOR *) dlst_prev(cur_ptr);#endif }}/************************************************************************ Function fnCmpAnchors() ** ** Compares to Anchors by its start position ** Parameter: ANCHOR a1: First Anchor ** ANCHOR a2: Second Anchor ** Return: As strcmp ************************************************************************/#ifdef newlistint fnCmpAnchors(const void *e1, const void *e2 TSRMLS_DC){ ANCHOR *a1, **aa1, *a2, **aa2; zend_llist_element **ee1, **ee2; ee1 = (zend_llist_element **) e1; ee2 = (zend_llist_element **) e2; aa1 = (ANCHOR **) (*ee1)->data; aa2 = (ANCHOR **) (*ee2)->data; a1 = *aa1; a2 = *aa2;#elseint fnCmpAnchors(ANCHOR *a1, ANCHOR *a2 TSRMLS_DC){#endif if(a1->start < a2->start) return -1; if(a1->start == a2->start) { /* It's importent to check this case as well, because a link with a bigger end has to be inserted first. */ if(a1->end < a2->end) return -1; /* If both start and end are equal (yes, it is possible) we will Src Anchor before a Dest anchor. There has been a case where an IMG was surrounded by a NAME which was surrounded by a HREF. In such a case the HREF doesn't work. */ if(a1->end == a2->end) { if(a1->tanchor > a2->tanchor) return -1; } } return 1;}/************************************************************************ Function fnCreateAnchorList() ** Uses either docofanchorrec or reldestrec to create a list of anchors ** depending on anchormode ** ** Returns a list of Anchors converted from an object record ** Parameter: int objectID: the object for which the list is created ** char **anchors: object records of anchors ** char **docofanchorrec: Name of destination absolut ** char **reldestrec: Name of destination relativ to current ** object ** int ancount: number of anchors ** int anchormode: 0 = use absolut dest, else rel. dest ** Return: List of Anchors, NULL if error ************************************************************************/#ifdef newlistzend_llist *fnCreateAnchorList(hw_objectID objID, char **anchors, char **docofanchorrec, char **reldestrec, int ancount, int anchormode)#elseDLIST *fnCreateAnchorList(hw_objectID objID, char **anchors, char **docofanchorrec, char **reldestrec, int ancount, int anchormode)#endif{ int start, end, i, destid, anchordestid, objectID; ANCHOR *cur_ptr = NULL;#ifdef newlist zend_llist *pAnchorList; pAnchorList = (zend_llist *) emalloc(sizeof(zend_llist)); zend_llist_init(pAnchorList, sizeof(char *), fnDeleteAnchor, 0);#else DLIST *pAnchorList = dlst_init();#endif for(i=ancount-1; i>=0; i--) { char *object = NULL; char *docofanchorptr = NULL; char *reldestptr = NULL; char *str, *str1, link[200]; if(NULL != anchors[i]) { object = anchors[i]; docofanchorptr = docofanchorrec[i]; if(reldestrec) /* FIXME reldestrec may only be NULL if anchormode != 0 */ reldestptr = reldestrec[i]; /* Determine Position. Doesn't matter if Src or Dest The Position field should always be there. Though there are case in which the position has no meaning, e.g. if a document is annotated and the annotation text doesn't contain a link of type annotation, In such a case the Position has the value 'invisible' */ str = strstr(object, "Position"); str += 9; if(((int) str != 9) && (0 != strncmp(str, "invisible", 9))) { sscanf(str, "0x%X 0x%X", &start, &end); /* Determine ObjectID */ objectID = 0; if(NULL != (str = strstr(object, "ObjectID"))) { str += 9; sscanf(str, "0x%X", &objectID); } cur_ptr = fnAddAnchor(pAnchorList, objectID, start, end); /* Determine Type of Anchor */ str = strstr(object, "TAnchor"); str += 8; if(*str == 'S') { char destdocname[200]; char nameanchor[200]; cur_ptr->tanchor = 1; cur_ptr->destdocname = NULL; if(NULL != (str = strstr(object, "Dest"))) { char *tempptr; /* No need to care about the value of Dest, because we take the info from docofanchorptr. Since the anchor has a destination there are two possibilities. 1. The destination is an anchor or 2. or the destination is a document already. In both cases docofanchorptr has the proper info because GETDOCBYANCHOR is such a nice message. */ switch(anchormode) { case 0: tempptr = docofanchorptr; break; default: tempptr = reldestptr; } if(NULL != tempptr) { destid = 0; if(NULL != (str = strstr(tempptr, "ObjectID="))) { str += 9; sscanf(str, "0x%X", &destid); } /* This is basically for NAME tags. There is no need to add the destname if it is the document itself. *//* if(destid == objID) { cur_ptr->destdocname = NULL; } else { */ /* It's always nice to deal with names, so let's first check for a name. If there is none we take the ObjectID. */ if(NULL != (str = strstr(tempptr, "Name="))) { str += 5; } else if(NULL != (str = strstr(tempptr, "ObjectID="))) { str += 9; } if(sscanf(str, "%s\n", destdocname)) { cur_ptr->destdocname = estrdup(destdocname); }/* } */ } } /* Get the Id of the anchor destination and the document id that belongs to that anchor. We need that soon in order to determine if the anchor points to a document or a dest anchor in a document. */ anchordestid = 0; if(NULL != (str = strstr(object, "Dest="))) { str += 5; sscanf(str, "0x%X", &anchordestid); } /* if anchordestid != destid then the destination is an anchor in a document whose name (objectID) is already in destdocname. We will have to extend the link by '#...' */ cur_ptr->nameanchor = NULL; if(anchordestid != destid) { if(NULL != (str = strstr(object, "Dest="))) { str += 5; if(sscanf(str, "%s\n", nameanchor)) cur_ptr->nameanchor = estrdup(nameanchor); } } if(!cur_ptr->destdocname) { cur_ptr->link = NULL; if(NULL != (str = strstr(object, "Hint=URL:"))) { str += 9; if(sscanf(str, "%s\n", link)) cur_ptr->link = estrdup(link); } else if(NULL != (str = strstr(object, "Hint="))) { str += 5; if(sscanf(str, "%s\n", link)) cur_ptr->link = estrdup(link); } } cur_ptr->fragment = NULL; if(NULL != (str = strstr(object, "Fragment="))) { str += 9; if(sscanf(str, "%s\n", link)) cur_ptr->fragment = estrdup(link); } { char *htmlattr, *str2; int offset; str1 = object; htmlattr = emalloc(strlen(object)); /* alloc mem big enough for htmlattr */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -