1 Star 0 Fork 0

nhky / swoole-src

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
swoole_server.cc 141.67 KB
一键复制 编辑 原始数据 按行查看 历史
韩天峰 提交于 2020-09-17 11:13 . Optimize code (#3671)
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache 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.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "php_swoole_server.h"
#include "php_swoole_process.h"
#include "swoole_msg_queue.h"
#include "ext/standard/php_var.h"
#include "zend_smart_str.h"
#ifdef SW_HAVE_ZLIB
#include <zlib.h>
#endif
#include <unordered_map>
#include <list>
#include <vector>
using namespace swoole;
struct TaskCo;
struct ServerProperty {
std::vector<zval *> ports;
std::vector<zval *> user_processes;
php_swoole_server_port_property *primary_port;
zend_fcall_info_cache *callbacks[PHP_SWOOLE_SERVER_CALLBACK_NUM];
std::unordered_map<int, zend_fcall_info_cache> task_callbacks;
std::unordered_map<int, TaskCo *> task_coroutine_map;
std::unordered_map<int, std::list<FutureTask *> *> send_coroutine_map;
};
struct ServerObject {
Server *serv;
ServerProperty *property;
zend_object std;
};
struct ConnectionIterator {
int current_fd;
uint32_t session_id;
Server *serv;
ListenPort *port;
int index;
};
struct TaskCo {
FutureTask context;
int *list;
uint32_t count;
zval *result;
TimerNode *timer;
ServerObject *server_object;
};
struct ServerEvent {
enum php_swoole_server_callback_type type;
std::string name;
ServerEvent(enum php_swoole_server_callback_type type, std::string &&name) : type(type), name(name) {}
};
// clang-format off
static std::unordered_map<std::string, ServerEvent> server_event_map({
{ "start", ServerEvent(SW_SERVER_CB_onStart, "Start") },
{ "shutdown", ServerEvent(SW_SERVER_CB_onShutdown, "Shutdown") },
{ "workerstart", ServerEvent(SW_SERVER_CB_onWorkerStart, "WorkerStart") },
{ "workerstop", ServerEvent(SW_SERVER_CB_onWorkerStop, "WorkerStop") },
{ "beforereload", ServerEvent(SW_SERVER_CB_onBeforeReload, "BeforeReload") },
{ "afterreload", ServerEvent(SW_SERVER_CB_onAfterReload, "AfterReload") },
{ "task", ServerEvent(SW_SERVER_CB_onTask, "Task") },
{ "finish", ServerEvent(SW_SERVER_CB_onFinish, "Finish") },
{ "workerexit", ServerEvent(SW_SERVER_CB_onWorkerExit, "WorkerExit") },
{ "workererror", ServerEvent(SW_SERVER_CB_onWorkerError, "WorkerError") },
{ "managerstart", ServerEvent(SW_SERVER_CB_onManagerStart, "ManagerStart") },
{ "managerstop", ServerEvent(SW_SERVER_CB_onManagerStop, "ManagerStop") },
{ "pipemessage", ServerEvent(SW_SERVER_CB_onPipeMessage, "PipeMessage") },
});
// clang-format on
static int php_swoole_task_finish(Server *serv, zval *zdata, EventData *current_task);
static void php_swoole_onPipeMessage(Server *serv, EventData *req);
static void php_swoole_onStart(Server *);
static void php_swoole_onShutdown(Server *);
static void php_swoole_onWorkerStart(Server *, int worker_id);
static void php_swoole_onBeforeReload(Server *serv);
static void php_swoole_onAfterReload(Server *serv);
static void php_swoole_onWorkerStop(Server *, int worker_id);
static void php_swoole_onWorkerExit(Server *serv, int worker_id);
static void php_swoole_onUserWorkerStart(Server *serv, Worker *worker);
static int php_swoole_onTask(Server *, EventData *task);
static int php_swoole_onFinish(Server *, EventData *task);
static void php_swoole_onWorkerError(Server *serv, int worker_id, pid_t worker_pid, int exit_code, int signo);
static void php_swoole_onManagerStart(Server *serv);
static void php_swoole_onManagerStop(Server *serv);
static void php_swoole_onSendTimeout(swTimer *timer, TimerNode *tnode);
static enum swReturn_code php_swoole_server_send_resume(Server *serv, FutureTask *context, int fd);
static void php_swoole_task_onTimeout(swTimer *timer, TimerNode *tnode);
static int php_swoole_server_dispatch_func(Server *serv, Connection *conn, SendData *data);
static zval *php_swoole_server_add_port(ServerObject *server_object, ListenPort *port);
/**
* Worker Buffer
*/
static void **php_swoole_server_worker_create_buffers(Server *serv, uint buffer_num);
static void php_swoole_server_worker_free_buffers(Server *serv, uint buffer_num, void **buffers);
static void *php_swoole_server_worker_get_buffer(Server *serv, DataHead *info);
static size_t php_swoole_server_worker_get_buffer_len(Server *serv, DataHead *info);
static void php_swoole_server_worker_add_buffer_len(Server *serv, DataHead *info, size_t len);
static void php_swoole_server_worker_move_buffer(Server *serv, PipeBuffer *buffer);
static size_t php_swoole_server_worker_get_packet(Server *serv, EventData *req, char **data_ptr);
static inline zend_bool php_swoole_server_isset_callback(ServerObject *server_object,
ListenPort *port,
int event_type) {
php_swoole_server_port_property *property = (php_swoole_server_port_property *) port->ptr;
if (property->callbacks[event_type] || server_object->property->primary_port->callbacks[event_type]) {
return true;
} else {
return false;
}
}
static sw_inline zend_bool is_enable_coroutine(Server *serv) {
if (swIsTaskWorker()) {
return serv->task_enable_coroutine;
} else {
return serv->enable_coroutine;
}
}
void php_swoole_server_rshutdown() {
if (!sw_server()) {
return;
}
Server *serv = sw_server();
serv->drain_worker_pipe();
if (serv->is_started() && !swIsUserWorker()) {
if (PG(last_error_message)) {
switch (PG(last_error_type)) {
case E_ERROR:
case E_CORE_ERROR:
case E_USER_ERROR:
case E_COMPILE_ERROR:
swoole_error_log(SW_LOG_ERROR,
SW_ERROR_PHP_FATAL_ERROR,
"Fatal error: %s in %s on line %d",
PG(last_error_message),
PG(last_error_file) ? PG(last_error_file) : "-",
PG(last_error_lineno));
break;
default:
break;
}
} else {
swoole_error_log(
SW_LOG_NOTICE, SW_ERROR_SERVER_WORKER_TERMINATED, "worker process is terminated by exit()/die()");
}
}
}
zend_class_entry *swoole_server_ce;
zend_object_handlers swoole_server_handlers;
zend_class_entry *swoole_connection_iterator_ce;
static zend_object_handlers swoole_connection_iterator_handlers;
static zend_class_entry *swoole_server_task_ce;
static zend_object_handlers swoole_server_task_handlers;
static sw_inline ServerObject *server_fetch_object(zend_object *obj) {
return (ServerObject *) ((char *) obj - swoole_server_handlers.offset);
}
static sw_inline Server *server_get_ptr(zval *zobject) {
return server_fetch_object(Z_OBJ_P(zobject))->serv;
}
Server *php_swoole_server_get_and_check_server(zval *zobject) {
Server *serv = server_get_ptr(zobject);
if (UNEXPECTED(!serv)) {
php_swoole_fatal_error(E_ERROR, "Invaild instance of %s", SW_Z_OBJCE_NAME_VAL_P(zobject));
}
return serv;
}
static sw_inline void server_set_ptr(zval *zobject, Server *serv) {
server_fetch_object(Z_OBJ_P(zobject))->serv = serv;
}
static void server_free_object(zend_object *object) {
ServerObject *server_object = server_fetch_object(object);
ServerProperty *property = server_object->property;
Server *serv = server_object->serv;
if (serv) {
if (serv->private_data_3) {
sw_zend_fci_cache_discard((zend_fcall_info_cache *) serv->private_data_3);
efree(serv->private_data_3);
}
if (serv->ptr2) {
efree(serv->ptr2);
}
for (int i = 0; i < PHP_SWOOLE_SERVER_CALLBACK_NUM; i++) {
zend_fcall_info_cache *fci_cache = property->callbacks[i];
if (fci_cache) {
efree(fci_cache);
property->callbacks[i] = nullptr;
}
}
for (auto i = property->user_processes.begin(); i != property->user_processes.end(); i++) {
sw_zval_free(*i);
}
for (auto zport : property->ports) {
php_swoole_server_port_deref(Z_OBJ_P(zport));
efree(zport);
}
server_object->serv = nullptr;
}
delete property;
zend_object_std_dtor(object);
if (serv && swIsMaster()) {
delete serv;
}
}
static zend_object *server_create_object(zend_class_entry *ce) {
ServerObject *server_object = (ServerObject *) zend_object_alloc(sizeof(ServerObject), ce);
zend_object_std_init(&server_object->std, ce);
object_properties_init(&server_object->std, ce);
server_object->std.handlers = &swoole_server_handlers;
server_object->property = new ServerProperty();
return &server_object->std;
}
struct ConnectionIteratorObject {
ConnectionIterator iterator;
zend_object std;
};
static sw_inline ConnectionIteratorObject *php_swoole_connection_iterator_fetch_object(zend_object *obj) {
return (ConnectionIteratorObject *) ((char *) obj - swoole_connection_iterator_handlers.offset);
}
static sw_inline ConnectionIterator *php_swoole_connection_iterator_get_ptr(zval *zobject) {
return &php_swoole_connection_iterator_fetch_object(Z_OBJ_P(zobject))->iterator;
}
ConnectionIterator *php_swoole_connection_iterator_get_and_check_ptr(zval *zobject) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_ptr(zobject);
if (UNEXPECTED(!iterator->serv)) {
php_swoole_fatal_error(E_ERROR, "Invaild instance of %s", SW_Z_OBJCE_NAME_VAL_P(zobject));
}
return iterator;
}
static void php_swoole_connection_iterator_free_object(zend_object *object) {
zend_object_std_dtor(object);
}
static zend_object *php_swoole_connection_iterator_create_object(zend_class_entry *ce) {
ConnectionIteratorObject *connection =
(ConnectionIteratorObject *) zend_object_alloc(sizeof(ConnectionIteratorObject), ce);
zend_object_std_init(&connection->std, ce);
object_properties_init(&connection->std, ce);
connection->std.handlers = &swoole_connection_iterator_handlers;
return &connection->std;
}
struct ServerTaskObject {
Server *serv;
DataHead info;
zend_object std;
};
static sw_inline ServerTaskObject *php_swoole_server_task_fetch_object(zend_object *obj) {
return (ServerTaskObject *) ((char *) obj - swoole_server_task_handlers.offset);
}
static sw_inline Server *php_swoole_server_task_get_server(zval *zobject) {
Server *serv = php_swoole_server_task_fetch_object(Z_OBJ_P(zobject))->serv;
if (!serv) {
php_swoole_fatal_error(E_ERROR, "Invaild instance of %s", SW_Z_OBJCE_NAME_VAL_P(zobject));
}
return serv;
}
static sw_inline void php_swoole_server_task_set_server(zval *zobject, Server *serv) {
php_swoole_server_task_fetch_object(Z_OBJ_P(zobject))->serv = serv;
}
static sw_inline DataHead *php_swoole_server_task_get_info(zval *zobject) {
ServerTaskObject *task = php_swoole_server_task_fetch_object(Z_OBJ_P(zobject));
if (!task->serv) {
php_swoole_fatal_error(E_ERROR, "Invaild instance of %s", SW_Z_OBJCE_NAME_VAL_P(zobject));
}
return &task->info;
}
static sw_inline void php_swoole_server_task_set_info(zval *zobject, DataHead *info) {
php_swoole_server_task_fetch_object(Z_OBJ_P(zobject))->info = *info;
}
static void php_swoole_server_task_free_object(zend_object *object) {
zend_object_std_dtor(object);
}
static zend_object *php_swoole_server_task_create_object(zend_class_entry *ce) {
ServerTaskObject *server_task = (ServerTaskObject *) zend_object_alloc(sizeof(ServerTaskObject), ce);
zend_object_std_init(&server_task->std, ce);
object_properties_init(&server_task->std, ce);
server_task->std.handlers = &swoole_server_task_handlers;
return &server_task->std;
}
// arginfo server
// clang-format off
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server__construct, 0, 0, 1)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, mode)
ZEND_ARG_INFO(0, sock_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_set, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, settings, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_send, 0, 0, 2)
ZEND_ARG_INFO(0, fd)
ZEND_ARG_INFO(0, send_data)
ZEND_ARG_INFO(0, server_socket)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_sendwait, 0, 0, 2)
ZEND_ARG_INFO(0, conn_fd)
ZEND_ARG_INFO(0, send_data)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_exists, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_protect, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_ARG_INFO(0, is_protected)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_sendto, 0, 0, 3)
ZEND_ARG_INFO(0, ip)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, send_data)
ZEND_ARG_INFO(0, server_socket)
ZEND_END_ARG_INFO()
//for object style
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_sendfile, 0, 0, 2)
ZEND_ARG_INFO(0, conn_fd)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_close, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_ARG_INFO(0, reset)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_pause, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_resume, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_END_ARG_INFO()
#ifdef SWOOLE_SOCKETS_SUPPORT
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_getSocket, 0, 0, 0)
ZEND_ARG_INFO(0, port)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_on, 0, 0, 2)
ZEND_ARG_INFO(0, event_name)
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_getCallback, 0, 0, 1)
ZEND_ARG_INFO(0, event_name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_listen, 0, 0, 3)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, sock_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_task, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, worker_id)
ZEND_ARG_CALLABLE_INFO(0, finish_callback, 1)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_taskwait, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, worker_id)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_taskCo, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, tasks, 0)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_taskWaitMulti, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, tasks, 0)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_finish, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_task_pack, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_reload, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_heartbeat, 0, 0, 1)
ZEND_ARG_INFO(0, reactor_id)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_stop, 0, 0, 0)
ZEND_ARG_INFO(0, worker_id)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_bind, 0, 0, 2)
ZEND_ARG_INFO(0, fd)
ZEND_ARG_INFO(0, uid)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_sendMessage, 0, 0, 2)
ZEND_ARG_INFO(0, message)
ZEND_ARG_INFO(0, dst_worker_id)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_addProcess, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, process, swoole_process, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_getClientInfo, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_ARG_INFO(0, reactor_id)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_getWorkerStatus, 0, 0, 0)
ZEND_ARG_INFO(0, worker_id)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_getClientList, 0, 0, 1)
ZEND_ARG_INFO(0, start_fd)
ZEND_ARG_INFO(0, find_count)
ZEND_END_ARG_INFO()
//arginfo connection_iterator
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_connection_iterator_offsetExists, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_connection_iterator_offsetGet, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_connection_iterator_offsetUnset, 0, 0, 1)
ZEND_ARG_INFO(0, fd)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_connection_iterator_offsetSet, 0, 0, 2)
ZEND_ARG_INFO(0, fd)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
//arginfo end
// clang-format on
SW_EXTERN_C_BEGIN
static PHP_METHOD(swoole_server, __construct);
static PHP_METHOD(swoole_server, __destruct);
static PHP_METHOD(swoole_server, set);
static PHP_METHOD(swoole_server, on);
static PHP_METHOD(swoole_server, getCallback);
static PHP_METHOD(swoole_server, listen);
static PHP_METHOD(swoole_server, sendMessage);
static PHP_METHOD(swoole_server, addProcess);
static PHP_METHOD(swoole_server, start);
static PHP_METHOD(swoole_server, stop);
static PHP_METHOD(swoole_server, send);
static PHP_METHOD(swoole_server, sendfile);
static PHP_METHOD(swoole_server, stats);
static PHP_METHOD(swoole_server, bind);
static PHP_METHOD(swoole_server, sendto);
static PHP_METHOD(swoole_server, sendwait);
static PHP_METHOD(swoole_server, exists);
static PHP_METHOD(swoole_server, protect);
static PHP_METHOD(swoole_server, close);
static PHP_METHOD(swoole_server, pause);
static PHP_METHOD(swoole_server, resume);
static PHP_METHOD(swoole_server, task);
static PHP_METHOD(swoole_server, taskwait);
static PHP_METHOD(swoole_server, taskWaitMulti);
static PHP_METHOD(swoole_server, taskCo);
static PHP_METHOD(swoole_server, finish);
static PHP_METHOD(swoole_server, reload);
static PHP_METHOD(swoole_server, shutdown);
static PHP_METHOD(swoole_server, heartbeat);
static PHP_METHOD(swoole_server, getClientList);
static PHP_METHOD(swoole_server, getClientInfo);
static PHP_METHOD(swoole_server, getWorkerId);
static PHP_METHOD(swoole_server, getWorkerPid);
static PHP_METHOD(swoole_server, getWorkerStatus);
static PHP_METHOD(swoole_server, getManagerPid);
static PHP_METHOD(swoole_server, getMasterPid);
#ifdef SW_BUFFER_RECV_TIME
static PHP_METHOD(swoole_server, getReceivedTime);
#endif
#ifdef SWOOLE_SOCKETS_SUPPORT
static PHP_METHOD(swoole_server, getSocket);
#endif
/**
* Server\Connection
*/
static PHP_METHOD(swoole_connection_iterator, count);
static PHP_METHOD(swoole_connection_iterator, rewind);
static PHP_METHOD(swoole_connection_iterator, next);
static PHP_METHOD(swoole_connection_iterator, current);
static PHP_METHOD(swoole_connection_iterator, key);
static PHP_METHOD(swoole_connection_iterator, valid);
static PHP_METHOD(swoole_connection_iterator, offsetExists);
static PHP_METHOD(swoole_connection_iterator, offsetGet);
static PHP_METHOD(swoole_connection_iterator, offsetSet);
static PHP_METHOD(swoole_connection_iterator, offsetUnset);
static PHP_METHOD(swoole_connection_iterator, __construct);
static PHP_METHOD(swoole_connection_iterator, __destruct);
/**
* Server\Task
*/
static PHP_METHOD(swoole_server_task, finish);
static PHP_METHOD(swoole_server_task, pack);
SW_EXTERN_C_END
// clang-format off
static zend_function_entry swoole_server_methods[] = {
PHP_ME(swoole_server, __construct, arginfo_swoole_server__construct, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, __destruct, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, listen, arginfo_swoole_server_listen, ZEND_ACC_PUBLIC)
PHP_MALIAS(swoole_server, addlistener, listen, arginfo_swoole_server_listen, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, on, arginfo_swoole_server_on, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getCallback, arginfo_swoole_server_getCallback, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, set, arginfo_swoole_server_set, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, start, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, send, arginfo_swoole_server_send, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, sendto, arginfo_swoole_server_sendto, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, sendwait, arginfo_swoole_server_sendwait, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, exists, arginfo_swoole_server_exists, ZEND_ACC_PUBLIC)
PHP_MALIAS(swoole_server, exist, exists, arginfo_swoole_server_exists, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, protect, arginfo_swoole_server_protect, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, sendfile, arginfo_swoole_server_sendfile, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, close, arginfo_swoole_server_close, ZEND_ACC_PUBLIC)
PHP_MALIAS(swoole_server, confirm, resume, arginfo_swoole_server_resume, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, pause, arginfo_swoole_server_pause, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, resume, arginfo_swoole_server_resume, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, task, arginfo_swoole_server_task, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, taskwait, arginfo_swoole_server_taskwait, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, taskWaitMulti, arginfo_swoole_server_taskWaitMulti, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, taskCo, arginfo_swoole_server_taskCo, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, finish, arginfo_swoole_server_finish, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, reload, arginfo_swoole_server_reload, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, shutdown, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, stop, arginfo_swoole_server_stop, ZEND_ACC_PUBLIC)
PHP_FALIAS(getLastError, swoole_last_error, arginfo_swoole_void)
PHP_ME(swoole_server, heartbeat, arginfo_swoole_server_heartbeat, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getClientInfo, arginfo_swoole_server_getClientInfo, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getClientList, arginfo_swoole_server_getClientList, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getWorkerId, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getWorkerPid, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getWorkerStatus, arginfo_swoole_server_getWorkerStatus, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getManagerPid, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, getMasterPid, arginfo_swoole_void, ZEND_ACC_PUBLIC)
//psr-0 style
PHP_MALIAS(swoole_server, connection_info, getClientInfo, arginfo_swoole_server_getClientInfo, ZEND_ACC_PUBLIC)
PHP_MALIAS(swoole_server, connection_list, getClientList, arginfo_swoole_server_getClientList, ZEND_ACC_PUBLIC)
//process
PHP_ME(swoole_server, sendMessage, arginfo_swoole_server_sendMessage, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, addProcess, arginfo_swoole_server_addProcess, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server, stats, arginfo_swoole_void, ZEND_ACC_PUBLIC)
#ifdef SWOOLE_SOCKETS_SUPPORT
PHP_ME(swoole_server, getSocket, arginfo_swoole_server_getSocket, ZEND_ACC_PUBLIC)
#endif
#ifdef SW_BUFFER_RECV_TIME
PHP_ME(swoole_server, getReceivedTime, arginfo_swoole_void, ZEND_ACC_PUBLIC)
#endif
PHP_ME(swoole_server, bind, arginfo_swoole_server_bind, ZEND_ACC_PUBLIC)
{nullptr, nullptr, nullptr}
};
static const zend_function_entry swoole_connection_iterator_methods[] =
{
PHP_ME(swoole_connection_iterator, __construct, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, __destruct, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, rewind, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, next, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, current, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, key, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, valid, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, count, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, offsetExists, arginfo_swoole_connection_iterator_offsetExists, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, offsetGet, arginfo_swoole_connection_iterator_offsetGet, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, offsetSet, arginfo_swoole_connection_iterator_offsetSet, ZEND_ACC_PUBLIC)
PHP_ME(swoole_connection_iterator, offsetUnset, arginfo_swoole_connection_iterator_offsetUnset, ZEND_ACC_PUBLIC)
PHP_FE_END
};
static const zend_function_entry swoole_server_task_methods[] =
{
PHP_ME(swoole_server_task, finish, arginfo_swoole_server_finish, ZEND_ACC_PUBLIC)
PHP_ME(swoole_server_task, pack, arginfo_swoole_server_task_pack, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END
};
// clang-format on
void php_swoole_server_minit(int module_number) {
SW_INIT_CLASS_ENTRY(swoole_server, "Swoole\\Server", "swoole_server", nullptr, swoole_server_methods);
SW_SET_CLASS_SERIALIZABLE(swoole_server, zend_class_serialize_deny, zend_class_unserialize_deny);
SW_SET_CLASS_CLONEABLE(swoole_server, sw_zend_class_clone_deny);
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_server, sw_zend_class_unset_property_deny);
SW_SET_CLASS_CUSTOM_OBJECT(swoole_server, server_create_object, server_free_object, ServerObject, std);
SW_FUNCTION_ALIAS(&swoole_timer_ce->function_table, "after", &swoole_server_ce->function_table, "after");
SW_FUNCTION_ALIAS(&swoole_timer_ce->function_table, "tick", &swoole_server_ce->function_table, "tick");
SW_FUNCTION_ALIAS(&swoole_timer_ce->function_table, "clear", &swoole_server_ce->function_table, "clearTimer");
SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "defer", &swoole_server_ce->function_table, "defer");
SW_INIT_CLASS_ENTRY(
swoole_server_task, "Swoole\\Server\\Task", "swoole_server_task", nullptr, swoole_server_task_methods);
swoole_server_task_ce->ce_flags |= ZEND_ACC_FINAL;
SW_SET_CLASS_SERIALIZABLE(swoole_server_task, zend_class_serialize_deny, zend_class_unserialize_deny);
SW_SET_CLASS_CLONEABLE(swoole_server_task, sw_zend_class_clone_deny);
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_server_task, sw_zend_class_unset_property_deny);
SW_SET_CLASS_CUSTOM_OBJECT(swoole_server_task,
php_swoole_server_task_create_object,
php_swoole_server_task_free_object,
ServerTaskObject,
std);
SW_INIT_CLASS_ENTRY(swoole_connection_iterator,
"Swoole\\Connection\\Iterator",
"swoole_connection_iterator",
nullptr,
swoole_connection_iterator_methods);
SW_SET_CLASS_SERIALIZABLE(swoole_connection_iterator, zend_class_serialize_deny, zend_class_unserialize_deny);
SW_SET_CLASS_CLONEABLE(swoole_connection_iterator, sw_zend_class_clone_deny);
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_connection_iterator, sw_zend_class_unset_property_deny);
SW_SET_CLASS_CUSTOM_OBJECT(swoole_connection_iterator,
php_swoole_connection_iterator_create_object,
php_swoole_connection_iterator_free_object,
ConnectionIteratorObject,
std);
zend_class_implements(swoole_connection_iterator_ce, 2, zend_ce_iterator, zend_ce_arrayaccess);
#ifdef SW_HAVE_COUNTABLE
zend_class_implements(swoole_connection_iterator_ce, 1, zend_ce_countable);
#endif
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onStart"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onShutdown"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onWorkerStart"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onWorkerStop"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onBeforeReload"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onAfterReload"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onWorkerExit"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onWorkerError"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onTask"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onFinish"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onManagerStart"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onManagerStop"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("onPipeMessage"), ZEND_ACC_PRIVATE);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("setting"), ZEND_ACC_PUBLIC);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("connections"), ZEND_ACC_PUBLIC);
zend_declare_property_string(swoole_server_ce, ZEND_STRL("host"), "", ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_ce, ZEND_STRL("port"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_ce, ZEND_STRL("type"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_ce, ZEND_STRL("mode"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("ports"), ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_ce, ZEND_STRL("master_pid"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_ce, ZEND_STRL("manager_pid"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_ce, ZEND_STRL("worker_id"), -1, ZEND_ACC_PUBLIC);
zend_declare_property_bool(swoole_server_ce, ZEND_STRL("taskworker"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_ce, ZEND_STRL("worker_pid"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_null(swoole_server_task_ce, ZEND_STRL("data"), ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_task_ce, ZEND_STRL("id"), -1, ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_task_ce, ZEND_STRL("worker_id"), -1, ZEND_ACC_PUBLIC);
zend_declare_property_long(swoole_server_task_ce, ZEND_STRL("flags"), 0, ZEND_ACC_PUBLIC);
SW_REGISTER_LONG_CONSTANT("SWOOLE_DISPATCH_RESULT_DISCARD_PACKET", SW_DISPATCH_RESULT_DISCARD_PACKET);
SW_REGISTER_LONG_CONSTANT("SWOOLE_DISPATCH_RESULT_CLOSE_CONNECTION", SW_DISPATCH_RESULT_CLOSE_CONNECTION);
SW_REGISTER_LONG_CONSTANT("SWOOLE_DISPATCH_RESULT_USERFUNC_FALLBACK", SW_DISPATCH_RESULT_USERFUNC_FALLBACK);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_TMPFILE", SW_TASK_TMPFILE);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_SERIALIZE", SW_TASK_SERIALIZE);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_NONBLOCK", SW_TASK_NONBLOCK);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_CALLBACK", SW_TASK_CALLBACK);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_WAITALL", SW_TASK_WAITALL);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_COROUTINE", SW_TASK_COROUTINE);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_PEEK", SW_TASK_PEEK);
SW_REGISTER_LONG_CONSTANT("SWOOLE_TASK_NOREPLY", SW_TASK_NOREPLY);
SW_REGISTER_LONG_CONSTANT("SWOOLE_WORKER_BUSY", SW_WORKER_BUSY);
SW_REGISTER_LONG_CONSTANT("SWOOLE_WORKER_IDLE", SW_WORKER_IDLE);
}
zend_fcall_info_cache *php_swoole_server_get_fci_cache(Server *serv, int server_fd, int event_type) {
ListenPort *port = serv->get_port_by_server_fd(server_fd);
php_swoole_server_port_property *property;
zend_fcall_info_cache *fci_cache;
ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->ptr2));
if (sw_unlikely(!port)) {
return nullptr;
}
if ((property = (php_swoole_server_port_property *) port->ptr) && (fci_cache = property->caches[event_type])) {
return fci_cache;
} else {
return server_object->property->primary_port->caches[event_type];
}
}
int php_swoole_create_dir(const char *path, size_t length) {
if (access(path, F_OK) == 0) {
return 0;
}
#if 1
return php_stream_mkdir(path, 0777, PHP_STREAM_MKDIR_RECURSIVE | REPORT_ERRORS, nullptr) ? 0 : -1;
#else
int startpath;
int endpath;
int i = 0;
int pathlen = length;
char curpath[128] = {};
if ('/' != path[0]) {
if (getcwd(curpath, sizeof(curpath)) == nullptr) {
php_swoole_sys_error(E_WARNING, "getcwd() failed");
return -1;
}
strcat(curpath, "/");
startpath = strlen(curpath);
strcat(curpath, path);
if (path[pathlen] != '/') {
strcat(curpath, "/");
}
endpath = strlen(curpath);
} else {
strcpy(curpath, path);
if (path[pathlen] != '/') {
strcat(curpath, "/");
}
startpath = 1;
endpath = strlen(curpath);
}
for (i = startpath; i < endpath; i++) {
if ('/' == curpath[i]) {
curpath[i] = '\0';
if (access(curpath, F_OK) != 0) {
if (mkdir(curpath, 0755) == -1) {
php_swoole_sys_error(E_WARNING, "mkdir(%s, 0755)", path);
return -1;
}
}
curpath[i] = '/';
}
}
return 0;
#endif
}
int php_swoole_task_pack(EventData *task, zval *zdata) {
smart_str serialized_data = {};
php_serialize_data_t var_hash;
task->info.type = SW_SERVER_EVENT_TASK;
// field fd save task_id
task->info.fd = SwooleG.task_id++;
if (sw_unlikely(SwooleG.task_id >= INT_MAX)) {
SwooleG.task_id = 0;
}
// field reactor_id save the worker_id
task->info.reactor_id = SwooleG.process_id;
swTask_type(task) = 0;
char *task_data_str;
int task_data_len = 0;
// need serialize
if (Z_TYPE_P(zdata) != IS_STRING) {
// serialize
swTask_type(task) |= SW_TASK_SERIALIZE;
PHP_VAR_SERIALIZE_INIT(var_hash);
php_var_serialize(&serialized_data, zdata, &var_hash);
PHP_VAR_SERIALIZE_DESTROY(var_hash);
if (!serialized_data.s) {
return -1;
}
task_data_str = ZSTR_VAL(serialized_data.s);
task_data_len = ZSTR_LEN(serialized_data.s);
} else {
task_data_str = Z_STRVAL_P(zdata);
task_data_len = Z_STRLEN_P(zdata);
}
if (!task->pack(task_data_str, task_data_len)) {
php_swoole_fatal_error(E_WARNING, "large task pack failed");
task->info.fd = SW_ERR;
task->info.len = 0;
}
smart_str_free(&serialized_data);
return task->info.fd;
}
void php_swoole_get_recv_data(Server *serv, zval *zdata, swRecvData *req) {
const char *data = req->data;
uint32_t length = req->info.len;
if (length == 0) {
ZVAL_EMPTY_STRING(zdata);
} else {
if (req->info.flags & SW_EVENT_DATA_OBJ_PTR) {
zend_string *worker_buffer = (zend_string *) (data - XtOffsetOf(zend_string, val));
ZVAL_STR(zdata, worker_buffer);
} else if (req->info.flags & SW_EVENT_DATA_POP_PTR) {
swString *recv_buffer = serv->get_recv_buffer(serv->get_connection_by_session_id(req->info.fd)->socket);
sw_set_zend_string(zdata, recv_buffer->pop(serv->recv_buffer_size), length);
} else {
ZVAL_STRINGL(zdata, data, length);
}
}
}
static sw_inline int php_swoole_check_task_param(Server *serv, zend_long dst_worker_id) {
if (UNEXPECTED(serv->task_worker_num == 0)) {
php_swoole_fatal_error(E_WARNING, "task method can't be executed without task worker");
return SW_ERR;
}
if (UNEXPECTED(dst_worker_id >= serv->task_worker_num)) {
php_swoole_fatal_error(E_WARNING, "worker_id must be less than task_worker_num[%u]", serv->task_worker_num);
return SW_ERR;
}
if (UNEXPECTED(swIsTaskWorker())) {
php_swoole_fatal_error(E_WARNING, "Server->task() cannot use in the task-worker");
return SW_ERR;
}
return SW_OK;
}
zval *php_swoole_task_unpack(EventData *task_result) {
zval *result_data, *result_unserialized_data;
char *result_data_str;
int result_data_len = 0;
php_unserialize_data_t var_hash;
/**
* Large result package
*/
if (swTask_type(task_result) & SW_TASK_TMPFILE) {
if (!task_result->unpack(SwooleTG.buffer_stack)) {
return nullptr;
}
result_data_str = SwooleTG.buffer_stack->str;
result_data_len = SwooleTG.buffer_stack->length;
} else {
result_data_str = task_result->data;
result_data_len = task_result->info.len;
}
if (swTask_type(task_result) & SW_TASK_SERIALIZE) {
result_unserialized_data = sw_malloc_zval();
PHP_VAR_UNSERIALIZE_INIT(var_hash);
// unserialize success
if (php_var_unserialize(result_unserialized_data,
(const unsigned char **) &result_data_str,
(const unsigned char *) (result_data_str + result_data_len),
&var_hash)) {
result_data = result_unserialized_data;
}
// failed
else {
result_data = sw_malloc_zval();
ZVAL_STRINGL(result_data, result_data_str, result_data_len);
}
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
} else {
result_data = sw_malloc_zval();
ZVAL_STRINGL(result_data, result_data_str, result_data_len);
}
return result_data;
}
static void php_swoole_task_wait_co(
Server *serv, EventData *req, double timeout, int dst_worker_id, INTERNAL_FUNCTION_PARAMETERS) {
ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->ptr2));
swTask_type(req) |= (SW_TASK_NONBLOCK | SW_TASK_COROUTINE);
TaskCo *task_co = (TaskCo *) emalloc(sizeof(TaskCo));
sw_memset_zero(task_co, sizeof(TaskCo));
task_co->count = 1;
Z_LVAL(task_co->context.coro_params) = req->info.fd;
sw_atomic_fetch_add(&serv->gs->tasking_num, 1);
if (serv->gs->task_workers.dispatch(req, &dst_worker_id) < 0) {
sw_atomic_fetch_sub(&serv->gs->tasking_num, 1);
RETURN_FALSE;
} else {
server_object->property->task_coroutine_map[req->info.fd] = task_co;
}
long ms = (long) (timeout * 1000);
TimerNode *timer = swoole_timer_add(ms, false, php_swoole_task_onTimeout, task_co);
if (timer) {
task_co->timer = timer;
}
task_co->server_object = server_object;
PHPCoroutine::yield_m(return_value, &task_co->context);
}
static void php_swoole_task_onTimeout(swTimer *timer, TimerNode *tnode) {
TaskCo *task_co = (TaskCo *) tnode->data;
FutureTask *context = &task_co->context;
zval *retval = nullptr;
// Server->taskwait, single task
if (task_co->list == nullptr) {
zval result;
ZVAL_FALSE(&result);
int ret = PHPCoroutine::resume_m(context, &result, retval);
if (ret == Coroutine::ERR_END && retval) {
zval_ptr_dtor(retval);
}
task_co->server_object->property->task_coroutine_map.erase(Z_LVAL(context->coro_params));
efree(task_co);
return;
}
uint32_t i;
zval *result = task_co->result;
for (i = 0; i < task_co->count; i++) {
if (!zend_hash_index_exists(Z_ARRVAL_P(result), i)) {
add_index_bool(result, i, 0);
task_co->server_object->property->task_coroutine_map.erase(task_co->list[i]);
}
}
int ret = PHPCoroutine::resume_m(context, result, retval);
if (ret == Coroutine::ERR_END && retval) {
zval_ptr_dtor(retval);
}
sw_zval_free(result);
efree(task_co);
}
extern ListenPort *php_swoole_server_port_get_and_check_ptr(zval *zobject);
extern void php_swoole_server_port_set_ptr(zval *zobject, ListenPort *port);
extern php_swoole_server_port_property *php_swoole_server_port_get_property(zval *zobject);
static zval *php_swoole_server_add_port(ServerObject *server_object, ListenPort *port) {
/* port */
zval *zport;
Server *serv = server_object->serv;
zport = sw_malloc_zval();
object_init_ex(zport, swoole_server_port_ce);
server_object->property->ports.push_back(zport);
/* port ptr */
php_swoole_server_port_set_ptr(zport, port);
/* port property */
php_swoole_server_port_property *property = php_swoole_server_port_get_property(zport);
property->serv = serv;
property->port = port;
/* linked */
port->ptr = property;
zend_update_property_string(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("host"), port->host);
zend_update_property_long(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("port"), port->port);
zend_update_property_long(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("type"), port->type);
zend_update_property_long(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("sock"), port->socket->fd);
do {
zval *zserv = (zval *) serv->ptr2;
zval *zports = sw_zend_read_and_convert_property_array(Z_OBJCE_P(zserv), zserv, ZEND_STRL("ports"), 0);
(void) add_next_index_zval(zports, zport);
} while (0);
/* iterator */
do {
zval connection_iterator;
object_init_ex(&connection_iterator, swoole_connection_iterator_ce);
ConnectionIterator *iterator = php_swoole_connection_iterator_get_ptr(&connection_iterator);
iterator->serv = serv;
iterator->port = port;
zend_update_property(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("connections"), &connection_iterator);
zval_ptr_dtor(&connection_iterator);
} while (0);
return zport;
}
void php_swoole_server_before_start(Server *serv, zval *zobject) {
/**
* create swoole server
*/
if (serv->create() < 0) {
php_swoole_fatal_error(E_ERROR, "failed to create the server. Error: %s", sw_error);
return;
}
#ifdef SW_LOG_TRACE_OPEN
auto primary_port = serv->get_primary_port();
swTraceLog(SW_TRACE_SERVER,
"Create Server: host=%s, port=%d, mode=%d, type=%d",
primary_port->host,
(int) primary_port->port,
serv->is_base_mode() ? Server::MODE_BASE : Server::MODE_PROCESS,
(int) primary_port->type);
#endif
if (serv->enable_coroutine) {
serv->reload_async = 1;
}
if (serv->send_yield) {
if (serv->onClose == nullptr && serv->is_support_unsafe_events()) {
serv->onClose = php_swoole_onClose;
}
}
/**
* init method
*/
serv->create_buffers = php_swoole_server_worker_create_buffers;
serv->free_buffers = php_swoole_server_worker_free_buffers;
serv->get_buffer = php_swoole_server_worker_get_buffer;
serv->get_buffer_len = php_swoole_server_worker_get_buffer_len;
serv->add_buffer_len = php_swoole_server_worker_add_buffer_len;
serv->move_buffer = php_swoole_server_worker_move_buffer;
serv->get_packet = php_swoole_server_worker_get_packet;
if (serv->is_base_mode()) {
serv->buffer_allocator = &SWOOLE_G(zend_string_allocator);
}
/**
* Master Process ID
*/
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("master_pid"), getpid());
zval *zsetting = sw_zend_read_and_convert_property_array(swoole_server_ce, zobject, ZEND_STRL("setting"), 0);
if (!zend_hash_str_exists(Z_ARRVAL_P(zsetting), ZEND_STRL("worker_num"))) {
add_assoc_long(zsetting, "worker_num", serv->worker_num);
}
if (!zend_hash_str_exists(Z_ARRVAL_P(zsetting), ZEND_STRL("task_worker_num"))) {
add_assoc_long(zsetting, "task_worker_num", serv->task_worker_num);
}
if (!zend_hash_str_exists(Z_ARRVAL_P(zsetting), ZEND_STRL("output_buffer_size"))) {
add_assoc_long(zsetting, "output_buffer_size", serv->output_buffer_size);
}
if (!zend_hash_str_exists(Z_ARRVAL_P(zsetting), ZEND_STRL("max_connection"))) {
add_assoc_long(zsetting, "max_connection", serv->get_max_connection());
}
uint32_t i;
zval *zport;
zval *zport_setting;
ListenPort *port;
bool find_http_port = false;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zobject));
for (i = 1; i < server_object->property->ports.size(); i++) {
zport = server_object->property->ports.at(i);
zport_setting = sw_zend_read_property_ex(swoole_server_port_ce, zport, SW_ZSTR_KNOWN(SW_ZEND_STR_SETTING), 0);
// use swoole_server->setting
if (zport_setting == nullptr || ZVAL_IS_NULL(zport_setting)) {
Z_TRY_ADDREF_P(zport);
sw_zend_call_method_with_1_params(zport, swoole_server_port_ce, nullptr, "set", nullptr, zsetting);
}
}
for (i = 0; i < server_object->property->ports.size(); i++) {
zport = server_object->property->ports.at(i);
port = php_swoole_server_port_get_and_check_ptr(zport);
if (serv->if_require_packet_callback(
port, php_swoole_server_isset_callback(server_object, port, SW_SERVER_CB_onPacket))) {
php_swoole_fatal_error(E_ERROR, "require onPacket callback");
return;
}
#ifdef SW_USE_OPENSSL
if (port->ssl_option.verify_peer && !port->ssl_option.client_cert_file) {
php_swoole_fatal_error(E_ERROR, "server open verify peer require client_cert_file config");
return;
}
#endif
if (port->open_http2_protocol && !serv->is_hash_dispatch_mode()) {
php_swoole_fatal_error(
E_ERROR,
"server dispatch mode should be FDMOD(%d) or IPMOD(%d) if open_http2_protocol is true",
SW_DISPATCH_FDMOD,
SW_DISPATCH_IPMOD);
return;
}
if (!port->open_http_protocol) {
port->open_http_protocol = port->open_websocket_protocol || port->open_http2_protocol;
}
if (port->open_http_protocol) {
find_http_port = true;
if (port->open_websocket_protocol) {
if (!php_swoole_server_isset_callback(server_object, port, SW_SERVER_CB_onMessage)) {
php_swoole_fatal_error(E_ERROR, "require onMessage callback");
return;
}
} else if (port->open_http_protocol &&
!php_swoole_server_isset_callback(server_object, port, SW_SERVER_CB_onRequest)) {
php_swoole_fatal_error(E_ERROR, "require onRequest callback");
return;
}
} else if (!port->open_redis_protocol) {
if (port->is_stream() && !php_swoole_server_isset_callback(server_object, port, SW_SERVER_CB_onReceive)) {
php_swoole_fatal_error(E_ERROR, "require onReceive callback");
return;
}
}
}
if (find_http_port) {
serv->onReceive = php_swoole_http_onReceive;
if (serv->is_support_unsafe_events()) {
serv->onClose = php_swoole_http_onClose;
}
if (!instanceof_function(Z_OBJCE_P(zobject), swoole_http_server_ce)) {
php_swoole_error(
E_WARNING,
"use %s class and open http related protocols may lead to some errors (inconsistent class type)",
SW_Z_OBJCE_NAME_VAL_P(zobject));
}
php_swoole_http_server_init_global_variant();
}
}
void php_swoole_server_register_callbacks(Server *serv) {
ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->ptr2));
/*
* optional callback
*/
if (server_object->property->callbacks[SW_SERVER_CB_onStart] != nullptr) {
serv->onStart = php_swoole_onStart;
}
serv->onShutdown = php_swoole_onShutdown;
/**
* require callback, set the master/manager/worker PID
*/
serv->onWorkerStart = php_swoole_onWorkerStart;
if (server_object->property->callbacks[SW_SERVER_CB_onBeforeReload] != nullptr) {
serv->onBeforeReload = php_swoole_onBeforeReload;
}
if (server_object->property->callbacks[SW_SERVER_CB_onAfterReload] != nullptr) {
serv->onAfterReload = php_swoole_onAfterReload;
}
if (server_object->property->callbacks[SW_SERVER_CB_onWorkerStop] != nullptr) {
serv->onWorkerStop = php_swoole_onWorkerStop;
}
if (server_object->property->callbacks[SW_SERVER_CB_onWorkerExit] != nullptr) {
serv->onWorkerExit = php_swoole_onWorkerExit;
}
/**
* Task Worker
*/
if (server_object->property->callbacks[SW_SERVER_CB_onTask] != nullptr) {
serv->onTask = php_swoole_onTask;
serv->onFinish = php_swoole_onFinish;
}
if (server_object->property->callbacks[SW_SERVER_CB_onWorkerError] != nullptr) {
serv->onWorkerError = php_swoole_onWorkerError;
}
if (server_object->property->callbacks[SW_SERVER_CB_onManagerStart] != nullptr) {
serv->onManagerStart = php_swoole_onManagerStart;
}
if (server_object->property->callbacks[SW_SERVER_CB_onManagerStop] != nullptr) {
serv->onManagerStop = php_swoole_onManagerStop;
}
if (server_object->property->callbacks[SW_SERVER_CB_onPipeMessage] != nullptr) {
serv->onPipeMessage = php_swoole_onPipeMessage;
}
if (serv->send_yield && serv->is_support_unsafe_events()) {
serv->onBufferEmpty = php_swoole_onBufferEmpty;
}
}
static int php_swoole_task_finish(Server *serv, zval *zdata, EventData *current_task) {
int flags = 0;
smart_str serialized_data = {};
php_serialize_data_t var_hash;
char *data_str;
int data_len = 0;
int ret;
// need serialize
if (Z_TYPE_P(zdata) != IS_STRING) {
// serialize
flags |= SW_TASK_SERIALIZE;
PHP_VAR_SERIALIZE_INIT(var_hash);
php_var_serialize(&serialized_data, zdata, &var_hash);
PHP_VAR_SERIALIZE_DESTROY(var_hash);
data_str = ZSTR_VAL(serialized_data.s);
data_len = ZSTR_LEN(serialized_data.s);
} else {
data_str = Z_STRVAL_P(zdata);
data_len = Z_STRLEN_P(zdata);
}
ret = serv->reply_task_result(data_str, data_len, flags, current_task);
smart_str_free(&serialized_data);
return ret;
}
static void php_swoole_onPipeMessage(Server *serv, EventData *req) {
ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->ptr2));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onPipeMessage];
zval *zserv = (zval *) serv->ptr2;
zval *zdata = php_swoole_task_unpack(req);
zval args[3];
if (UNEXPECTED(zdata == nullptr)) {
return;
}
swTraceLog(SW_TRACE_SERVER,
"PipeMessage: fd=%d|len=%d|from_id=%d|data=%.*s\n",
req->info.fd,
req->info.len,
req->info.reactor_id,
req->info.len,
req->data);
args[0] = *zserv;
ZVAL_LONG(&args[1], (zend_long) req->info.reactor_id);
args[2] = *zdata;
if (UNEXPECTED(!zend::function::call(fci_cache, 3, args, nullptr, is_enable_coroutine(serv)))) {
php_swoole_error(E_WARNING, "%s->onPipeMessage handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
sw_zval_free(zdata);
}
int php_swoole_onReceive(Server *serv, swRecvData *req) {
zend_fcall_info_cache *fci_cache =
php_swoole_server_get_fci_cache(serv, req->info.server_fd, SW_SERVER_CB_onReceive);
if (fci_cache) {
zval *zserv = (zval *) serv->ptr2;
zval args[4];
args[0] = *zserv;
ZVAL_LONG(&args[1], (zend_long) req->info.fd);
ZVAL_LONG(&args[2], (zend_long) req->info.reactor_id);
php_swoole_get_recv_data(serv, &args[3], req);
if (UNEXPECTED(!zend::function::call(fci_cache, 4, args, nullptr, SwooleG.enable_coroutine))) {
php_swoole_error(E_WARNING, "%s->onReceive handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
serv->close(req->info.fd, false);
}
zval_ptr_dtor(&args[3]);
}
return SW_OK;
}
int php_swoole_onPacket(Server *serv, swRecvData *req) {
zval *zserv = (zval *) serv->ptr2;
zval zaddr;
array_init(&zaddr);
DgramPacket *packet = (DgramPacket *) req->data;
add_assoc_long(&zaddr, "server_socket", req->info.server_fd);
Connection *from_sock = serv->get_connection(req->info.server_fd);
if (from_sock) {
add_assoc_long(&zaddr, "server_port", from_sock->info.get_port());
}
char address[INET6_ADDRSTRLEN];
if (packet->socket_type == SW_SOCK_UDP) {
inet_ntop(AF_INET, &packet->socket_addr.addr.inet_v4.sin_addr, address, sizeof(address));
add_assoc_string(&zaddr, "address", address);
add_assoc_long(&zaddr, "port", ntohs(packet->socket_addr.addr.inet_v4.sin_port));
} else if (packet->socket_type == SW_SOCK_UDP6) {
inet_ntop(AF_INET6, &packet->socket_addr.addr.inet_v6.sin6_addr, address, sizeof(address));
add_assoc_string(&zaddr, "address", address);
add_assoc_long(&zaddr, "port", packet->socket_addr.addr.inet_v6.sin6_port);
} else if (packet->socket_type == SW_SOCK_UNIX_DGRAM) {
add_assoc_string(&zaddr, "address", packet->socket_addr.addr.un.sun_path);
}
zend_fcall_info_cache *fci_cache =
php_swoole_server_get_fci_cache(serv, req->info.server_fd, SW_SERVER_CB_onPacket);
zval args[3];
args[0] = *zserv;
ZVAL_STRINGL(&args[1], packet->data, packet->length);
args[2] = zaddr;
if (UNEXPECTED(!zend::function::call(fci_cache, 3, args, nullptr, SwooleG.enable_coroutine))) {
php_swoole_error(E_WARNING, "%s->onPipeMessage handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
zval_ptr_dtor(&zaddr);
zval_ptr_dtor(&args[1]);
return SW_OK;
}
static sw_inline void php_swoole_create_task_object(zval *ztask, Server *serv, EventData *req, zval *zdata) {
object_init_ex(ztask, swoole_server_task_ce);
php_swoole_server_task_set_server(ztask, serv);
php_swoole_server_task_set_info(ztask, &req->info);
zend_update_property_long(
swoole_server_task_ce, SW_Z8_OBJ_P(ztask), ZEND_STRL("worker_id"), (zend_long) req->info.reactor_id);
zend_update_property_long(swoole_server_task_ce, SW_Z8_OBJ_P(ztask), ZEND_STRL("id"), (zend_long) req->info.fd);
zend_update_property(swoole_server_task_ce, SW_Z8_OBJ_P(ztask), ZEND_STRL("data"), zdata);
zend_update_property_long(
swoole_server_task_ce, SW_Z8_OBJ_P(ztask), ZEND_STRL("flags"), (zend_long) swTask_type(req));
}
static int php_swoole_onTask(Server *serv, EventData *req) {
sw_atomic_fetch_sub(&serv->gs->tasking_num, 1);
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zval *zdata = php_swoole_task_unpack(req);
if (zdata == nullptr) {
return SW_ERR;
}
zval retval;
uint32_t argc;
zval argv[4];
if (serv->task_enable_coroutine || serv->task_use_object) {
argc = 2;
argv[0] = *zserv;
php_swoole_create_task_object(&argv[1], serv, req, zdata);
} else {
argc = 4;
argv[0] = *zserv;
ZVAL_LONG(&argv[1], (zend_long) req->info.fd);
ZVAL_LONG(&argv[2], (zend_long) req->info.reactor_id);
argv[3] = *zdata;
}
if (UNEXPECTED(!zend::function::call(server_object->property->callbacks[SW_SERVER_CB_onTask],
argc,
argv,
&retval,
serv->task_enable_coroutine))) {
php_swoole_error(E_WARNING, "%s->onTask handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
if (argc == 2) {
zval_ptr_dtor(&argv[1]);
}
sw_zval_free(zdata);
if (!ZVAL_IS_NULL(&retval)) {
php_swoole_task_finish(serv, &retval, req);
zval_ptr_dtor(&retval);
}
return SW_OK;
}
static int php_swoole_onFinish(Server *serv, EventData *req) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zval args[3];
zval *zdata = php_swoole_task_unpack(req);
if (zdata == nullptr) {
return SW_ERR;
}
if (swTask_type(req) & SW_TASK_COROUTINE) {
int task_id = req->info.fd;
auto task_co_iterator = server_object->property->task_coroutine_map.find(task_id);
if (task_co_iterator == server_object->property->task_coroutine_map.end()) {
swoole_error_log(SW_LOG_WARNING, SW_ERROR_TASK_TIMEOUT, "task[%d] has expired", task_id);
_fail:
sw_zval_free(zdata);
return SW_OK;
}
TaskCo *task_co = task_co_iterator->second;
// Server->taskwait
if (task_co->list == nullptr) {
zval *retval = nullptr;
if (task_co->timer) {
swoole_timer_del(task_co->timer);
}
FutureTask *context = &task_co->context;
int ret = PHPCoroutine::resume_m(context, zdata, retval);
if (ret == Coroutine::ERR_END && retval) {
zval_ptr_dtor(retval);
}
efree(task_co);
sw_zval_free(zdata);
server_object->property->task_coroutine_map.erase(task_id);
return SW_OK;
}
// Server->taskCo
uint32_t i;
int task_index = -1;
zval *result = task_co->result;
for (i = 0; i < task_co->count; i++) {
if (task_co->list[i] == task_id) {
task_index = i;
break;
}
}
if (task_index < 0) {
php_swoole_fatal_error(E_WARNING, "task[%d] is invalid", task_id);
goto _fail;
}
(void) add_index_zval(result, task_index, zdata);
efree(zdata);
server_object->property->task_coroutine_map.erase(task_id);
if (php_swoole_array_length(result) == task_co->count) {
zval *retval = nullptr;
if (task_co->timer) {
swoole_timer_del(task_co->timer);
task_co->timer = nullptr;
}
FutureTask *context = &task_co->context;
int ret = PHPCoroutine::resume_m(context, result, retval);
if (ret == Coroutine::ERR_END && retval) {
zval_ptr_dtor(retval);
}
sw_zval_free(result);
efree(task_co);
}
return SW_OK;
}
args[0] = *zserv;
ZVAL_LONG(&args[1], (zend_long) req->info.fd);
args[2] = *zdata;
zend_fcall_info_cache *fci_cache = nullptr;
if (swTask_type(req) & SW_TASK_CALLBACK) {
auto callback_iterator = server_object->property->task_callbacks.find(req->info.fd);
if (callback_iterator == server_object->property->task_callbacks.end()) {
swTask_type(req) = swTask_type(req) & (~SW_TASK_CALLBACK);
} else {
fci_cache = &callback_iterator->second;
}
} else {
fci_cache = server_object->property->callbacks[SW_SERVER_CB_onFinish];
}
if (UNEXPECTED(fci_cache == nullptr)) {
sw_zval_free(zdata);
php_swoole_fatal_error(E_WARNING, "require onFinish callback");
return SW_ERR;
}
if (UNEXPECTED(!zend::function::call(fci_cache, 3, args, nullptr, SwooleG.enable_coroutine))) {
php_swoole_error(E_WARNING, "%s->onFinish handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
if (swTask_type(req) & SW_TASK_CALLBACK) {
sw_zend_fci_cache_discard(fci_cache);
server_object->property->task_callbacks.erase(req->info.fd);
}
sw_zval_free(zdata);
return SW_OK;
}
static void php_swoole_onStart(Server *serv) {
serv->lock();
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onStart];
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("master_pid"), serv->gs->master_pid);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("manager_pid"), serv->gs->manager_pid);
if (UNEXPECTED(!zend::function::call(fci_cache, 1, zserv, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onStart handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
serv->unlock();
}
static void php_swoole_onManagerStart(Server *serv) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onManagerStart];
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("master_pid"), serv->gs->master_pid);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("manager_pid"), serv->gs->manager_pid);
if (UNEXPECTED(!zend::function::call(fci_cache, 1, zserv, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onManagerStart handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
static void php_swoole_onManagerStop(Server *serv) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onManagerStop];
if (UNEXPECTED(!zend::function::call(fci_cache, 1, zserv, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onManagerStop handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
static void php_swoole_onShutdown(Server *serv) {
serv->lock();
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onShutdown];
if (fci_cache != nullptr) {
if (UNEXPECTED(!zend::function::call(fci_cache, 1, zserv, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onShutdown handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
serv->unlock();
}
static void php_swoole_onWorkerStart(Server *serv, int worker_id) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerStart];
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("master_pid"), serv->gs->master_pid);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("manager_pid"), serv->gs->manager_pid);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("worker_id"), worker_id);
zend_update_property_bool(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("taskworker"), swIsTaskWorker());
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("worker_pid"), getpid());
if (!is_enable_coroutine(serv)) {
SwooleG.enable_coroutine = 0;
PHPCoroutine::disable_hook();
}
if (fci_cache) {
zval args[2];
args[0] = *zserv;
ZVAL_LONG(&args[1], worker_id);
if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, nullptr, is_enable_coroutine(serv)))) {
php_swoole_error(E_WARNING, "%s->onWorkerStart handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
}
static void php_swoole_onBeforeReload(Server *serv) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onBeforeReload];
if (fci_cache) {
zval args[1];
args[0] = *zserv;
if (UNEXPECTED(!zend::function::call(fci_cache, 1, args, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onBeforeReload handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
}
static void php_swoole_onAfterReload(Server *serv) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onAfterReload];
if (fci_cache) {
zval args[1];
args[0] = *zserv;
if (UNEXPECTED(!zend::function::call(fci_cache, 1, args, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onAfterReload handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
}
static void php_swoole_onWorkerStop(Server *serv, int worker_id) {
if (SwooleWG.shutdown) {
return;
}
SwooleWG.shutdown = true;
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerStop];
zval args[2];
args[0] = *zserv;
ZVAL_LONG(&args[1], worker_id);
if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onWorkerStop handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
static void php_swoole_onWorkerExit(Server *serv, int worker_id) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerExit];
zval args[2];
args[0] = *zserv;
ZVAL_LONG(&args[1], worker_id);
if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onWorkerExit handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
static void php_swoole_onUserWorkerStart(Server *serv, Worker *worker) {
if (serv->enable_coroutine) {
SwooleG.enable_coroutine = 1;
}
zval *object = (zval *) worker->ptr;
zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(object), ZEND_STRL("id"), SwooleG.process_id);
zval *zserv = (zval *) serv->ptr2;
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("master_pid"), serv->gs->master_pid);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("manager_pid"), serv->gs->manager_pid);
php_swoole_process_start(worker, object);
}
static void php_swoole_onWorkerError(Server *serv, int worker_id, pid_t worker_pid, int exit_code, int signo) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerError];
zval args[5];
args[0] = *zserv;
ZVAL_LONG(&args[1], worker_id);
ZVAL_LONG(&args[2], worker_pid);
ZVAL_LONG(&args[3], exit_code);
ZVAL_LONG(&args[4], signo);
if (UNEXPECTED(!zend::function::call(fci_cache, 5, args, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onWorkerError handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
void php_swoole_onConnect(Server *serv, DataHead *info) {
zend_fcall_info_cache *fci_cache = php_swoole_server_get_fci_cache(serv, info->server_fd, SW_SERVER_CB_onConnect);
if (fci_cache) {
zval *zserv = (zval *) serv->ptr2;
zval args[3];
args[0] = *zserv;
ZVAL_LONG(&args[1], info->fd);
ZVAL_LONG(&args[2], info->reactor_id);
if (UNEXPECTED(!zend::function::call(fci_cache, 3, args, nullptr, SwooleG.enable_coroutine))) {
php_swoole_error(E_WARNING, "%s->onConnect handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
}
void php_swoole_onClose(Server *serv, DataHead *info) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
if (SwooleG.enable_coroutine && serv->send_yield) {
auto _i_coros_list = server_object->property->send_coroutine_map.find(info->fd);
if (_i_coros_list != server_object->property->send_coroutine_map.end()) {
auto coros_list = _i_coros_list->second;
server_object->property->send_coroutine_map.erase(info->fd);
while (!coros_list->empty()) {
FutureTask *context = coros_list->front();
coros_list->pop_front();
swoole_set_last_error(ECONNRESET);
zval_ptr_dtor(&context->coro_params);
ZVAL_NULL(&context->coro_params);
php_swoole_server_send_resume(serv, context, info->fd);
}
delete coros_list;
}
}
zend_fcall_info_cache *fci_cache = php_swoole_server_get_fci_cache(serv, info->server_fd, SW_SERVER_CB_onClose);
if (fci_cache) {
zval args[3];
args[0] = *zserv;
ZVAL_LONG(&args[1], info->fd);
ZVAL_LONG(&args[2], info->reactor_id);
if (UNEXPECTED(!zend::function::call(fci_cache, 3, args, nullptr, SwooleG.enable_coroutine))) {
php_swoole_error(E_WARNING, "%s->onClose handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
}
void php_swoole_onBufferFull(Server *serv, DataHead *info) {
zval *zserv = (zval *) serv->ptr2;
zend_fcall_info_cache *fci_cache =
php_swoole_server_get_fci_cache(serv, info->server_fd, SW_SERVER_CB_onBufferFull);
if (fci_cache) {
zval args[2];
args[0] = *zserv;
ZVAL_LONG(&args[1], info->fd);
if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onBufferFull handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
}
static void php_swoole_onSendTimeout(swTimer *timer, TimerNode *tnode) {
FutureTask *context = (FutureTask *) tnode->data;
zval *zdata = &context->coro_params;
zval result;
zval *retval = nullptr;
Server *serv = sw_server();
ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->ptr2));
swoole_set_last_error(ETIMEDOUT);
ZVAL_FALSE(&result);
int fd = (int) (long) context->private_data;
auto _i_coros_list = server_object->property->send_coroutine_map.find(fd);
if (_i_coros_list != server_object->property->send_coroutine_map.end()) {
auto coros_list = _i_coros_list->second;
coros_list->remove(context);
// free memory
if (coros_list->size() == 0) {
delete coros_list;
server_object->property->send_coroutine_map.erase(fd);
}
} else {
swWarn("send coroutine[fd=%d] not exists", fd);
return;
}
context->private_data = nullptr;
int ret = PHPCoroutine::resume_m(context, &result, retval);
if (ret == Coroutine::ERR_END && retval) {
zval_ptr_dtor(retval);
}
zval_ptr_dtor(zdata);
efree(context);
}
static enum swReturn_code php_swoole_server_send_resume(Server *serv, FutureTask *context, int fd) {
char *data;
zval *zdata = &context->coro_params;
zval result;
zval *retval = nullptr;
if (ZVAL_IS_NULL(zdata)) {
_fail:
ZVAL_FALSE(&result);
} else {
size_t length = php_swoole_get_send_data(zdata, &data);
if (length == 0) {
goto _fail;
}
bool ret = serv->send(fd, data, length);
if (!ret && swoole_get_last_error() == SW_ERROR_OUTPUT_SEND_YIELD && serv->send_yield) {
return SW_CONTINUE;
}
ZVAL_BOOL(&result, ret);
}
if (context->timer) {
swoole_timer_del((TimerNode *) context->timer);
context->timer = nullptr;
}
int ret = PHPCoroutine::resume_m(context, &result, retval);
if (ret == Coroutine::ERR_END && retval) {
zval_ptr_dtor(retval);
}
zval_ptr_dtor(zdata);
efree(context);
return SW_READY;
}
void php_swoole_server_send_yield(Server *serv, int fd, zval *zdata, zval *return_value) {
ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->ptr2));
std::list<FutureTask *> *coros_list;
auto coroutine_iterator = server_object->property->send_coroutine_map.find(fd);
if (coroutine_iterator == server_object->property->send_coroutine_map.end()) {
coros_list = new std::list<FutureTask *>;
server_object->property->send_coroutine_map[fd] = coros_list;
} else {
coros_list = coroutine_iterator->second;
}
FutureTask *context = (FutureTask *) emalloc(sizeof(FutureTask));
coros_list->push_back(context);
context->private_data = (void *) (long) fd;
if (serv->send_timeout > 0) {
context->timer = swoole_timer_add((long) (serv->send_timeout * 1000), false, php_swoole_onSendTimeout, context);
} else {
context->timer = nullptr;
}
context->coro_params = *zdata;
PHPCoroutine::yield_m(return_value, context);
}
static int php_swoole_server_dispatch_func(Server *serv, Connection *conn, SendData *data) {
serv->lock();
zend_fcall_info_cache *fci_cache = (zend_fcall_info_cache *) serv->private_data_3;
zval args[4];
zval *zserv = &args[0], *zfd = &args[1], *ztype = &args[2], *zdata = nullptr;
zval retval;
zend_long worker_id = -1;
*zserv = *((zval *) serv->ptr2);
ZVAL_LONG(zfd, (zend_long)(conn ? conn->session_id : data->info.fd));
ZVAL_LONG(ztype, (zend_long)(data ? data->info.type : (int) SW_SERVER_EVENT_CLOSE));
if (data && sw_zend_function_max_num_args(fci_cache->function_handler) > 3) {
// TODO: reduce memory copy
zdata = &args[3];
ZVAL_STRINGL(zdata, data->data, data->info.len > SW_IPC_BUFFER_SIZE ? SW_IPC_BUFFER_SIZE : data->info.len);
}
if (UNEXPECTED(sw_zend_call_function_ex(nullptr, fci_cache, zdata ? 4 : 3, args, &retval) != SUCCESS)) {
php_swoole_error(E_WARNING, "%s->onDispatch handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
} else if (!ZVAL_IS_NULL(&retval)) {
worker_id = zval_get_long(&retval);
if (worker_id >= (zend_long) serv->worker_num) {
php_swoole_fatal_error(E_WARNING, "invalid target worker-id[" ZEND_LONG_FMT "]", worker_id);
worker_id = -1;
}
zval_ptr_dtor(&retval);
}
if (zdata) {
zval_ptr_dtor(zdata);
}
serv->unlock();
/* the exception should only be thrown after unlocked */
if (UNEXPECTED(EG(exception))) {
zend_exception_error(EG(exception), E_ERROR);
}
return worker_id;
}
void php_swoole_onBufferEmpty(Server *serv, DataHead *info) {
zval *zserv = (zval *) serv->ptr2;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend_fcall_info_cache *fci_cache;
if (serv->send_yield) {
auto _i_coros_list = server_object->property->send_coroutine_map.find(info->fd);
if (_i_coros_list != server_object->property->send_coroutine_map.end()) {
auto coros_list = _i_coros_list->second;
server_object->property->send_coroutine_map.erase(info->fd);
while (!coros_list->empty()) {
FutureTask *context = coros_list->front();
coros_list->pop_front();
if (php_swoole_server_send_resume(serv, context, info->fd) == SW_CONTINUE) {
coros_list->push_back(context);
return;
}
}
delete coros_list;
}
}
fci_cache = php_swoole_server_get_fci_cache(serv, info->server_fd, SW_SERVER_CB_onBufferEmpty);
if (fci_cache) {
zval args[2];
args[0] = *zserv;
ZVAL_LONG(&args[1], info->fd);
if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, nullptr, false))) {
php_swoole_error(E_WARNING, "%s->onBufferEmpty handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
}
}
}
static void **php_swoole_server_worker_create_buffers(Server *serv, uint buffer_num) {
zend_string **buffers = (zend_string **) sw_calloc(buffer_num, sizeof(zend_string *));
if (buffers == nullptr) {
swError("malloc for worker input_buffers failed");
}
return (void **) buffers;
}
static void php_swoole_server_worker_free_buffers(Server *serv, uint buffer_num, void **buffers) {
sw_free(buffers);
}
static sw_inline zend_string *php_swoole_server_worker_get_input_buffer(Server *serv, int reactor_id) {
zend_string **buffers = (zend_string **) serv->worker_input_buffers;
if (serv->is_base_mode()) {
return buffers[0];
} else {
return buffers[reactor_id];
}
}
static sw_inline void php_swoole_server_worker_set_buffer(Server *serv, DataHead *info, zend_string *addr) {
zend_string **buffers = (zend_string **) serv->worker_input_buffers;
buffers[info->reactor_id] = addr;
}
static void *php_swoole_server_worker_get_buffer(Server *serv, DataHead *info) {
zend_string *worker_buffer = php_swoole_server_worker_get_input_buffer(serv, info->reactor_id);
if (worker_buffer == nullptr) {
worker_buffer = zend_string_alloc(info->len, 0);
worker_buffer->len = 0;
php_swoole_server_worker_set_buffer(serv, info, worker_buffer);
}
return worker_buffer->val + worker_buffer->len;
}
static size_t php_swoole_server_worker_get_buffer_len(Server *serv, DataHead *info) {
zend_string *worker_buffer = php_swoole_server_worker_get_input_buffer(serv, info->reactor_id);
return worker_buffer == nullptr ? 0 : worker_buffer->len;
}
static void php_swoole_server_worker_add_buffer_len(Server *serv, DataHead *info, size_t len) {
zend_string *worker_buffer = php_swoole_server_worker_get_input_buffer(serv, info->reactor_id);
worker_buffer->len += len;
}
static void php_swoole_server_worker_move_buffer(Server *serv, PipeBuffer *buffer) {
zend_string *worker_buffer = php_swoole_server_worker_get_input_buffer(serv, buffer->info.reactor_id);
memcpy(buffer->data, &worker_buffer, sizeof(worker_buffer));
worker_buffer->val[worker_buffer->len] = '\0';
php_swoole_server_worker_set_buffer(serv, &buffer->info, nullptr);
}
static size_t php_swoole_server_worker_get_packet(Server *serv, EventData *req, char **data_ptr) {
size_t length;
if (req->info.flags & SW_EVENT_DATA_PTR) {
PacketPtr *task = (PacketPtr *) req;
*data_ptr = task->data.str;
length = task->data.length;
} else if (req->info.flags & SW_EVENT_DATA_OBJ_PTR) {
zend_string *worker_buffer;
memcpy(&worker_buffer, req->data, sizeof(worker_buffer));
*data_ptr = worker_buffer->val;
length = worker_buffer->len;
} else {
*data_ptr = req->data;
length = req->info.len;
}
return length;
}
static PHP_METHOD(swoole_server, __construct) {
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
Server *serv = server_object->serv;
if (serv) {
php_swoole_fatal_error(E_ERROR, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
}
zval *zserv = ZEND_THIS;
char *host;
size_t host_len = 0;
zend_long sock_type = SW_SOCK_TCP;
zend_long serv_port = 0;
zend_long serv_mode = Server::MODE_PROCESS;
// only cli env
if (!SWOOLE_G(cli)) {
zend_throw_exception_ex(
swoole_exception_ce, -1, "%s can only be used in CLI mode", SW_Z_OBJCE_NAME_VAL_P(zserv));
RETURN_FALSE;
}
if (sw_server() != nullptr) {
zend_throw_exception_ex(
swoole_exception_ce, -3, "server is running. unable to create %s", SW_Z_OBJCE_NAME_VAL_P(zserv));
RETURN_FALSE;
}
ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 4)
Z_PARAM_STRING(host, host_len)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(serv_port)
Z_PARAM_LONG(serv_mode)
Z_PARAM_LONG(sock_type)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
if (serv_mode != Server::MODE_BASE && serv_mode != Server::MODE_PROCESS) {
php_swoole_fatal_error(E_ERROR, "invalid $mode parameters %d", (int) serv_mode);
RETURN_FALSE;
}
serv = new Server((enum Server::Mode) serv_mode);
serv->ptr2 = sw_zval_dup(zserv);
server_set_ptr(zserv, serv);
if (serv_mode == Server::MODE_BASE) {
serv->reactor_num = 1;
serv->worker_num = 1;
}
/* primary port */
do {
if (serv_port == 0 && strcasecmp(host, "SYSTEMD") == 0) {
if (serv->add_systemd_socket() <= 0) {
php_swoole_fatal_error(E_ERROR, "failed to add systemd socket");
RETURN_FALSE;
}
} else {
ListenPort *port = serv->add_port((enum swSocket_type) sock_type, host, serv_port);
if (!port) {
zend_throw_exception_ex(swoole_exception_ce,
errno,
"failed to listen server port[%s:" ZEND_LONG_FMT "], Error: %s[%d]",
host,
serv_port,
strerror(errno),
errno);
RETURN_FALSE;
}
}
for (auto ls : serv->ports) {
php_swoole_server_add_port(server_object, ls);
}
server_object->property->primary_port = (php_swoole_server_port_property *) serv->get_primary_port()->ptr;
} while (0);
/* iterator */
do {
zval connection_iterator;
object_init_ex(&connection_iterator, swoole_connection_iterator_ce);
ConnectionIterator *iterator = php_swoole_connection_iterator_get_ptr(&connection_iterator);
iterator->serv = serv;
zend_update_property(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("connections"), &connection_iterator);
zval_ptr_dtor(&connection_iterator);
} while (0);
/* info */
zend_update_property_stringl(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("host"), host, host_len);
zend_update_property_long(
swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("port"), (zend_long) serv->get_primary_port()->port);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("mode"), serv_mode);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("type"), sock_type);
}
static PHP_METHOD(swoole_server, __destruct) {}
static PHP_METHOD(swoole_server, set) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (serv->is_started()) {
php_swoole_fatal_error(
E_WARNING, "server is running, unable to execute %s->set", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
RETURN_FALSE;
}
zval *zset = nullptr, *ztmp;
HashTable *vht;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY(zset)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
vht = Z_ARRVAL_P(zset);
php_swoole_set_global_option(vht);
if (php_swoole_array_get_value(vht, "chroot", ztmp)) {
serv->chroot = zend::String(ztmp).to_std_string();
}
if (php_swoole_array_get_value(vht, "user", ztmp)) {
serv->user = zend::String(ztmp).to_std_string();
}
if (php_swoole_array_get_value(vht, "group", ztmp)) {
serv->group = zend::String(ztmp).to_std_string();
}
if (php_swoole_array_get_value(vht, "daemonize", ztmp)) {
serv->daemonize = zval_is_true(ztmp);
}
if (php_swoole_array_get_value(vht, "pid_file", ztmp)) {
serv->pid_file = zend::String(ztmp).to_std_string();
}
if (php_swoole_array_get_value(vht, "reactor_num", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->reactor_num = SW_MAX(0, SW_MIN(v, UINT16_MAX));
if (serv->reactor_num == 0) {
serv->reactor_num = SW_CPU_NUM;
}
}
if (php_swoole_array_get_value(vht, "single_thread", ztmp)) {
serv->single_thread = zval_is_true(ztmp);
}
if (php_swoole_array_get_value(vht, "worker_num", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->worker_num = SW_MAX(0, SW_MIN(v, UINT32_MAX));
if (serv->worker_num == 0) {
serv->worker_num = SW_CPU_NUM;
}
}
if (php_swoole_array_get_value(vht, "max_wait_time", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->max_wait_time = SW_MAX(0, SW_MIN(v, UINT32_MAX));
}
if (php_swoole_array_get_value(vht, "max_queued_bytes", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->max_queued_bytes = SW_MAX(0, SW_MIN(v, UINT32_MAX));
}
if (php_swoole_array_get_value(vht, "enable_coroutine", ztmp)) {
serv->enable_coroutine = zval_is_true(ztmp);
SwooleG.enable_coroutine = zval_is_true(ztmp);
}
if (php_swoole_array_get_value(vht, "max_coro_num", ztmp) ||
php_swoole_array_get_value(vht, "max_coroutine", ztmp)) {
zend_long max_num;
max_num = zval_get_long(ztmp);
PHPCoroutine::set_max_num(max_num <= 0 ? SW_DEFAULT_MAX_CORO_NUM : max_num);
}
if (php_swoole_array_get_value(vht, "hook_flags", ztmp)) {
PHPCoroutine::set_hook_flags(zval_get_long(ztmp));
}
if (php_swoole_array_get_value(vht, "send_timeout", ztmp)) {
serv->send_timeout = zval_get_double(ztmp);
}
if (php_swoole_array_get_value(vht, "dispatch_mode", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->dispatch_mode = SW_MAX(0, SW_MIN(v, UINT8_MAX));
}
if (php_swoole_array_get_value(vht, "send_yield", ztmp)) {
serv->send_yield = zval_is_true(ztmp);
if (serv->send_yield &&
!(serv->dispatch_mode == SW_DISPATCH_FDMOD || serv->dispatch_mode == SW_DISPATCH_IPMOD)) {
php_swoole_error(E_WARNING, "'send_yield' option can only be set when using dispatch_mode=2/4");
serv->send_yield = 0;
}
}
if (php_swoole_array_get_value(vht, "dispatch_func", ztmp)) {
Server::DispatchFunction c_dispatch_func = nullptr;
while (1) {
if (Z_TYPE_P(ztmp) == IS_STRING) {
c_dispatch_func = (Server::DispatchFunction) swoole_get_function(Z_STRVAL_P(ztmp), Z_STRLEN_P(ztmp));
if (c_dispatch_func) {
break;
}
}
#ifdef ZTS
if (serv->is_process_mode() && !serv->single_thread) {
php_swoole_fatal_error(E_ERROR, "option [dispatch_func] does not support with ZTS");
}
#endif
char *func_name = nullptr;
zend_fcall_info_cache *fci_cache = (zend_fcall_info_cache *) emalloc(sizeof(zend_fcall_info_cache));
if (!sw_zend_is_callable_ex(ztmp, nullptr, 0, &func_name, nullptr, fci_cache, nullptr)) {
php_swoole_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
return;
}
efree(func_name);
sw_zend_fci_cache_persist(fci_cache);
if (serv->private_data_3) {
sw_zend_fci_cache_discard((zend_fcall_info_cache *) serv->private_data_3);
efree(serv->private_data_3);
}
serv->private_data_3 = (void *) fci_cache;
c_dispatch_func = php_swoole_server_dispatch_func;
break;
}
serv->dispatch_func = c_dispatch_func;
}
/**
* for dispatch_mode = 1/3
*/
if (php_swoole_array_get_value(vht, "discard_timeout_request", ztmp)) {
serv->discard_timeout_request = zval_is_true(ztmp);
}
// onConnect/onClose event
if (php_swoole_array_get_value(vht, "enable_unsafe_event", ztmp)) {
serv->enable_unsafe_event = zval_is_true(ztmp);
}
// delay receive
if (php_swoole_array_get_value(vht, "enable_delay_receive", ztmp)) {
serv->enable_delay_receive = zval_is_true(ztmp);
}
#if defined(__linux__) and defined(HAVE_REUSEPORT)
if (php_swoole_array_get_value(vht, "enable_reuse_port", ztmp)) {
serv->enable_reuse_port = zval_is_true(ztmp);
}
#endif
// task use object
if (php_swoole_array_get_value(vht, "task_use_object", ztmp)) {
serv->task_use_object = zval_is_true(ztmp);
}
// task coroutine
if (php_swoole_array_get_value(vht, "task_enable_coroutine", ztmp)) {
serv->task_enable_coroutine = zval_is_true(ztmp);
}
// task_worker_num
if (php_swoole_array_get_value(vht, "task_worker_num", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->task_worker_num = SW_MAX(0, SW_MIN(v, UINT32_MAX));
}
// task ipc mode, 1,2,3
if (php_swoole_array_get_value(vht, "task_ipc_mode", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->task_ipc_mode = SW_MAX(0, SW_MIN(v, UINT8_MAX));
}
/**
* Temporary file directory for task_worker
*/
if (php_swoole_array_get_value(vht, "task_tmpdir", ztmp)) {
zend::String str_v(ztmp);
if (php_swoole_create_dir(str_v.val(), str_v.len()) < 0) {
php_swoole_fatal_error(E_ERROR, "Unable to create task_tmpdir[%s]", str_v.val());
return;
}
if (SwooleG.task_tmpdir) {
sw_free(SwooleG.task_tmpdir);
}
SwooleG.task_tmpdir = (char *) sw_malloc(str_v.len() + sizeof(SW_TASK_TMP_FILE) + 1);
if (!SwooleG.task_tmpdir) {
php_swoole_fatal_error(E_ERROR, "malloc() failed");
RETURN_FALSE;
}
SwooleG.task_tmpdir_len =
sw_snprintf(SwooleG.task_tmpdir, SW_TASK_TMPDIR_SIZE, "%s/swoole.task.XXXXXX", str_v.val()) + 1;
}
// task_max_request
if (php_swoole_array_get_value(vht, "task_max_request", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->task_max_request = SW_MAX(0, SW_MIN(v, UINT32_MAX));
// task_max_request_grace
if (php_swoole_array_get_value(vht, "task_max_request_grace", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->task_max_request_grace = SW_MAX(0, SW_MIN(v, UINT32_MAX));
} else if (serv->task_max_request > SW_WORKER_MIN_REQUEST) {
serv->task_max_request_grace = serv->task_max_request / 2;
}
}
// max_connection
if (php_swoole_array_get_value(vht, "max_connection", ztmp) || php_swoole_array_get_value(vht, "max_conn", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->set_max_connection(SW_MAX(0, SW_MIN(v, UINT32_MAX)));
}
// heartbeat_check_interval
if (php_swoole_array_get_value(vht, "heartbeat_check_interval", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->heartbeat_check_interval = SW_MAX(0, SW_MIN(v, UINT16_MAX));
}
// heartbeat idle time
if (php_swoole_array_get_value(vht, "heartbeat_idle_time", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->heartbeat_idle_time = SW_MAX(0, SW_MIN(v, UINT16_MAX));
if (serv->heartbeat_check_interval > serv->heartbeat_idle_time) {
php_swoole_fatal_error(E_WARNING, "heartbeat_idle_time must be greater than heartbeat_check_interval");
serv->heartbeat_check_interval = serv->heartbeat_idle_time / 2;
}
} else if (serv->heartbeat_check_interval > 0) {
serv->heartbeat_idle_time = serv->heartbeat_check_interval * 2;
}
// max_request
if (php_swoole_array_get_value(vht, "max_request", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->max_request = SW_MAX(0, SW_MIN(v, UINT32_MAX));
// max_request_grace
if (php_swoole_array_get_value(vht, "max_request_grace", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->max_request_grace = SW_MAX(0, SW_MIN(v, UINT32_MAX));
} else if (serv->max_request > SW_WORKER_MIN_REQUEST) {
serv->max_request_grace = serv->max_request / 2;
}
}
// reload async
if (php_swoole_array_get_value(vht, "reload_async", ztmp)) {
serv->reload_async = zval_is_true(ztmp);
}
// cpu affinity
if (php_swoole_array_get_value(vht, "open_cpu_affinity", ztmp)) {
serv->open_cpu_affinity = zval_is_true(ztmp);
}
// cpu affinity set
if (php_swoole_array_get_value(vht, "cpu_affinity_ignore", ztmp)) {
int ignore_num = zend_hash_num_elements(Z_ARRVAL_P(ztmp));
if (ignore_num >= SW_CPU_NUM) {
php_swoole_fatal_error(E_ERROR, "cpu_affinity_ignore num must be less than cpu num (%d)", SW_CPU_NUM);
RETURN_FALSE;
}
int available_num = SW_CPU_NUM - ignore_num;
int *available_cpu = (int *) sw_malloc(sizeof(int) * available_num);
if (!available_cpu) {
php_swoole_fatal_error(E_WARNING, "malloc() failed");
RETURN_FALSE;
}
int flag, i, available_i = 0;
zval *zval_core = nullptr;
for (i = 0; i < SW_CPU_NUM; i++) {
flag = 1;
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(ztmp), zval_core)
if (i == zval_get_long(zval_core)) {
flag = 0;
break;
}
SW_HASHTABLE_FOREACH_END();
if (flag) {
available_cpu[available_i] = i;
available_i++;
}
}
serv->cpu_affinity_available_num = available_num;
if (serv->cpu_affinity_available) {
sw_free(serv->cpu_affinity_available);
}
serv->cpu_affinity_available = available_cpu;
}
// parse cookie header
if (php_swoole_array_get_value(vht, "http_parse_cookie", ztmp)) {
serv->http_parse_cookie = zval_is_true(ztmp);
}
// parse x-www-form-urlencoded form data
if (php_swoole_array_get_value(vht, "http_parse_post", ztmp)) {
serv->http_parse_post = zval_is_true(ztmp);
}
// parse multipart/form-data file uploads
if (php_swoole_array_get_value(vht, "http_parse_files", ztmp)) {
serv->http_parse_files = zval_is_true(ztmp);
}
#ifdef SW_HAVE_COMPRESSION
// http content compression
if (php_swoole_array_get_value(vht, "http_compression", ztmp)) {
serv->http_compression = zval_is_true(ztmp);
}
if (php_swoole_array_get_value(vht, "http_compression_level", ztmp) ||
php_swoole_array_get_value(vht, "http_gzip_level", ztmp)) {
zend_long level = zval_get_long(ztmp);
if (level > UINT8_MAX) {
level = UINT8_MAX;
} else if (level < 0) {
level = 0;
}
serv->http_compression_level = level;
}
#endif
#ifdef SW_HAVE_ZLIB
if (php_swoole_array_get_value(vht, "websocket_compression", ztmp)) {
serv->websocket_compression = zval_is_true(ztmp);
}
#endif
// temporary directory for HTTP uploaded file.
if (php_swoole_array_get_value(vht, "upload_tmp_dir", ztmp)) {
zend::String str_v(ztmp);
if (php_swoole_create_dir(str_v.val(), str_v.len()) < 0) {
php_swoole_fatal_error(E_ERROR, "Unable to create upload_tmp_dir[%s]", str_v.val());
return;
}
serv->upload_tmp_dir = str_v.to_std_string();
}
/**
* http static file handler
*/
if (php_swoole_array_get_value(vht, "enable_static_handler", ztmp)) {
serv->enable_static_handler = zval_is_true(ztmp);
}
if (php_swoole_array_get_value(vht, "document_root", ztmp)) {
zend::String str_v(ztmp);
if (str_v.len() >= PATH_MAX) {
php_swoole_fatal_error(E_ERROR, "The length of document_root must be less than %d", PATH_MAX);
return;
}
serv->set_document_root(std::string(str_v.val(), str_v.len()));
}
if (php_swoole_array_get_value(vht, "http_autoindex", ztmp)) {
serv->http_autoindex = zval_is_true(ztmp);
}
if (php_swoole_array_get_value(vht, "http_index_files", ztmp)) {
if (ZVAL_IS_ARRAY(ztmp)) {
zval *_http_index_files;
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(ztmp), _http_index_files)
zend::String __http_index_files(_http_index_files);
if (__http_index_files.len() > 0) {
serv->add_static_handler_index_files(__http_index_files.to_std_string());
}
SW_HASHTABLE_FOREACH_END();
} else {
php_swoole_fatal_error(E_ERROR, "http_index_files must be array");
RETURN_FALSE;
}
}
/**
* [static_handler] locations
*/
if (php_swoole_array_get_value(vht, "static_handler_locations", ztmp)) {
if (ZVAL_IS_ARRAY(ztmp)) {
zval *_location;
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(ztmp), _location)
zend::String __location(_location);
if (__location.len() > 0 && __location.val()[0] == '/') {
serv->add_static_handler_location(__location.to_std_string());
}
SW_HASHTABLE_FOREACH_END();
} else {
php_swoole_fatal_error(E_ERROR, "static_handler_locations num must be array");
RETURN_FALSE;
}
}
/**
* buffer input size
*/
if (php_swoole_array_get_value(vht, "input_buffer_size", ztmp) ||
php_swoole_array_get_value(vht, "buffer_input_size", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->input_buffer_size = SW_MAX(0, SW_MIN(v, UINT32_MAX));
}
/**
* buffer output size
*/
if (php_swoole_array_get_value(vht, "output_buffer_size", ztmp) ||
php_swoole_array_get_value(vht, "buffer_output_size", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->output_buffer_size = SW_MAX(0, SW_MIN(v, UINT32_MAX));
}
// message queue key
if (php_swoole_array_get_value(vht, "message_queue_key", ztmp)) {
zend_long v = zval_get_long(ztmp);
serv->message_queue_key = SW_MAX(0, SW_MIN(v, INT64_MAX));
}
if (serv->task_enable_coroutine &&
(serv->task_ipc_mode == SW_TASK_IPC_MSGQUEUE || serv->task_ipc_mode == SW_TASK_IPC_PREEMPTIVE)) {
php_swoole_fatal_error(E_ERROR, "cannot use msgqueue when task_enable_coroutine is enable");
RETURN_FALSE;
}
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
sw_zend_call_method_with_1_params(
server_object->property->ports.at(0), swoole_server_port_ce, nullptr, "set", nullptr, zset);
zval *zsetting = sw_zend_read_and_convert_property_array(swoole_server_ce, ZEND_THIS, ZEND_STRL("setting"), 0);
php_array_merge(Z_ARRVAL_P(zsetting), Z_ARRVAL_P(zset));
RETURN_TRUE;
}
static PHP_METHOD(swoole_server, on) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (serv->is_started()) {
php_swoole_fatal_error(E_WARNING, "server is running, unable to register event callback function");
RETURN_FALSE;
}
zval *name;
zval *cb;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &name, &cb) == FAILURE) {
RETURN_FALSE;
}
char *func_name = nullptr;
zend_fcall_info_cache *fci_cache = (zend_fcall_info_cache *) emalloc(sizeof(zend_fcall_info_cache));
if (!sw_zend_is_callable_ex(cb, nullptr, 0, &func_name, nullptr, fci_cache, nullptr)) {
php_swoole_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
return;
}
efree(func_name);
zend::String _event_name_ori(name);
zend::String _event_name_tolower(zend_string_tolower(_event_name_ori.get()), false);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
auto i = server_event_map.find(_event_name_tolower.to_std_string());
if (i == server_event_map.end()) {
zval *port_object = server_object->property->ports.at(0);
zval retval;
efree(fci_cache);
sw_zend_call_method_with_2_params(port_object, swoole_server_port_ce, nullptr, "on", &retval, name, cb);
RETURN_BOOL(Z_BVAL_P(&retval));
} else {
int event_type = i->second.type;
std::string property_name = "on" + i->second.name;
zend_update_property(
swoole_server_ce, SW_Z8_OBJ_P(ZEND_THIS), property_name.c_str(), property_name.length(), cb);
if (server_object->property->callbacks[event_type]) {
efree(server_object->property->callbacks[event_type]);
}
server_object->property->callbacks[event_type] = fci_cache;
RETURN_TRUE;
}
}
static PHP_METHOD(swoole_server, getCallback) {
zval *name;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(name)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
zend::String _event_name_ori(name);
zend::String _event_name_tolower(zend_string_tolower(_event_name_ori.get()), false);
auto i = server_event_map.find(_event_name_tolower.to_std_string());
if (i != server_event_map.end()) {
std::string property_name = "on" + i->second.name;
// Notice: we should use Z_OBJCE_P instead of swoole_server_ce, because we need to consider the subclasses.
zval rv,
*property = zend_read_property(
Z_OBJCE_P(ZEND_THIS), SW_Z8_OBJ_P(ZEND_THIS), property_name.c_str(), property_name.length(), 1, &rv);
if (!ZVAL_IS_NULL(property)) {
RETURN_ZVAL(property, 1, 0);
}
}
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
sw_zend_call_method_with_1_params(
server_object->property->ports.at(0), swoole_server_port_ce, nullptr, "getcallback", return_value, name);
}
static PHP_METHOD(swoole_server, listen) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (serv->is_started()) {
php_swoole_fatal_error(E_WARNING, "server is running, can't add listener");
RETURN_FALSE;
}
char *host;
size_t host_len;
long sock_type;
long port;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll", &host, &host_len, &port, &sock_type) == FAILURE) {
RETURN_FALSE;
}
ListenPort *ls = serv->add_port((enum swSocket_type) sock_type, host, (int) port);
if (!ls) {
RETURN_FALSE;
}
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
zval *port_object = php_swoole_server_add_port(server_object, ls);
RETURN_ZVAL(port_object, 1, 0);
}
extern Worker *php_swoole_process_get_and_check_worker(zval *zobject);
static PHP_METHOD(swoole_server, addProcess) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (serv->is_started()) {
php_swoole_fatal_error(E_WARNING, "server is running, can't add process");
RETURN_FALSE;
}
zval *process = nullptr;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &process) == FAILURE) {
RETURN_FALSE;
}
if (ZVAL_IS_NULL(process)) {
php_swoole_fatal_error(E_WARNING, "the first parameter can't be empty");
RETURN_FALSE;
}
if (!instanceof_function(Z_OBJCE_P(process), swoole_process_ce)) {
php_swoole_fatal_error(E_ERROR, "object is not instanceof swoole_process");
RETURN_FALSE;
}
if (serv->onUserWorkerStart == nullptr) {
serv->onUserWorkerStart = php_swoole_onUserWorkerStart;
}
zval *tmp_process = (zval *) emalloc(sizeof(zval));
memcpy(tmp_process, process, sizeof(zval));
process = tmp_process;
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
server_object->property->user_processes.push_back(process);
Z_TRY_ADDREF_P(process);
Worker *worker = php_swoole_process_get_and_check_worker(process);
worker->ptr = process;
int id = serv->add_worker(worker);
if (id < 0) {
php_swoole_fatal_error(E_WARNING, "Server::add_worker() failed");
RETURN_FALSE;
}
zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(process), ZEND_STRL("id"), id);
RETURN_LONG(id);
}
static inline zend_bool is_websocket_server(zval *zobject) {
return instanceof_function(Z_OBJCE_P(zobject), swoole_websocket_server_ce);
}
static inline zend_bool is_http_server(zval *zobject) {
return instanceof_function(Z_OBJCE_P(zobject), swoole_http_server_ce);
}
static PHP_METHOD(swoole_server, start) {
zval *zserv = ZEND_THIS;
Server *serv = php_swoole_server_get_and_check_server(zserv);
if (serv->is_started()) {
php_swoole_fatal_error(
E_WARNING, "server is running, unable to execute %s->start()", SW_Z_OBJCE_NAME_VAL_P(zserv));
RETURN_FALSE;
}
if (serv->is_shutdown()) {
php_swoole_fatal_error(
E_WARNING, "server have been shutdown, unable to execute %s->start()", SW_Z_OBJCE_NAME_VAL_P(zserv));
RETURN_FALSE;
}
if (SwooleTG.reactor) {
php_swoole_fatal_error(
E_WARNING, "eventLoop has already been created, unable to start %s", SW_Z_OBJCE_NAME_VAL_P(zserv));
RETURN_FALSE;
}
php_swoole_server_register_callbacks(serv);
serv->onReceive = php_swoole_onReceive;
if (is_websocket_server(zserv) || is_http_server(zserv)) {
zval *zsetting = sw_zend_read_and_convert_property_array(swoole_server_ce, ZEND_THIS, ZEND_STRL("setting"), 0);
add_assoc_bool(zsetting, "open_http_protocol", 1);
add_assoc_bool(zsetting, "open_mqtt_protocol", 0);
add_assoc_bool(zsetting, "open_eof_check", 0);
add_assoc_bool(zsetting, "open_length_check", 0);
enum protocol_flags { SW_HTTP2_PROTOCOL = 1u << 1, SW_WEBSOCKET_PROTOCOL = 1u << 2 };
uint8_t protocol_flag = 0;
auto primary_port = serv->get_primary_port();
if (primary_port->open_http2_protocol) {
add_assoc_bool(zsetting, "open_http2_protocol", 1);
protocol_flag |= SW_HTTP2_PROTOCOL;
}
if (primary_port->open_websocket_protocol || is_websocket_server(zserv)) {
add_assoc_bool(zsetting, "open_websocket_protocol", 1);
protocol_flag |= SW_WEBSOCKET_PROTOCOL;
}
primary_port->clear_protocol();
primary_port->open_http_protocol = 1;
primary_port->open_http2_protocol = !!(protocol_flag & SW_HTTP2_PROTOCOL);
primary_port->open_websocket_protocol = !!(protocol_flag & SW_WEBSOCKET_PROTOCOL);
}
php_swoole_server_before_start(serv, zserv);
if (serv->start() < 0) {
php_swoole_fatal_error(E_ERROR, "failed to start server. Error: %s", sw_error);
}
RETURN_TRUE;
}
static PHP_METHOD(swoole_server, send) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
zval *zfd;
zval *zdata;
zend_long server_socket = -1;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_ZVAL(zfd)
Z_PARAM_ZVAL(zdata)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(server_socket)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
if (UNEXPECTED(ZVAL_IS_NULL(zfd))) {
php_swoole_fatal_error(E_WARNING, "fd can not be null");
RETURN_FALSE;
}
char *data;
size_t length = php_swoole_get_send_data(zdata, &data);
if (length == 0) {
php_swoole_fatal_error(E_WARNING, "data is empty");
RETURN_FALSE;
}
// UNIX DGRAM SOCKET
if (serv->have_dgram_sock && Z_TYPE_P(zfd) == IS_STRING && Z_STRVAL_P(zfd)[0] == '/') {
network::Socket *sock = server_socket == -1 ? serv->dgram_socket : serv->get_server_socket(server_socket);
if (sock == nullptr) {
RETURN_FALSE;
}
RETURN_BOOL(sock->sendto(Z_STRVAL_P(zfd), 0, data, length) > 0);
}
fd = zval_get_long(zfd);
if (UNEXPECTED((int) fd <= 0)) {
php_swoole_fatal_error(E_WARNING, "invalid fd[" ZEND_LONG_FMT "]", fd);
RETURN_FALSE;
}
bool ret = serv->send(fd, data, length);
if (!ret && swoole_get_last_error() == SW_ERROR_OUTPUT_SEND_YIELD) {
zval_add_ref(zdata);
php_swoole_server_send_yield(serv, fd, zdata, return_value);
} else {
RETURN_BOOL(ret);
}
}
static PHP_METHOD(swoole_server, sendto) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
char *ip;
size_t ip_len;
zend_long port;
char *data;
size_t len;
zend_long server_socket_fd = -1;
zend_bool ipv6 = 0;
ZEND_PARSE_PARAMETERS_START(3, 4)
Z_PARAM_STRING(ip, ip_len)
Z_PARAM_LONG(port)
Z_PARAM_STRING(data, len)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(server_socket_fd)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
if (len == 0) {
php_swoole_fatal_error(E_WARNING, "data is empty");
RETURN_FALSE;
}
if (strchr(ip, ':')) {
ipv6 = 1;
}
if (ipv6 == 0 && !serv->udp_socket_ipv4) {
php_swoole_fatal_error(E_WARNING, "UDP listener has to be added before executing sendto");
RETURN_FALSE;
} else if (ipv6 == 1 && !serv->udp_socket_ipv6) {
php_swoole_fatal_error(E_WARNING, "UDP6 listener has to be added before executing sendto");
RETURN_FALSE;
}
network::Socket *server_socket = nullptr;
if (server_socket_fd < 0) {
server_socket = ipv6 ? serv->udp_socket_ipv6 : serv->udp_socket_ipv4;
} else {
server_socket = serv->get_server_socket(server_socket_fd);
}
if (server_socket == nullptr) {
RETURN_FALSE;
}
SW_CHECK_RETURN(server_socket->sendto(ip, port, data, len));
}
static PHP_METHOD(swoole_server, sendfile) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
char *filename;
size_t len;
zend_long offset = 0;
zend_long length = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls|ll", &fd, &filename, &len, &offset, &length) == FAILURE) {
RETURN_FALSE;
}
if (swIsMaster()) {
php_swoole_fatal_error(E_WARNING, "can't sendfile[%s] to the connections in master process", filename);
RETURN_FALSE;
}
RETURN_BOOL(serv->sendfile((int) fd, filename, len, offset, length));
}
static PHP_METHOD(swoole_server, close) {
if (swIsMaster()) {
php_swoole_fatal_error(E_WARNING, "can't close the connections in master process");
RETURN_FALSE;
}
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
zend_bool reset = false;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_LONG(fd)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(reset)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
RETURN_BOOL(serv->close((int) fd, reset));
}
static PHP_METHOD(swoole_server, pause) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &fd) == FAILURE) {
RETURN_FALSE;
}
RETURN_BOOL(serv->feedback(fd, SW_SERVER_EVENT_PAUSE_RECV));
}
static PHP_METHOD(swoole_server, resume) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &fd) == FAILURE) {
RETURN_FALSE;
}
RETURN_BOOL(serv->feedback(fd, SW_SERVER_EVENT_RESUME_RECV));
}
static PHP_METHOD(swoole_server, stats) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
array_init(return_value);
add_assoc_long_ex(return_value, ZEND_STRL("start_time"), serv->gs->start_time);
add_assoc_long_ex(return_value, ZEND_STRL("connection_num"), serv->gs->connection_num);
add_assoc_long_ex(return_value, ZEND_STRL("accept_count"), serv->gs->accept_count);
add_assoc_long_ex(return_value, ZEND_STRL("close_count"), serv->gs->close_count);
/**
* reset
*/
int tasking_num = serv->gs->tasking_num;
if (tasking_num < 0) {
tasking_num = serv->gs->tasking_num = 0;
}
uint32_t idle_worker_num = 0;
uint32_t worker_num = serv->worker_num;
add_assoc_long_ex(return_value, ZEND_STRL("worker_num"), worker_num);
idle_worker_num = serv->get_idle_worker_num();
add_assoc_long_ex(return_value, ZEND_STRL("idle_worker_num"), idle_worker_num);
add_assoc_long_ex(return_value, ZEND_STRL("tasking_num"), tasking_num);
add_assoc_long_ex(return_value, ZEND_STRL("request_count"), serv->gs->request_count);
if (SwooleWG.worker) {
add_assoc_long_ex(return_value, ZEND_STRL("worker_request_count"), SwooleWG.worker->request_count);
add_assoc_long_ex(return_value, ZEND_STRL("worker_dispatch_count"), SwooleWG.worker->dispatch_count);
}
if (serv->task_ipc_mode > SW_TASK_IPC_UNIXSOCK && serv->gs->task_workers.queue) {
size_t queue_num = -1;
size_t queue_bytes = -1;
if (swMsgQueue_stat(serv->gs->task_workers.queue, &queue_num, &queue_bytes) == 0) {
add_assoc_long_ex(return_value, ZEND_STRL("task_queue_num"), queue_num);
add_assoc_long_ex(return_value, ZEND_STRL("task_queue_bytes"), queue_bytes);
}
}
if (serv->task_worker_num > 0) {
idle_worker_num = serv->get_idle_task_worker_num();
add_assoc_long_ex(return_value, ZEND_STRL("task_idle_worker_num"), idle_worker_num);
}
add_assoc_long_ex(return_value, ZEND_STRL("coroutine_num"), Coroutine::count());
}
static PHP_METHOD(swoole_server, reload) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_bool only_reload_taskworker = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &only_reload_taskworker) == FAILURE) {
RETURN_FALSE;
}
int sig = only_reload_taskworker ? SIGUSR2 : SIGUSR1;
if (swoole_kill(serv->gs->manager_pid, sig) < 0) {
php_swoole_sys_error(E_WARNING, "failed to send the reload signal");
RETURN_FALSE;
}
RETURN_TRUE;
}
static PHP_METHOD(swoole_server, heartbeat) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_bool close_connection = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &close_connection) == FAILURE) {
RETURN_FALSE;
}
if (serv->heartbeat_idle_time < 1) {
RETURN_FALSE;
}
array_init(return_value);
int checktime = (int) time(nullptr) - serv->heartbeat_idle_time;
serv->foreach_connection([serv, checktime, close_connection, return_value](Connection *conn) {
swTrace("heartbeat check fd=%d", conn->fd);
if (conn->protect || conn->last_time == 0 || conn->last_time > checktime) {
return;
}
if (close_connection) {
conn->close_force = 1;
serv->factory.end(&serv->factory, conn->fd);
}
add_next_index_long(return_value, conn->session_id);
});
}
static PHP_METHOD(swoole_server, taskwait) {
if (!swIsWorker()) {
php_swoole_fatal_error(E_WARNING, "taskwait method can only be used in the worker process");
RETURN_FALSE;
}
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
EventData buf;
memset(&buf.info, 0, sizeof(buf.info));
zval *zdata;
double timeout = SW_TASKWAIT_TIMEOUT;
zend_long dst_worker_id = -1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|dl", &zdata, &timeout, &dst_worker_id) == FAILURE) {
RETURN_FALSE;
}
if (php_swoole_check_task_param(serv, dst_worker_id) < 0) {
RETURN_FALSE;
}
if (php_swoole_task_pack(&buf, zdata) < 0) {
RETURN_FALSE;
}
int _dst_worker_id = (int) dst_worker_id;
// coroutine
if (PHPCoroutine::get_cid() >= 0) {
php_swoole_task_wait_co(serv, &buf, timeout, _dst_worker_id, INTERNAL_FUNCTION_PARAM_PASSTHRU);
return;
}
int task_id = buf.info.fd;
uint64_t notify;
EventData *task_result = &(serv->task_result[SwooleG.process_id]);
sw_memset_zero(task_result, sizeof(EventData));
swPipe *task_notify_pipe = &serv->task_notify[SwooleG.process_id];
swSocket *task_notify_socket = task_notify_pipe->getSocket(task_notify_pipe, SW_PIPE_READ);
// clear history task
while (task_notify_socket->wait_event(0, SW_EVENT_READ) == SW_OK) {
if (read(task_notify_socket->fd, &notify, sizeof(notify)) <= 0) {
break;
}
}
sw_atomic_fetch_add(&serv->gs->tasking_num, 1);
if (serv->gs->task_workers.dispatch_blocking(&buf, &_dst_worker_id) >= 0) {
while (1) {
if (task_notify_socket->wait_event((int) (timeout * 1000), SW_EVENT_READ) != SW_OK) {
break;
}
if (task_notify_pipe->read(task_notify_pipe, &notify, sizeof(notify)) > 0) {
if (task_result->info.fd != task_id) {
continue;
}
zval *task_notify_data = php_swoole_task_unpack(task_result);
if (task_notify_data == nullptr) {
RETURN_FALSE;
} else {
RETVAL_ZVAL(task_notify_data, 0, 0);
efree(task_notify_data);
return;
}
break;
} else {
php_swoole_sys_error(E_WARNING, "taskwait failed");
break;
}
}
} else {
sw_atomic_fetch_sub(&serv->gs->tasking_num, 1);
}
RETURN_FALSE;
}
static PHP_METHOD(swoole_server, taskWaitMulti) {
if (!swIsWorker()) {
php_swoole_fatal_error(E_WARNING, "taskWaitMulti method can only be used in the worker process");
RETURN_FALSE;
}
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
EventData buf;
memset(&buf.info, 0, sizeof(buf.info));
zval *ztasks;
zval *ztask;
double timeout = SW_TASKWAIT_TIMEOUT;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|d", &ztasks, &timeout) == FAILURE) {
RETURN_FALSE;
}
array_init(return_value);
int dst_worker_id;
int task_id;
int i = 0;
int n_task = php_swoole_array_length(ztasks);
if (n_task >= SW_MAX_CONCURRENT_TASK) {
php_swoole_fatal_error(E_WARNING, "too many concurrent tasks");
RETURN_FALSE;
}
int list_of_id[SW_MAX_CONCURRENT_TASK] = {};
uint64_t notify;
EventData *task_result = &(serv->task_result[SwooleG.process_id]);
sw_memset_zero(task_result, sizeof(EventData));
swPipe *task_notify_pipe = &serv->task_notify[SwooleG.process_id];
Worker *worker = serv->get_worker(SwooleG.process_id);
char _tmpfile[sizeof(SW_TASK_TMP_FILE)] = SW_TASK_TMP_FILE;
int _tmpfile_fd = swoole_tmpfile(_tmpfile);
if (_tmpfile_fd < 0) {
RETURN_FALSE;
}
close(_tmpfile_fd);
int *finish_count = (int *) task_result->data;
worker->lock.lock(&worker->lock);
*finish_count = 0;
memcpy(task_result->data + 4, _tmpfile, sizeof(_tmpfile));
worker->lock.unlock(&worker->lock);
// clear history task
swSocket *task_notify_socket = task_notify_pipe->getSocket(task_notify_pipe, SW_PIPE_WORKER);
while (read(task_notify_socket->fd, &notify, sizeof(notify)) > 0)
;
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(ztasks), ztask)
task_id = php_swoole_task_pack(&buf, ztask);
if (task_id < 0) {
php_swoole_fatal_error(E_WARNING, "task pack failed");
goto _fail;
}
swTask_type(&buf) |= SW_TASK_WAITALL;
dst_worker_id = -1;
sw_atomic_fetch_add(&serv->gs->tasking_num, 1);
if (serv->gs->task_workers.dispatch_blocking(&buf, &dst_worker_id) < 0) {
php_swoole_sys_error(E_WARNING, "taskwait failed");
task_id = -1;
_fail:
add_index_bool(return_value, i, 0);
n_task--;
} else {
sw_atomic_fetch_sub(&serv->gs->tasking_num, 1);
}
list_of_id[i] = task_id;
i++;
SW_HASHTABLE_FOREACH_END();
if (n_task == 0) {
swoole_set_last_error(SW_ERROR_TASK_DISPATCH_FAIL);
RETURN_FALSE;
}
double _now = swoole_microtime();
while (n_task > 0) {
task_notify_pipe->timeout = timeout;
int ret = task_notify_pipe->read(task_notify_pipe, &notify, sizeof(notify));
if (ret > 0 && *finish_count < n_task) {
if (swoole_microtime() - _now < timeout) {
continue;
}
}
break;
}
worker->lock.lock(&worker->lock);
auto content = swoole_file_get_contents(_tmpfile);
worker->lock.unlock(&worker->lock);
if (content.get() == nullptr) {
RETURN_FALSE;
}
EventData *result;
zval *zdata;
uint32_t j;
do {
result = (EventData *) (content->str + content->offset);
task_id = result->info.fd;
zdata = php_swoole_task_unpack(result);
if (zdata == nullptr) {
goto _next;
}
for (j = 0; j < php_swoole_array_length(ztasks); j++) {
if (list_of_id[j] == task_id) {
break;
}
}
(void) add_index_zval(return_value, j, zdata);
efree(zdata);
_next:
content->offset += sizeof(DataHead) + result->info.len;
} while (content->offset < 0 || (size_t) content->offset < content->length);
// delete tmp file
unlink(_tmpfile);
}
static PHP_METHOD(swoole_server, taskCo) {
if (!swIsWorker()) {
php_swoole_fatal_error(E_WARNING, "taskCo method can only be used in the worker process");
RETURN_FALSE;
}
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
zval *ztasks;
zval *ztask;
double timeout = SW_TASKWAIT_TIMEOUT;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|d", &ztasks, &timeout) == FAILURE) {
RETURN_FALSE;
}
int dst_worker_id = -1;
int task_id;
int i = 0;
uint32_t n_task = php_swoole_array_length(ztasks);
EventData buf;
memset(&buf.info, 0, sizeof(buf.info));
if (n_task >= SW_MAX_CONCURRENT_TASK) {
php_swoole_fatal_error(E_WARNING, "too many concurrent tasks");
RETURN_FALSE;
}
if (php_swoole_check_task_param(serv, dst_worker_id) < 0) {
RETURN_FALSE;
}
int *list = (int *) ecalloc(n_task, sizeof(int));
if (list == nullptr) {
RETURN_FALSE;
}
TaskCo *task_co = (TaskCo *) emalloc(sizeof(TaskCo));
if (task_co == nullptr) {
efree(list);
RETURN_FALSE;
}
task_co->server_object = server_object;
zval *result = sw_malloc_zval();
array_init(result);
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(ztasks), ztask)
task_id = php_swoole_task_pack(&buf, ztask);
if (task_id < 0) {
php_swoole_fatal_error(E_WARNING, "failed to pack task");
goto _fail;
}
swTask_type(&buf) |= (SW_TASK_NONBLOCK | SW_TASK_COROUTINE);
dst_worker_id = -1;
sw_atomic_fetch_add(&serv->gs->tasking_num, 1);
if (serv->gs->task_workers.dispatch(&buf, &dst_worker_id) < 0) {
task_id = -1;
_fail:
add_index_bool(result, i, 0);
n_task--;
sw_atomic_fetch_sub(&serv->gs->tasking_num, 1);
} else {
server_object->property->task_coroutine_map[task_id] = task_co;
}
list[i] = task_id;
i++;
SW_HASHTABLE_FOREACH_END();
if (n_task == 0) {
swoole_set_last_error(SW_ERROR_TASK_DISPATCH_FAIL);
RETURN_FALSE;
}
long ms = (long) (timeout * 1000);
task_co->result = result;
task_co->list = list;
task_co->count = n_task;
TimerNode *timer = swoole_timer_add(ms, false, php_swoole_task_onTimeout, task_co);
if (timer) {
task_co->timer = timer;
}
PHPCoroutine::yield_m(return_value, &task_co->context);
}
static PHP_METHOD(swoole_server, task) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
zval *zdata;
zend_long dst_worker_id = -1;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_ZVAL(zdata)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(dst_worker_id)
Z_PARAM_FUNC_EX(fci, fci_cache, 1, 0)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
if (php_swoole_check_task_param(serv, dst_worker_id) < 0) {
RETURN_FALSE;
}
EventData buf;
memset(&buf.info, 0, sizeof(buf.info));
if (php_swoole_task_pack(&buf, zdata) < 0) {
RETURN_FALSE;
}
if (!swIsWorker()) {
swTask_type(&buf) |= SW_TASK_NOREPLY;
} else if (fci.size) {
swTask_type(&buf) |= SW_TASK_CALLBACK;
sw_zend_fci_cache_persist(&fci_cache);
server_object->property->task_callbacks[buf.info.fd] = fci_cache;
}
swTask_type(&buf) |= SW_TASK_NONBLOCK;
int _dst_worker_id = (int) dst_worker_id;
sw_atomic_fetch_add(&serv->gs->tasking_num, 1);
if (serv->gs->task_workers.dispatch(&buf, &_dst_worker_id) >= 0) {
RETURN_LONG(buf.info.fd);
}
sw_atomic_fetch_sub(&serv->gs->tasking_num, 1);
RETURN_FALSE;
}
static PHP_METHOD(swoole_server, sendMessage) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
if (!serv->onPipeMessage) {
php_swoole_fatal_error(E_WARNING, "onPipeMessage is null, can't use sendMessage");
RETURN_FALSE;
}
zval *zmessage;
zend_long worker_id = -1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &zmessage, &worker_id) == FAILURE) {
RETURN_FALSE;
}
if (worker_id == SwooleG.process_id) {
php_swoole_fatal_error(E_WARNING, "can't send messages to self");
RETURN_FALSE;
}
if (worker_id >= serv->worker_num + serv->task_worker_num) {
php_swoole_fatal_error(E_WARNING, "worker_id[%d] is invalid", (int) worker_id);
RETURN_FALSE;
}
EventData buf;
memset(&buf.info, 0, sizeof(buf.info));
if (php_swoole_task_pack(&buf, zmessage) < 0) {
RETURN_FALSE;
}
buf.info.type = SW_SERVER_EVENT_PIPE_MESSAGE;
buf.info.reactor_id = SwooleG.process_id;
Worker *to_worker = serv->get_worker(worker_id);
SW_CHECK_RETURN(serv->send_to_worker_from_worker(
to_worker, &buf, sizeof(buf.info) + buf.info.len, SW_PIPE_MASTER | SW_PIPE_NONBLOCK));
}
static PHP_METHOD(swoole_server, finish) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
if (sw_unlikely(serv->task_enable_coroutine)) {
php_swoole_fatal_error(E_ERROR,
"please use %s->finish instead when task_enable_coroutine is enable",
ZSTR_VAL(swoole_server_task_ce->name));
RETURN_FALSE;
}
zval *zdata;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(zdata)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
SW_CHECK_RETURN(php_swoole_task_finish(serv, zdata, nullptr));
}
static PHP_METHOD(swoole_server_task, finish) {
Server *serv = php_swoole_server_task_get_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zval *zdata;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(zdata)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
DataHead *info = php_swoole_server_task_get_info(ZEND_THIS);
SW_CHECK_RETURN(php_swoole_task_finish(serv, zdata, (EventData *) info));
}
static PHP_METHOD(swoole_server_task, pack) {
EventData buf;
memset(&buf.info, 0, sizeof(buf.info));
zval *zdata;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(zdata)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
if (php_swoole_task_pack(&buf, zdata) < 0) {
RETURN_FALSE;
}
swTask_type(&buf) |= (SW_TASK_NONBLOCK | SW_TASK_NOREPLY);
RETURN_STRINGL((char *) &buf, sizeof(buf.info) + buf.info.len);
}
static PHP_METHOD(swoole_server, bind) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd = 0;
zend_long uid = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &fd, &uid) == FAILURE) {
RETURN_FALSE;
}
if (uid > UINT32_MAX) {
php_swoole_fatal_error(E_WARNING, "uid can not be greater than %u", UINT32_MAX);
RETURN_FALSE;
}
Connection *conn = serv->get_connection_by_session_id(fd);
if (conn == nullptr || conn->active == 0) {
RETURN_FALSE;
}
sw_spinlock(&conn->lock);
if (conn->uid != 0) {
RETVAL_FALSE;
} else {
conn->uid = (uint32_t) uid;
RETVAL_TRUE;
}
sw_spinlock_release(&conn->lock);
}
#ifdef SWOOLE_SOCKETS_SUPPORT
static PHP_METHOD(swoole_server, getSocket) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
zend_long port = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &port) == FAILURE) {
RETURN_FALSE;
}
ListenPort *lp = serv->get_port(port);
php_socket *socket_object = php_swoole_convert_to_socket(lp->socket->fd);
if (!socket_object) {
RETURN_FALSE;
}
SW_ZEND_REGISTER_RESOURCE(return_value, (void *) socket_object, php_sockets_le_socket());
zval *zsocket = sw_zval_dup(return_value);
Z_TRY_ADDREF_P(zsocket);
}
#endif
static PHP_METHOD(swoole_server, getClientInfo) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
zend_long reactor_id = -1;
zend_bool dont_check_connection = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|lb", &fd, &reactor_id, &dont_check_connection) == FAILURE) {
RETURN_FALSE;
}
Connection *conn = serv->get_connection_verify(fd);
if (!conn) {
RETURN_FALSE;
}
// connection is closed
if (conn->active == 0 && !dont_check_connection) {
RETURN_FALSE;
} else {
array_init(return_value);
if (conn->uid > 0 || serv->dispatch_mode == SW_DISPATCH_UIDMOD) {
add_assoc_long(return_value, "uid", conn->uid);
}
ListenPort *port = serv->get_port_by_fd(conn->fd);
if (port && port->open_websocket_protocol) {
add_assoc_long(return_value, "websocket_status", conn->websocket_status);
}
#ifdef SW_USE_OPENSSL
if (conn->ssl_client_cert && conn->ssl_client_cert_pid == SwooleG.pid) {
add_assoc_stringl(
return_value, "ssl_client_cert", conn->ssl_client_cert->str, conn->ssl_client_cert->length);
}
#endif
// server socket
Connection *from_sock = serv->get_connection(conn->server_fd);
if (from_sock) {
add_assoc_long(return_value, "server_port", from_sock->info.get_port());
}
add_assoc_long(return_value, "server_fd", conn->server_fd);
add_assoc_long(return_value, "socket_fd", conn->fd);
add_assoc_long(return_value, "socket_type", conn->socket_type);
add_assoc_long(return_value, "remote_port", conn->info.get_port());
add_assoc_string(return_value, "remote_ip", (char *) conn->info.get_ip());
add_assoc_long(return_value, "reactor_id", conn->reactor_id);
add_assoc_long(return_value, "connect_time", conn->connect_time);
add_assoc_long(return_value, "last_time", conn->last_time);
add_assoc_long(return_value, "close_errno", conn->close_errno);
}
}
static PHP_METHOD(swoole_server, getClientList) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long start_fd = 0;
zend_long find_count = 10;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &start_fd, &find_count) == FAILURE) {
RETURN_FALSE;
}
// exceeded the maximum number of searches
if (find_count > SW_MAX_FIND_COUNT) {
php_swoole_fatal_error(E_WARNING, "swoole connection list max_find_count=%d", SW_MAX_FIND_COUNT);
RETURN_FALSE;
}
// copy it out to avoid being overwritten by other processes
int serv_max_fd = serv->get_maxfd();
if (start_fd == 0) {
start_fd = serv->get_minfd();
} else {
Connection *conn = serv->get_connection_by_session_id(start_fd);
if (!conn) {
RETURN_FALSE;
}
start_fd = conn->fd;
}
if ((int) start_fd >= serv_max_fd) {
RETURN_FALSE;
}
array_init(return_value);
int fd = start_fd + 1;
Connection *conn;
for (; fd <= serv_max_fd; fd++) {
swTrace("maxfd=%d, fd=%d, find_count=%ld, start_fd=%ld", serv_max_fd, fd, find_count, start_fd);
conn = serv->get_connection(fd);
if (conn->active && !conn->closed) {
#ifdef SW_USE_OPENSSL
if (conn->ssl && !conn->ssl_ready) {
continue;
}
#endif
add_next_index_long(return_value, conn->session_id);
find_count--;
}
// finish fetch
if (find_count <= 0) {
break;
}
}
}
static PHP_METHOD(swoole_server, sendwait) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
zval *zdata;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &fd, &zdata) == FAILURE) {
RETURN_FALSE;
}
char *data;
size_t length = php_swoole_get_send_data(zdata, &data);
if (length == 0) {
php_swoole_fatal_error(E_WARNING, "data is empty");
RETURN_FALSE;
}
if (serv->is_process_mode() || swIsTaskWorker()) {
php_swoole_fatal_error(E_WARNING, "can't sendwait");
RETURN_FALSE;
}
RETURN_BOOL(serv->sendwait(fd, data, length));
}
static PHP_METHOD(swoole_server, exists) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_LONG(fd)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
Connection *conn = serv->get_connection_by_session_id(fd);
if (!conn) {
RETURN_FALSE;
}
// connection is closed
if (conn->active == 0 || conn->closed) {
RETURN_FALSE;
} else {
RETURN_TRUE;
}
}
static PHP_METHOD(swoole_server, protect) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long fd;
zend_bool value = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &fd, &value) == FAILURE) {
RETURN_FALSE;
}
Connection *conn = serv->get_connection_by_session_id(fd);
if (!conn) {
RETURN_FALSE;
}
// connection is closed
if (conn->active == 0 || conn->closed) {
RETURN_FALSE;
} else {
conn->protect = value;
RETURN_TRUE;
}
}
#ifdef SW_BUFFER_RECV_TIME
static PHP_METHOD(swoole_server, getReceivedTime) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
if (serv->last_receive_usec > 0) {
RETURN_DOUBLE(serv->last_receive_usec);
} else {
RETURN_FALSE;
}
}
#endif
static PHP_METHOD(swoole_server, getWorkerId) {
if (!swIsWorker()) {
RETURN_FALSE;
} else {
RETURN_LONG(SwooleG.process_id);
}
}
static PHP_METHOD(swoole_server, getWorkerStatus) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_long worker_id = SwooleG.process_id;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &worker_id) == FAILURE) {
RETURN_FALSE;
}
Worker *worker = serv->get_worker(worker_id);
if (!worker) {
RETURN_FALSE;
} else {
RETURN_LONG(worker->status);
}
}
static PHP_METHOD(swoole_server, getWorkerPid) {
if (!swIsWorker()) {
RETURN_FALSE;
} else {
RETURN_LONG(SwooleG.pid);
}
}
static PHP_METHOD(swoole_server, getManagerPid) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
RETURN_LONG(serv->gs->manager_pid);
}
static PHP_METHOD(swoole_server, getMasterPid) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
RETURN_LONG(serv->gs->master_pid);
}
static PHP_METHOD(swoole_server, shutdown) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
if (swoole_kill(serv->gs->master_pid, SIGTERM) < 0) {
php_swoole_sys_error(E_WARNING, "failed to shutdown. swKill(%d, SIGTERM) failed", serv->gs->master_pid);
RETURN_FALSE;
} else {
RETURN_TRUE;
}
}
static PHP_METHOD(swoole_server, stop) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (sw_unlikely(!serv->is_started())) {
php_swoole_fatal_error(E_WARNING, "server is not running");
RETURN_FALSE;
}
zend_bool wait_reactor = 0;
long worker_id = SwooleG.process_id;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lb", &worker_id, &wait_reactor) == FAILURE) {
RETURN_FALSE;
}
if (worker_id == SwooleG.process_id && wait_reactor == 0) {
if (SwooleTG.reactor != nullptr) {
SwooleTG.reactor->defer(
[](void *data) {
swReactor *reactor = (swReactor *) data;
reactor->running = false;
},
SwooleTG.reactor);
}
serv->running = false;
} else {
Worker *worker = serv->get_worker(worker_id);
if (worker == nullptr) {
RETURN_FALSE;
} else if (swoole_kill(worker->pid, SIGTERM) < 0) {
php_swoole_sys_error(E_WARNING, "swKill(%d, SIGTERM) failed", worker->pid);
RETURN_FALSE;
}
}
RETURN_TRUE;
}
// swoole_connection_iterator
static PHP_METHOD(swoole_connection_iterator, __construct) {
php_swoole_fatal_error(E_ERROR, "please use the Swoole\\Server->connections");
return;
}
static PHP_METHOD(swoole_connection_iterator, rewind) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
iterator->index = 0;
iterator->current_fd = iterator->serv->get_minfd();
}
static PHP_METHOD(swoole_connection_iterator, valid) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
int fd = iterator->current_fd;
Connection *conn;
int max_fd = iterator->serv->get_maxfd();
for (; fd <= max_fd; fd++) {
conn = iterator->serv->get_connection(fd);
if (conn->active && !conn->closed) {
#ifdef SW_USE_OPENSSL
if (conn->ssl && !conn->ssl_ready) {
continue;
}
#endif
if (iterator->port &&
(iterator->port->socket_fd < 0 || conn->server_fd != (uint32_t) iterator->port->socket_fd)) {
continue;
}
iterator->session_id = conn->session_id;
iterator->current_fd = fd;
iterator->index++;
RETURN_TRUE;
}
}
RETURN_FALSE;
}
static PHP_METHOD(swoole_connection_iterator, current) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
RETURN_LONG(iterator->session_id);
}
static PHP_METHOD(swoole_connection_iterator, next) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
iterator->current_fd++;
}
static PHP_METHOD(swoole_connection_iterator, key) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
RETURN_LONG(iterator->index);
}
static PHP_METHOD(swoole_connection_iterator, count) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
if (iterator->port) {
RETURN_LONG(*iterator->port->connection_num);
} else {
RETURN_LONG(iterator->serv->gs->connection_num);
}
}
static PHP_METHOD(swoole_connection_iterator, offsetExists) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
zval *zserv = (zval *) iterator->serv->ptr2;
zval *zfd;
zval retval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zfd) == FAILURE) {
RETURN_FALSE;
}
sw_zend_call_method_with_1_params(zserv, swoole_server_ce, nullptr, "exists", &retval, zfd);
RETVAL_BOOL(Z_BVAL_P(&retval));
}
static PHP_METHOD(swoole_connection_iterator, offsetGet) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
zval *zserv = (zval *) iterator->serv->ptr2;
zval *zfd;
zval retval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zfd) == FAILURE) {
RETURN_FALSE;
}
sw_zend_call_method_with_1_params(zserv, swoole_server_ce, nullptr, "getClientInfo", &retval, zfd);
RETVAL_ZVAL(&retval, 0, 0);
}
static PHP_METHOD(swoole_connection_iterator, offsetSet) {}
static PHP_METHOD(swoole_connection_iterator, offsetUnset) {}
static PHP_METHOD(swoole_connection_iterator, __destruct) {}
1
https://gitee.com/nhky/swoole-src.git
git@gitee.com:nhky/swoole-src.git
nhky
swoole-src
swoole-src
master

搜索帮助