Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-09 09:06:09

0001 #ifndef CURLINC_MULTI_H
0002 #define CURLINC_MULTI_H
0003 /***************************************************************************
0004  *                                  _   _ ____  _
0005  *  Project                     ___| | | |  _ \| |
0006  *                             / __| | | | |_) | |
0007  *                            | (__| |_| |  _ <| |___
0008  *                             \___|\___/|_| \_\_____|
0009  *
0010  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
0011  *
0012  * This software is licensed as described in the file COPYING, which
0013  * you should have received as part of this distribution. The terms
0014  * are also available at https://curl.se/docs/copyright.html.
0015  *
0016  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
0017  * copies of the Software, and permit persons to whom the Software is
0018  * furnished to do so, under the terms of the COPYING file.
0019  *
0020  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
0021  * KIND, either express or implied.
0022  *
0023  * SPDX-License-Identifier: curl
0024  *
0025  ***************************************************************************/
0026 /*
0027   This is an "external" header file. Do not give away any internals here!
0028 
0029   GOALS
0030 
0031   o Enable a "pull" interface. The application that uses libcurl decides where
0032     and when to ask libcurl to get/send data.
0033 
0034   o Enable multiple simultaneous transfers in the same thread without making it
0035     complicated for the application.
0036 
0037   o Enable the application to select() on its own file descriptors and curl's
0038     file descriptors simultaneous easily.
0039 
0040 */
0041 
0042 /*
0043  * This header file should not really need to include "curl.h" since curl.h
0044  * itself includes this file and we expect user applications to do #include
0045  * <curl/curl.h> without the need for especially including multi.h.
0046  *
0047  * For some reason we added this include here at one point, and rather than to
0048  * break existing (wrongly written) libcurl applications, we leave it as-is
0049  * but with this warning attached.
0050  */
0051 #include "curl.h"
0052 
0053 #ifdef __cplusplus
0054 extern "C" {
0055 #endif
0056 
0057 typedef void CURLM;
0058 
0059 typedef enum {
0060   CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
0061                                     curl_multi_socket*() soon */
0062   CURLM_OK,
0063   CURLM_BAD_HANDLE,      /* the passed-in handle is not a valid CURLM handle */
0064   CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
0065   CURLM_OUT_OF_MEMORY,   /* if you ever get this, you are in deep sh*t */
0066   CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
0067   CURLM_BAD_SOCKET,      /* the passed in socket argument did not match */
0068   CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
0069   CURLM_ADDED_ALREADY,   /* an easy handle already added to a multi handle was
0070                             attempted to get added - again */
0071   CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
0072                                callback */
0073   CURLM_WAKEUP_FAILURE,  /* wakeup is unavailable or failed */
0074   CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */
0075   CURLM_ABORTED_BY_CALLBACK,
0076   CURLM_UNRECOVERABLE_POLL,
0077   CURLM_LAST
0078 } CURLMcode;
0079 
0080 /* You can check for CURLM_CALL_MULTI_SOCKET too in the same style it works
0081    for curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
0082 #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
0083 
0084 /* bitmask bits for CURLMOPT_PIPELINING */
0085 #define CURLPIPE_NOTHING   0L
0086 #define CURLPIPE_HTTP1     1L
0087 #define CURLPIPE_MULTIPLEX 2L
0088 
0089 typedef enum {
0090   CURLMSG_NONE, /* first, not used */
0091   CURLMSG_DONE, /* This easy handle has completed. 'result' contains
0092                    the CURLcode of the transfer */
0093   CURLMSG_LAST /* last, not used */
0094 } CURLMSG;
0095 
0096 struct CURLMsg {
0097   CURLMSG msg;       /* what this message means */
0098   CURL *easy_handle; /* the handle it concerns */
0099   union {
0100     void *whatever;    /* message-specific data */
0101     CURLcode result;   /* return code for transfer */
0102   } data;
0103 };
0104 typedef struct CURLMsg CURLMsg;
0105 
0106 /* Based on poll(2) structure and values.
0107  * We do not use pollfd and POLL* constants explicitly
0108  * to cover platforms without poll(). */
0109 #define CURL_WAIT_POLLIN    0x0001
0110 #define CURL_WAIT_POLLPRI   0x0002
0111 #define CURL_WAIT_POLLOUT   0x0004
0112 
0113 struct curl_waitfd {
0114   curl_socket_t fd;
0115   short events;
0116   short revents;
0117 };
0118 
0119 /*
0120  * Name:    curl_multi_init()
0121  *
0122  * Desc:    initialize multi-style curl usage
0123  *
0124  * Returns: a new CURLM handle to use in all 'curl_multi' functions.
0125  */
0126 CURL_EXTERN CURLM *curl_multi_init(void);
0127 
0128 /*
0129  * Name:    curl_multi_add_handle()
0130  *
0131  * Desc:    add a standard curl handle to the multi stack
0132  *
0133  * Returns: CURLMcode type, general multi error code.
0134  */
0135 CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *m,
0136                                             CURL *curl);
0137 
0138 /*
0139  * Name:    curl_multi_remove_handle()
0140  *
0141  * Desc:    removes a curl handle from the multi stack again
0142  *
0143  * Returns: CURLMcode type, general multi error code.
0144  */
0145 CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *m,
0146                                                CURL *curl);
0147 
0148 /*
0149  * Name:    curl_multi_fdset()
0150  *
0151  * Desc:    Ask curl for its fd_set sets. The app can use these to select() or
0152  *          poll() on. We want curl_multi_perform() called as soon as one of
0153  *          them are ready.
0154  *
0155  * Returns: CURLMcode type, general multi error code.
0156  */
0157 CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *m,
0158                                        fd_set *read_fd_set,
0159                                        fd_set *write_fd_set,
0160                                        fd_set *exc_fd_set,
0161                                        int *max_fd);
0162 
0163 /*
0164  * Name:     curl_multi_wait()
0165  *
0166  * Desc:     Poll on all fds within a CURLM set as well as any
0167  *           additional fds passed to the function.
0168  *
0169  * Returns:  CURLMcode type, general multi error code.
0170  */
0171 CURL_EXTERN CURLMcode curl_multi_wait(CURLM *m,
0172                                       struct curl_waitfd extra_fds[],
0173                                       unsigned int extra_nfds,
0174                                       int timeout_ms,
0175                                       int *ret);
0176 
0177 /*
0178  * Name:     curl_multi_poll()
0179  *
0180  * Desc:     Poll on all fds within a CURLM set as well as any
0181  *           additional fds passed to the function.
0182  *
0183  * Returns:  CURLMcode type, general multi error code.
0184  */
0185 CURL_EXTERN CURLMcode curl_multi_poll(CURLM *m,
0186                                       struct curl_waitfd extra_fds[],
0187                                       unsigned int extra_nfds,
0188                                       int timeout_ms,
0189                                       int *ret);
0190 
0191 /*
0192  * Name:     curl_multi_wakeup()
0193  *
0194  * Desc:     wakes up a sleeping curl_multi_poll call.
0195  *
0196  * Returns:  CURLMcode type, general multi error code.
0197  */
0198 CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *m);
0199 
0200 /*
0201  * Name:    curl_multi_perform()
0202  *
0203  * Desc: When the app thinks there is data available for curl it calls this
0204  *          function to read/write whatever there is right now. This returns
0205  *          as soon as the reads and writes are done. This function does not
0206  *          require that there actually is data available for reading or that
0207  *          data can be written, it can be called. It returns the number of
0208  *          handles that still transfer data in the second argument's
0209  *          integer-pointer.
0210  *
0211  * Returns: CURLMcode type, general multi error code. *NOTE* that this only
0212  *          returns errors etc regarding the whole multi stack. There might
0213  *          still have occurred problems on individual transfers even when
0214  *          this returns OK.
0215  */
0216 CURL_EXTERN CURLMcode curl_multi_perform(CURLM *m,
0217                                          int *running_handles);
0218 
0219 /*
0220  * Name:    curl_multi_cleanup()
0221  *
0222  * Desc:    Cleans up and removes a whole multi stack. It does not free or
0223  *          touch any individual easy handles in any way. We need to define
0224  *          in what state those handles are going to be if this function is
0225  *          called in the middle of a transfer.
0226  *
0227  * Returns: CURLMcode type, general multi error code.
0228  */
0229 CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *m);
0230 
0231 /*
0232  * Name:    curl_multi_info_read()
0233  *
0234  * Desc:    Ask the multi handle if there is any messages/informationals from
0235  *          the individual transfers. Messages include informationals such as
0236  *          error code from the transfer or the fact that a transfer is
0237  *          completed. More details on these should be written down as well.
0238  *
0239  *          Repeated calls to this function return a new struct each time,
0240  *          until a special "end of msgs" struct is returned as a signal that
0241  *          there is no more to get at this point.
0242  *
0243  *          The data the returned pointer points to does not survive calling
0244  *          curl_multi_cleanup().
0245  *
0246  *          The 'CURLMsg' struct is meant to be simple and only contain basic
0247  *          information. If more involved information is wanted, we provide
0248  *          the particular "transfer handle" in that struct and that
0249  *          should/could/would be used in subsequent curl_easy_getinfo() calls
0250  *          (or similar). The point being that we must never expose complex
0251  *          structs to applications, as then we undoubtably get backwards
0252  *          compatibility problems in the future.
0253  *
0254  * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
0255  *          of structs. It also writes the number of messages left in the
0256  *          queue (after this read) in the integer the second argument points
0257  *          to.
0258  */
0259 CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *m,
0260                                           int *msgs_in_queue);
0261 
0262 /*
0263  * Name:    curl_multi_strerror()
0264  *
0265  * Desc:    The curl_multi_strerror function may be used to turn a CURLMcode
0266  *          value into the equivalent human readable error string. This is
0267  *          useful for printing meaningful error messages.
0268  *
0269  * Returns: A pointer to a null-terminated error message.
0270  */
0271 CURL_EXTERN const char *curl_multi_strerror(CURLMcode error);
0272 
0273 /*
0274  * Name:    curl_multi_socket() and
0275  *          curl_multi_socket_all()
0276  *
0277  * Desc:    An alternative version of curl_multi_perform() that allows the
0278  *          application to pass in one of the file descriptors that have been
0279  *          detected to have "action" on them and let libcurl perform.
0280  *          See man page for details.
0281  */
0282 #define CURL_POLL_NONE   0
0283 #define CURL_POLL_IN     1
0284 #define CURL_POLL_OUT    2
0285 #define CURL_POLL_INOUT  3
0286 #define CURL_POLL_REMOVE 4
0287 
0288 #define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
0289 
0290 #define CURL_CSELECT_IN   0x01
0291 #define CURL_CSELECT_OUT  0x02
0292 #define CURL_CSELECT_ERR  0x04
0293 
0294 typedef int (*curl_socket_callback)(CURL *easy,      /* easy handle */
0295                                     curl_socket_t s, /* socket */
0296                                     int what,        /* see above */
0297                                     void *userp,     /* private callback
0298                                                         pointer */
0299                                     void *socketp);  /* private socket
0300                                                         pointer */
0301 /*
0302  * Name:    curl_multi_timer_callback
0303  *
0304  * Desc:    Called by libcurl whenever the library detects a change in the
0305  *          maximum number of milliseconds the app is allowed to wait before
0306  *          curl_multi_socket() or curl_multi_perform() must be called
0307  *          (to allow libcurl's timed events to take place).
0308  *
0309  * Returns: The callback should return zero.
0310  */
0311 typedef int (*curl_multi_timer_callback)(CURLM *m,        /* multi handle */
0312                                          long timeout_ms, /* see above */
0313                                          void *userp);    /* private callback
0314                                                              pointer */
0315 
0316 CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
0317 curl_multi_socket(CURLM *m, curl_socket_t s, int *running_handles);
0318 
0319 CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *m,
0320                                                curl_socket_t s,
0321                                                int ev_bitmask,
0322                                                int *running_handles);
0323 
0324 CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
0325 curl_multi_socket_all(CURLM *m, int *running_handles);
0326 
0327 #ifndef CURL_ALLOW_OLD_MULTI_SOCKET
0328 /* This macro below was added in 7.16.3 to push users who recompile to use
0329  * the new curl_multi_socket_action() instead of the old curl_multi_socket()
0330  */
0331 #define curl_multi_socket(x, y, z) curl_multi_socket_action(x, y, 0, z)
0332 #endif
0333 
0334 /*
0335  * Name:    curl_multi_timeout()
0336  *
0337  * Desc:    Returns the maximum number of milliseconds the app is allowed to
0338  *          wait before curl_multi_socket() or curl_multi_perform() must be
0339  *          called (to allow libcurl's timed events to take place).
0340  *
0341  * Returns: CURLM error code.
0342  */
0343 CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *m,
0344                                          long *timeout_ms);
0345 
0346 typedef enum {
0347   /* This is the socket callback function pointer */
0348   CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1),
0349 
0350   /* This is the argument passed to the socket callback */
0351   CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2),
0352 
0353   /* set to 1 to enable pipelining for this multi handle */
0354   CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3),
0355 
0356   /* This is the timer callback function pointer */
0357   CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4),
0358 
0359   /* This is the argument passed to the timer callback */
0360   CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5),
0361 
0362   /* maximum number of entries in the connection cache */
0363   CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6),
0364 
0365   /* maximum number of (pipelining) connections to one host */
0366   CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7),
0367 
0368   /* maximum number of requests in a pipeline */
0369   CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8),
0370 
0371   /* a connection with a content-length longer than this
0372      is not considered for pipelining */
0373   CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9),
0374 
0375   /* a connection with a chunk length longer than this
0376      is not considered for pipelining */
0377   CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10),
0378 
0379   /* a list of site names(+port) that are blocked from pipelining */
0380   CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11),
0381 
0382   /* a list of server types that are blocked from pipelining */
0383   CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12),
0384 
0385   /* maximum number of open connections in total */
0386   CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13),
0387 
0388    /* This is the server push callback function pointer */
0389   CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14),
0390 
0391   /* This is the argument passed to the server push callback */
0392   CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15),
0393 
0394   /* maximum number of concurrent streams to support on a connection */
0395   CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16),
0396 
0397   /* network has changed, adjust caches/connection reuse */
0398   CURLOPT(CURLMOPT_NETWORK_CHANGED, CURLOPTTYPE_LONG, 17),
0399 
0400   /* This is the notify callback function pointer */
0401   CURLOPT(CURLMOPT_NOTIFYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 18),
0402 
0403   /* This is the argument passed to the notify callback */
0404   CURLOPT(CURLMOPT_NOTIFYDATA, CURLOPTTYPE_OBJECTPOINT, 19),
0405 
0406   /* maximum number of threads used with threaded DNS resolver */
0407   CURLOPT(CURLMOPT_RESOLVE_THREADS_MAX, CURLOPTTYPE_LONG, 20),
0408 
0409   /* set to 1L for not joining threads when multi is cleaned up */
0410   CURLOPT(CURLMOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 21),
0411 
0412   CURLMOPT_LASTENTRY /* the last unused */
0413 } CURLMoption;
0414 
0415 /* Definition of bits for the CURLMOPT_NETWORK_CHANGED argument: */
0416 
0417 /* - CURLMNWC_CLEAR_ALL tells libcurl to clear "everything" that could be
0418    associated with this network, including both connections and DNS data. */
0419 #define CURLMNWC_CLEAR_ALL (1L << 0)
0420 
0421 /* - CURLMNWC_CLEAR_CONNS tells libcurl to prevent further reuse of existing
0422    connections. Connections that are idle are closed. Ongoing transfers do
0423    continue with the connection they have. */
0424 #define CURLMNWC_CLEAR_CONNS (1L << 1)
0425 
0426 /* - CURLMNWC_CLEAR_DNS tells libcurl to clear the DNS cache associated with
0427    this multi handle. Ongoing transfers keep using their already resolved
0428    addresses, but future name resolutions are performed again. */
0429 #define CURLMNWC_CLEAR_DNS (1L << 2)
0430 
0431 /*
0432  * Name:    curl_multi_setopt()
0433  *
0434  * Desc:    Sets options for the multi handle.
0435  *
0436  * Returns: CURLM error code.
0437  */
0438 CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *m,
0439                                         CURLMoption option, ...);
0440 
0441 /*
0442  * Name:    curl_multi_assign()
0443  *
0444  * Desc:    This function sets an association in the multi handle between the
0445  *          given socket and a private pointer of the application. This is
0446  *          (only) useful for curl_multi_socket uses.
0447  *
0448  * Returns: CURLM error code.
0449  */
0450 CURL_EXTERN CURLMcode curl_multi_assign(CURLM *m,
0451                                         curl_socket_t sockfd, void *sockp);
0452 
0453 /*
0454  * Name:    curl_multi_get_handles()
0455  *
0456  * Desc:    Returns an allocated array holding all handles currently added to
0457  *          the multi handle. Marks the final entry with a NULL pointer. If
0458  *          there is no easy handle added to the multi handle, this function
0459  *          returns an array with the first entry as a NULL pointer.
0460  *
0461  * Returns: NULL on failure, otherwise a CURL **array pointer
0462  */
0463 CURL_EXTERN CURL **curl_multi_get_handles(CURLM *m);
0464 
0465 typedef enum {
0466   CURLMINFO_NONE, /* first, never use this */
0467   /* The number of easy handles currently managed by the multi handle,
0468    * e.g. have been added but not yet removed. */
0469   CURLMINFO_XFERS_CURRENT = 1,
0470   /* The number of easy handles running, e.g. not done and not queueing. */
0471   CURLMINFO_XFERS_RUNNING = 2,
0472   /* The number of easy handles waiting to start, e.g. for a connection
0473    * to become available due to limits on parallelism, max connections
0474    * or other factors. */
0475   CURLMINFO_XFERS_PENDING = 3,
0476   /* The number of easy handles finished, waiting for their results to
0477    * be read via `curl_multi_info_read()`. */
0478   CURLMINFO_XFERS_DONE = 4,
0479   /* The total number of easy handles added to the multi handle, ever. */
0480   CURLMINFO_XFERS_ADDED = 5,
0481 
0482   CURLMINFO_LASTENTRY /* the last unused */
0483 } CURLMinfo_offt;
0484 
0485 /*
0486  * Name:    curl_multi_get_offt()
0487  *
0488  * Desc:    Retrieves a numeric value for the `CURLMINFO_*` enums.
0489  *
0490  * Returns: CULRM_OK or error when value could not be obtained.
0491  */
0492 CURL_EXTERN CURLMcode curl_multi_get_offt(CURLM *m,
0493                                           CURLMinfo_offt info,
0494                                           curl_off_t *pvalue);
0495 
0496 /*
0497  * Name: curl_push_callback
0498  *
0499  * Desc: This callback gets called when a new stream is being pushed by the
0500  *       server. It approves or denies the new stream. It can also decide
0501  *       to completely fail the connection.
0502  *
0503  * Returns: CURL_PUSH_OK, CURL_PUSH_DENY or CURL_PUSH_ERROROUT
0504  */
0505 #define CURL_PUSH_OK       0
0506 #define CURL_PUSH_DENY     1
0507 #define CURL_PUSH_ERROROUT 2 /* added in 7.72.0 */
0508 
0509 struct curl_pushheaders;  /* forward declaration only */
0510 
0511 CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
0512                                         size_t num);
0513 CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
0514                                          const char *name);
0515 
0516 typedef int (*curl_push_callback)(CURL *parent,
0517                                   CURL *easy,
0518                                   size_t num_headers,
0519                                   struct curl_pushheaders *headers,
0520                                   void *userp);
0521 
0522 /*
0523  * Name:    curl_multi_waitfds()
0524  *
0525  * Desc:    Ask curl for fds for polling. The app can use these to poll on.
0526  *          We want curl_multi_perform() called as soon as one of them are
0527  *          ready. Passing zero size allows to get a number of fds.
0528  *
0529  * Returns: CURLMcode type, general multi error code.
0530  */
0531 CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *m,
0532                                          struct curl_waitfd *ufds,
0533                                          unsigned int size,
0534                                          unsigned int *fd_count);
0535 
0536 /*
0537  * Notifications dispatched by a multi handle, when enabled.
0538  */
0539 #define CURLMNOTIFY_INFO_READ    0
0540 #define CURLMNOTIFY_EASY_DONE    1
0541 
0542 /*
0543  * Callback to install via CURLMOPT_NOTIFYFUNCTION.
0544  */
0545 typedef void (*curl_notify_callback)(CURLM *m,
0546                                      unsigned int notification,
0547                                      CURL *easy,
0548                                      void *user_data);
0549 
0550 CURL_EXTERN CURLMcode curl_multi_notify_disable(CURLM *m,
0551                                                 unsigned int notification);
0552 
0553 CURL_EXTERN CURLMcode curl_multi_notify_enable(CURLM *m,
0554                                                unsigned int notification);
0555 
0556 #ifdef __cplusplus
0557 } /* end of extern "C" */
0558 #endif
0559 
0560 #endif